- Fixed
streamProxy()dropping finalized tool-call metadata such as OpenAI Responses namespaces (#7709).
- Added
BeforeToolCallResult.terminateso blocked tool calls can participate in the existing batch early-termination rule (#7715 by @muyiyr).
- Fixed
Agent.reset()clearing transcript and runtime state during active runs; it now rejects until the agent is idle (#7717 by @wesleyzhangwq).
- Replaced the legacy harness session model with the v4 lane-based
Session,SessionStorage, andSessionRepoAPIs, including durable operation records, global facts, shared sequence numbers, and tree-scoped lane views. - Promoted the v2 session and
AgentHarnessAPI from the experimental entrypoint to the default package export and removed the experimental subpaths. - Removed the legacy JSONL and in-memory repository APIs. Use the v4
JsonlSessionRepoorInMemorySessionRepo, both implementing the newSessionRepocontract. - Added the required
FileSystem.renameFile()operation to harness execution environments for atomic JSONL publication; custom file-system implementations must provide same-filesystem replacement semantics (#7707 by @davidbrai).
- Added typed AI-request and harness telemetry schemas, their combined schema tuple, callback helpers, and a generated schema reference.
- Added bounded
Session.findEntriesOnBranch()andfindEntryOnBranch()queries with explicit traversal, filtering, ordering, and limit options. - Added a compile-complete
AgentHarnessv2 scaffold; unfinished operation paths reject withHarnessNotImplementedwhile durable execution is implemented. - Added
JsonlSessionRepo, a v4 append-only JSONL session repository with metadata validation and shared storage semantics (#7611 by @davidbrai). - Added indexed
Session.findOpenOperations()recovery queries andRecordQuery.operationKindfiltering (#7646). - Added
AgentOptions.shouldStopAfterTurnfor gracefully stopping after a completed turn before queued messages or another model call are processed. See Agent Options (#7367 by @acmerfight). - Added proxy forwarding for arbitrary OpenAI-compatible
samplingParams(#7568 by @mrexodia).
- Fixed Windows path handling for
NodeExecutionEnvfile basenames, recursive skill loading, and prompt template names. - Fixed
JsonlSessionRepoenforcing session IDs globally across working directories; IDs are now unique within each working directory. - Fixed JSONL session forks and torn-tail repairs to publish atomically, avoiding partially written or corrupted sessions after interrupted writes (#7707 by @davidbrai).
- Replaced
AgentHarness'sExecutionEnvdependency and context-freeAgentToolinputs with application-definedtoolContextvalues and context-awareAgentHarnessTooldefinitions.
- Added context-aware
read,write,edit, andbashharness tools backed byExecutionEnv, including async bash execution preparation.
- Aligned harness tool path handling, edit serialization, shell output capture, explicit non-inherited environments, and cross-platform process cleanup with coding-agent behavior.
- Fixed compaction and branch-summary requests to use fresh routing session IDs with prompt caching disabled where supported (#6618 by @tmustier).
- Added retry policy support and lifecycle events for compaction and branch-summary operations in
AgentHarness(#6901 by @davidbrai).
- Restored the
AgentstreamFnoption and host-configurable fallback for omitted agent-loop stream functions without reintroducing api-ai/compatdependency (#6915).
- Changed
SessionStorageto usegetPathToRootOrCompaction(), require session name and statistics methods, support cursor-based entry reads, and store retained compaction tails as self-contained checkpoints (#6594 by @cristinaponcela). - Moved the
uuidv7export to@earendil-works/pi-ai(#6834 by @xl0). - Replaced the optional
AgentstreamFnfallback with a requiredstreamFunctionand made low-level loop stream functions required, preventing@earendil-works/pi-ai/compatand all built-in providers from entering selective-provider bundles (#6851).
- Added usage metadata to tool results, compaction entries, and branch summaries in the agent harness (#6671 by @davidbrai).
- Added
AgentToolResult.addedToolNamespropagation toToolResultMessageso tools introduced by a result can be loaded from that transcript point onward (#6474).
- Added the
maxmodel thinking level afterxhigh.
- Added configurable harness session context entry transforms and custom-entry message projectors.
- Added custom metadata support in JSONL session headers (#6417 by @ArcadiaLin).
- Exported
InMemorySessionStorageandJsonlSessionStorage(#6435).
- Fixed harness split-turn compaction to serialize summary requests so single-concurrency providers are not asked to run overlapping generations (#5536).
- Fixed harness tool calls from length-truncated assistant messages to fail instead of waiting for missing tool results (#6285).
- Fixed harness session ingestion to normalize
nullmessage content before context projection, avoiding crashes on lax imported transcripts (#6343). - Fixed non-positive or oversized harness shell execution timeouts to fail with a clear validation error instead of being clamped to an immediate timeout (#6181).
- Fixed harness session storage short entry ids to use the random tail of the generated uuidv7 instead of the timestamp prefix, which was nearly constant between calls (#6242).
- Added
prepareNextTurnWithContextforAgentusers that need the next-turn loop context.
- Fixed
Agent.prepareNextTurnto keep receiving the run abort signal instead of the next-turn context.
- Renamed the public harness shell execution options type from
ExecutionEnvExecOptionstoShellExecOptions.
AgentHarnessOptions.modelsis required and is the only auth path: the harness streams turns, compaction, and branch summarization through the providedModelsinstance (models.streamSimple()/completeSimple()), resolving auth through the providers.AgentHarnessOptions.getApiKeyAndHeadersis removed — apps that resolved keys per request now express that as provider auth (ApiKeyAuth/OAuthAuth) on the providers in theModelscollection. Build one withcreateModels()+ provider factories (orbuiltinModels()from@earendil-works/pi-ai/providers/all); tests usefauxProvider().compact(),generateSummary(), andgenerateBranchSummary()take aModelsparameter and no longer accept explicitapiKey/headers.StreamFnis defined structurally ((model, context, options?) => AssistantMessageEventStream | Promise<...>);Models.streamSimplesatisfies it.- Removed the
@earendil-works/pi-agent-core/baseselective-provider entrypoint; use the root package with an explicitModelsinstance instead.
- Fixed harness session names to normalize newline characters before storing labels (#5999 by @haoqixu).
- Fixed harness compaction estimates to ignore malformed all-zero assistant usage after truncated responses (#5526 by @dmmulroy).
- Fixed Node execution environment commands through legacy WSL
bash.exeto pass scripts over stdin so shell variables expand in the target bash (#5893).
- Added
@earendil-works/pi-agent-core/basefor bundlers that want to pair the agent core with selective@earendil-works/pi-ai/baseprovider registration (#5348 by @FredKSchott).
- Fixed late tool progress callbacks after tool settlement to be ignored instead of emitting stale
tool_execution_updateevents (#5573).
- Fixed the compaction summarization system prompt to use neutral AI assistant wording for non-coding agents (#5401).
- Renamed agent harness
model_selectandthinking_level_selectevents tomodel_updateandthinking_level_update.
- Added agent harness tool registry APIs,
tools_updateevents, branch-scoped active-tool persistence, and duplicate tool validation.
- Fixed context token estimates to count user image attachments consistently with tool result images (#4983).
- Changed source syntax to avoid TypeScript constructs that require JavaScript emit, keeping the package compatible with Node.js strip-only TypeScript checks.
- Removed the package-level development watch script now that the root TypeScript check validates strip-only-compatible sources.
- Fixed tool-call preflight to stop preparing sibling tool calls after the run is aborted (#4276).
- Fixed tail truncation for oversized single-line output that ends with a trailing newline (#4715).
- Fixed Windows Node execution environment command spawns to hide helper console windows from background processes (#4699).
- Raised the minimum supported Node.js version to 22.19.0.
- Changed the default agent transport to
autoso providers can use their best available transport by default (#4083).
- Added
shouldStopAfterTurnto the low-level agent loop config for gracefully exiting after a completed turn before polling queued messages or starting another LLM call.
- Migrated public TypeBox-facing types and examples from
@sinclair/typebox0.34.x totypebox1.x. Install and import fromtypeboxinstead of relying on@sinclair/typeboxtransitively (#3112)
- Added
terminate: truetool-result hints to skip the automatic follow-up LLM call when every finalized tool result in the current batch opts into early termination (#3525)
- Fixed
streamProxy()to preserve the proxy-safe serializable subset of stream options, including session, transport, retry-delay, metadata, header, cache-retention, and thinking-budget settings (#3512) - Fixed parallel tool execution to emit
tool_execution_endas soon as each tool is finalized, while still emitting persisted tool-result messages in assistant source order (#3503)
- Clarified parallel tool execution ordering docs to specify that final tool lifecycle and tool-result artifacts are emitted in tool completion order.
- Fixed parallel tool-call finalization to convert
afterToolCallhook throws into error tool results instead of aborting the batch (#3084)
AgentStatehas been reshaped:streamMessagewas renamed tostreamingMessageerrorwas renamed toerrorMessageisStreaming,streamingMessage,pendingToolCalls, anderrorMessageare now readonly in the public APIpendingToolCallsis now typed asReadonlySet<string>toolsandmessagesare now accessor properties, and assigning either field copies the provided top-level array instead of preserving array identity
AgentOptions.initialStateno longer accepts runtime-owned fields. RemoveisStreaming,streamingMessage,pendingToolCalls, anderrorMessagefrominitialStatevalues.- Removed
Agentmutator methods in favor of direct property access:agent.setSystemPrompt(value)->agent.state.systemPrompt = valueagent.setModel(model)->agent.state.model = modelagent.setThinkingLevel(level)->agent.state.thinkingLevel = levelagent.setTools(tools)->agent.state.tools = toolsagent.replaceMessages(messages)->agent.state.messages = messagesagent.appendMessage(message)->agent.state.messages.push(message)agent.clearMessages()->agent.state.messages = []agent.setToolExecution(mode)->agent.toolExecution = modeagent.setBeforeToolCall(fn)->agent.beforeToolCall = fnagent.setAfterToolCall(fn)->agent.afterToolCall = fnagent.setTransport(transport)->agent.transport = transport
- Removed queue mode getter/setter methods in favor of properties:
agent.setSteeringMode(mode)->agent.steeringMode = modeagent.getSteeringMode()->agent.steeringModeagent.setFollowUpMode(mode)->agent.followUpMode = modeagent.getFollowUpMode()->agent.followUpMode
Agent.subscribe()listeners are now awaited and receive the activeAbortSignal:agent.subscribe((event) => { ... })->agent.subscribe(async (event, signal) => { ... })agent_endis now the final emitted event for a run, but not the idle boundaryagent.waitForIdle(),agent.prompt(...), andagent.continue()now settle only after awaitedagent_endlisteners finishagent.state.isStreamingremainstrueuntil that settlement completes
- Added
AgentTool.prepareArgumentshook to prepare raw tool call arguments before schema validation, enabling compatibility shims for resumed sessions with outdated tool schemas
- Added
Agent.signalto expose the active abort signal for the current turn, allowing callers to forward cancellation into nested async work (#2660)
- Fixed steering messages to wait until the current assistant message's tool-call batch fully finishes instead of skipping pending tool calls.
- Added
beforeToolCallandafterToolCallhooks toAgentOptionsandAgentLoopConfigfor preflight blocking and post-execution tool result mutation.
- Added configurable tool execution mode to
AgentandagentLoopviatoolExecution: "parallel" | "sequential", withparallelas the default. Parallel mode preflights tool calls sequentially, executes allowed tools concurrently, and emits final tool results in assistant source order.
- Added
transporttoAgentOptionsandAgentLoopConfigforwarding, allowing stream transport preference ("sse","websocket","auto") to flow into provider calls.
- Fixed
continue()to resume queued steering/follow-up messages when context currently ends in an assistant message, and preserved one-at-a-time steering ordering during assistant-tail resumes (#1312 by @ferologics)
- Added
maxRetryDelayMsoption toAgentOptionsto cap server-requested retry delays. Passed through to the underlying stream function. (#1123)
thinkingBudgetsoption onAgentandAgentOptionsto customize token budgets per thinking level (#529 by @melihmucuk)
sessionIdoption onAgentto forward session identifiers to LLM providers for session-based caching.
minimalthinking level now maps tominimalreasoning effort instead of being treated aslow.
- Queue API replaced with steer/followUp: The
queueMessage()method has been split into two methods with different delivery semantics (#403):steer(msg): Interrupts the agent mid-run. Delivered after current tool execution, skips remaining tools.followUp(msg): Waits until the agent finishes. Delivered only when there are no more tool calls or steering messages.
- Queue mode renamed:
queueModeoption renamed tosteeringMode. Added newfollowUpModeoption. Both control whether messages are delivered one-at-a-time or all at once. - AgentLoopConfig callbacks renamed:
getQueuedMessagessplit intogetSteeringMessagesandgetFollowUpMessages. - Agent methods renamed:
queueMessage()→steer()andfollowUp()clearMessageQueue()→clearSteeringQueue(),clearFollowUpQueue(),clearAllQueues()setQueueMode()/getQueueMode()→setSteeringMode()/getSteeringMode()andsetFollowUpMode()/getFollowUpMode()
prompt()andcontinue()now throw if called while the agent is already streaming, preventing race conditions and corrupted state. Usesteer()orfollowUp()to queue messages during streaming, orawaitthe previous call.
-
Transport abstraction removed:
ProviderTransport,AppTransport, andAgentTransportinterface have been removed. Use thestreamFnoption directly for custom streaming implementations. -
Agent options renamed:
transport→ removed (usestreamFninstead)messageTransformer→convertToLlmpreprocessor→transformContext
-
AppMessagerenamed toAgentMessage: All references toAppMessagehave been renamed toAgentMessagefor consistency. -
CustomMessagesrenamed toCustomAgentMessages: The declaration merging interface has been renamed. -
UserMessageWithAttachmentsandAttachmenttypes removed: Attachment handling is now the responsibility of theconvertToLlmfunction. -
Agent loop moved from
@mariozechner/pi-ai: TheagentLoop,agentLoopContinue, and related types have moved to this package. Import from@mariozechner/pi-agent-coreinstead.
-
streamFnoption onAgentfor custom stream implementations. Default usesstreamSimplefrom pi-ai. -
streamProxy()utility function for browser apps that need to proxy LLM calls through a backend server. Replaces the removedAppTransport. -
getApiKeyoption for dynamic API key resolution (useful for expiring OAuth tokens like GitHub Copilot). -
agentLoop()andagentLoopContinue()low-level functions for running the agent loop without theAgentclass wrapper. -
New exported types:
AgentLoopConfig,AgentContext,AgentTool,AgentToolResult,AgentToolUpdateCallback,StreamFn.
-
Agentconstructor now has all options optional (empty options use defaults). -
queueMessage()is now synchronous (no longer returns a Promise).