earendil-works/pi · error

No default stream function configured. Pass streamFn explici

Error message

No default stream function configured. Pass streamFn explicitly or call setDefaultStreamFn().

What it means

pi-agent-core ships no built-in provider runtime: Agent and the runAgentLoop/runAgentLoopContinue functions fall back to getDefaultStreamFn() when the caller omits streamFn, and that getter throws until the host registers an implementation with setDefaultStreamFn() (stream-fn.ts:17). The error means the process was wired without ever deciding how model calls reach a provider - it fails fast at construction/loop start, before any request is attempted.

Source

Thrown at packages/agent/src/stream-fn.ts:17

import type { StreamFn } from "./types.ts";

let defaultStreamFn: StreamFn | undefined;

/**
 * Configure the fallback used by Agent and low-level loops when callers omit streamFn.
 *
 * Hosts that provide a default model runtime can install its stream function here
 * without making pi-agent-core depend on a provider catalog or compatibility layer.
 */
export function setDefaultStreamFn(streamFn: StreamFn | undefined): void {
	defaultStreamFn = streamFn;
}

export function getDefaultStreamFn(): StreamFn {
	if (!defaultStreamFn) {
		throw new Error("No default stream function configured. Pass streamFn explicitly or call setDefaultStreamFn().");
	}
	return defaultStreamFn;
}

View on GitHub (pinned to 4af9d21d3b)

Solutions

  1. Pass streamFn explicitly when constructing the Agent or calling runAgentLoop - immune to module-instance issues
  2. Otherwise call setDefaultStreamFn(stream) once at app startup, before any Agent is created
  3. If you already called it, check for duplicate copies of the agent package (npm ls, lockfile audit) and dedupe
  4. Make sure the module that performs setup is imported for its side effects early in the entrypoint

Example fix

// before
const agent = new Agent({ model }); // throws: no default stream function

// after - pass it explicitly (or register once at startup)
import { stream } from "@earendil-works/pi-ai";
const agent = new Agent({ model, streamFn: stream });
// or, at app startup:
setDefaultStreamFn(stream);
Defensive patterns

Strategy: validation

Validate before calling

import { getDefaultStreamFn } from "@earendil-works/pi-agent-core";

function hasStreamRuntime(): boolean {
  try {
    getDefaultStreamFn();
    return true;
  } catch {
    return false;
  }
}

if (!hasStreamRuntime() && !options.streamFn) {
  throw new Error("Configure a stream function before creating Agents");
}

Try / catch

try {
  const agent = new Agent({ model });
} catch (e) {
  if (e instanceof Error && e.message.includes("No default stream function")) {
    failFastWithConfigGuidance(); // wire streamFn or setDefaultStreamFn, then restart
  }
  throw e;
}

Prevention

When it happens

Trigger: Constructing new Agent({ model }) or calling runAgentLoop without streamFn before any setDefaultStreamFn call; registering the default in a different copy of the module (duplicate package installs or mixed ESM/CJS resolution) so the Agent reads an unset instance; calling setDefaultStreamFn(undefined) during teardown and then creating a new Agent.

Common situations: New host apps embedding the agent core without wiring a runtime; upgrades that moved or renamed the setup call; monorepos loading two versions of the package; import-order or tree-shaking changes dropping the setup module's side effect.

Related errors


AI-assisted analysis of earendil-works/pi@4af9d21d3b (2026-08-24). Data as JSON: /api/errors/418cc02309e64b3f. Report an issue: GitHub.