Skip to content

@fungi.computer/mule

MuleStreamFunction = (model, context, options?) => AssistantMessageEventStream | Promise<AssistantMessageEventStream>>

Pi’s model stream function, supplied explicitly by the caller.

Model<Api>

TranscriptContext

SimpleStreamOptions

AssistantMessageEventStream | Promise<AssistantMessageEventStream>


MuleIdentityKind = "run" | "turn" | "message" | "tool_call" | "tool_result" | "terminal"

Causal roles added around Pi’s model and tool loop.


MuleIdentity = object

One run-local causal identity.

readonly kind: MuleIdentityKind

readonly value: string

readonly optional parent?: MuleIdentity


MuleError = object

Expected failure from Mule’s model, tool, control, or listener work.

readonly _tag: "MuleError"

readonly phase: "model" | "tool" | "control" | "listener"

readonly message: string

readonly optional cause?: unknown

The underlying rejection or thrown value, when one exists.


MuleToolResult = object

Result produced by a tool before Mule forms Pi’s correlated result message.

readonly content: (TextContent | ImageContent)[]

readonly optional details?: JsonValue

readonly optional usage?: Usage

readonly isError: boolean

readonly optional terminate?: boolean


MuleToolExecutionPart = { type: "update"; result: MuleToolResult; } | { type: "result"; result: MuleToolResult; }

Progress or terminal output from one tool execution.


MuleToolRejection = object

A real parser or authorization rejection produced before tool execution.

readonly message: string

readonly optional terminate?: boolean


MuleCompletedTurn = object

Facts from a completed Pi turn supplied to the retained stop hook.

readonly message: AssistantMessage

readonly toolResults: readonly ToolResultMessage[]

readonly context: readonly Message[]

readonly newMessages: readonly Message[]


MuleEvent = { type: "run_start"; run: MuleIdentity; } | { type: "model_prompt"; run: MuleIdentity; turn: MuleIdentity; attempt: number; systemPrompt: string; } | { type: "turn_start"; run: MuleIdentity; turn: MuleIdentity; } | { type: "message_start"; run: MuleIdentity; turn: MuleIdentity; message: MuleIdentity; value: Message; } | { type: "message_update"; run: MuleIdentity; turn: MuleIdentity; message: MuleIdentity; value: AssistantMessage; event: AssistantMessageEvent; } | { type: "message_end"; run: MuleIdentity; turn: MuleIdentity; message: MuleIdentity; value: Message; } | { type: "tool_execution_start"; replay: "safe" | "unsafe"; run: MuleIdentity; turn: MuleIdentity; toolCall: MuleIdentity; call: ToolCall; } | { type: "tool_execution_update"; run: MuleIdentity; turn: MuleIdentity; toolCall: MuleIdentity; call: ToolCall; result: MuleToolResult; } | { type: "tool_execution_end"; run: MuleIdentity; turn: MuleIdentity; toolCall: MuleIdentity; call: ToolCall; result: MuleToolResult; } | { type: "turn_end"; run: MuleIdentity; turn: MuleIdentity; message: AssistantMessage; toolResults: readonly ToolResultMessage[]; } | { type: "run_end"; run: MuleIdentity; terminal: MuleIdentity; outcome: "completed" | "cancelled" | "failed"; }

Lifecycle emitted around Pi values. Pi messages and events are not rewritten.

{ type: "run_start"; run: MuleIdentity; }


{ type: "model_prompt"; run: MuleIdentity; turn: MuleIdentity; attempt: number; systemPrompt: string; }

readonly type: "model_prompt"

Exact prompt sent on this model attempt, including after a retry.

readonly run: MuleIdentity

readonly turn: MuleIdentity

readonly attempt: number

readonly systemPrompt: string


{ type: "turn_start"; run: MuleIdentity; turn: MuleIdentity; }


{ type: "message_start"; run: MuleIdentity; turn: MuleIdentity; message: MuleIdentity; value: Message; }


{ type: "message_update"; run: MuleIdentity; turn: MuleIdentity; message: MuleIdentity; value: AssistantMessage; event: AssistantMessageEvent; }


{ type: "message_end"; run: MuleIdentity; turn: MuleIdentity; message: MuleIdentity; value: Message; }


{ type: "tool_execution_start"; replay: "safe" | "unsafe"; run: MuleIdentity; turn: MuleIdentity; toolCall: MuleIdentity; call: ToolCall; }


{ type: "tool_execution_update"; run: MuleIdentity; turn: MuleIdentity; toolCall: MuleIdentity; call: ToolCall; result: MuleToolResult; }


{ type: "tool_execution_end"; run: MuleIdentity; turn: MuleIdentity; toolCall: MuleIdentity; call: ToolCall; result: MuleToolResult; }


{ type: "turn_end"; run: MuleIdentity; turn: MuleIdentity; message: AssistantMessage; toolResults: readonly ToolResultMessage[]; }


{ type: "run_end"; run: MuleIdentity; terminal: MuleIdentity; outcome: "completed" | "cancelled" | "failed"; }

readonly type: "run_end"

The run’s one terminal. A run interrupted after run_start ends cancelled; a run that fails with a non-listener MuleError ends failed. A listener failure ends the run without this event.

readonly run: MuleIdentity

readonly terminal: MuleIdentity

readonly outcome: "completed" | "cancelled" | "failed"


MuleToolCheckpoint = { call: ToolCall; state: "pending"; } | { call: ToolCall; state: "started"; replay: "safe" | "unsafe"; } | { call: ToolCall; state: "completed"; result: MuleToolResult; message?: ToolResultMessage; }

Durable evidence for a call in an interrupted assistant turn.

{ call: ToolCall; state: "pending"; }


{ call: ToolCall; state: "started"; replay: "safe" | "unsafe"; }


{ call: ToolCall; state: "completed"; result: MuleToolResult; message?: ToolResultMessage; }

readonly call: ToolCall

readonly state: "completed"

readonly result: MuleToolResult

readonly optional message?: ToolResultMessage

Present when the transcript message was committed too.


MuleResume = object

Completed assistant turn recovered by the transcript owner, before its next model call.

readonly message: AssistantMessage

readonly tools: readonly MuleToolCheckpoint[]


MuleRunSettings = object

Run inputs that are identical on the Promise and Effect roots.

readonly model: Model<Api>>

readonly optional stream?: MuleStreamFunction

Override Pi’s default streamSimple, primarily for explicit providers and tests.

readonly systemPrompt: string

readonly messages: readonly Message[]

readonly optional resume?: MuleResume

Continue a durable, completed assistant turn before requesting another response.

readonly optional streamOptions?: Omit<SimpleStreamOptions, "signal">>

Pi stream options. Cancellation is the run’s interruption, never a signal here.

readonly optional modelStreamIdleTimeoutMs?: number

Maximum silence between provider stream events, in milliseconds.

readonly optional toolExecution?: "parallel" | "sequential"

readonly optional retry?: RetryPolicy

Pi’s bounded retry policy around each assistant call (retryAssistantCall). Undefined means no retry, matching pi-ai’s own default. Hosts that want Pi coding-agent’s numbers pass piCodingAgentRetryDefaults.

readonly optional retryAfterMs?: (message) => number | undefined

Provider’s bounded Retry-After evidence for the last assistant error.

AssistantMessage

number | undefined


MuleRunOutcome = object

Honest terminal result of one Mule invocation.

readonly status: "completed" | "cancelled" | "failed"

readonly run: MuleIdentity

readonly terminal: MuleIdentity

readonly message: AssistantMessage

readonly messages: readonly Message[]


MulePromiseListener = (event, signal) => Promise<void> > | void

Promise listener adapted once into Mule’s canonical Effect program.

MuleEvent

AbortSignal

Promise<void> | void


MuleToolPreparation = { status: "prepared"; execute: (signal) => AsyncIterable<MuleToolExecutionPart>>; } | object & MuleToolRejection

Outcome of preparing one exact Pi tool call.

{ status: "prepared"; execute: (signal) => AsyncIterable<MuleToolExecutionPart>; }

readonly status: "prepared"

readonly execute: (signal) => AsyncIterable<MuleToolExecutionPart>>

Run the already-decoded and authorized call; abort ends it early.

AbortSignal

AsyncIterable<MuleToolExecutionPart>


object & MuleToolRejection


MuleTool = object

Pi tool declaration paired with its Promise preparation door.

readonly descriptor: Tool

readonly optional replay?: "safe" | "unsafe"

Only read-only or explicitly idempotent tools may opt into crash replay.

readonly optional executionMode?: "parallel" | "sequential"

readonly prepare: (call, signal) => Promise<MuleToolPreparation>>

Decode and authorize one exact Pi tool call before it can execute.

ToolCall

AbortSignal

Promise<MuleToolPreparation>


MuleRunInput = MuleRunSettings & object

Inputs for one complete Pi model/tool loop through the Promise facade.

readonly optional tools?: readonly MuleTool[]

readonly optional resolveApiKey?: (provider, signal) => Promise<string | undefined>>

Resolve a fresh provider credential immediately before each Pi call.

string

AbortSignal

Promise<string | undefined>

readonly optional getSteeringMessages?: (signal) => Promise<readonly Message[]>

Pull messages that should steer the active run at Pi’s safe point.

AbortSignal

Promise<readonly Message[]>

readonly optional getFollowUpMessages?: (signal) => Promise<readonly Message[]>

Pull messages queued until the run would otherwise finish.

AbortSignal

Promise<readonly Message[]>

readonly optional shouldStopAfterTurn?: (turn, signal) => Promise<boolean>>

Request a graceful stop after the current Pi turn has fully settled.

MuleCompletedTurn

AbortSignal

Promise<boolean>


Mule = object

Promise-facing Mule interface.

readonly run: (input, listener?, signal?) => Promise<MuleRunOutcome>>

Run one complete Pi model/tool loop. Rejects with the MuleError that failed the run, or with the abort reason (an AbortError when the reason is not an Error) after the caller aborts signal.

MuleRunInput

MulePromiseListener

AbortSignal

Promise<MuleRunOutcome>

const mule: Mule

Default Promise-facing Mule interface.