@oh-my-pi/pi-agent-core
Breaking Changes
- Removed
harmony-leakexports from the@oh-my-pi/pi-agent-corepackage entrypoint - Replaced the experimental
promptToolCallsagent/loop option withtoolCallSyntax, selecting an explicit in-band tool-call grammar instead of a boolean GLM-only mode.
Added
- Added support for selecting owned in-band tool-call syntax via
PI_OWNED_TOOLS=<syntax>(for examplehermesorqwen3) while preserving legacyPI_OWNED_TOOLS=1/trueas GLM mode - Added owned in-band tool calling for multiple syntaxes (
glm,hermes,kimi,xml,anthropic,deepseek,harmony,pi-native,qwen3). Owned mode sends no native provider tools, appends a syntax-specific prompt/catalog, re-encodes prior tool calls/results as grammar-owned text, and parses streamed model output back into canonical tool calls. - Added tool-example folding to
normalizeTools: when given a model's affinity syntax (resolved viapreferredToolSyntax), it renders each tool'sexamplesinto an<examples>block in that native syntax and appends it to the wire description. Wired through both context paths (fresh build and append-onlytakeSnapshot/buildvia a newexampleSyntaxbuild option), with the_iintent-field placeholder added to examples when intent tracing injects it. - Added the
abortOnFabricatedToolResultoption toAgentOptions/AgentLoopConfig(defaulttrue): when owned tool calling is active and the model fabricates a tool result mid-turn,trueaborts the provider request immediately whilefalselets it finish and discards the fabricated continuation.
Changed
- Added owned in-band syntax support to
Agentloop configuration resolution by selecting syntax fromtoolCallSyntaxorPI_OWNED_TOOLSwhen present
Fixed
- Fixed append-only context cache fingerprinting to account for
exampleSyntax, so switching tool-call syntax rebuilds cached prompts with the correct injected tool examples - Fixed owned in-band tool-calling requests to omit
toolChoiceafter stripping native tools, preventing invalid tool-choice requests - Fixed owned tool calling letting the model fabricate tool results by treating grammar-owned tool-result markers in assistant text as a hard turn boundary: calls before the fabrication are kept, fabricated results and dependent calls are dropped, and the real result is fed back on the next turn.
@oh-my-pi/pi-ai
Added
- Added
jsonSchemaToTypeScriptto@oh-my-pi/pi-ai/utils/schemato render JSON Schema argument shapes as compact, human-readable TypeScript-style signatures - Added the generic
ToolExampletype (ToolCallExample/ToolCompareExample/ToolNoteExample, parameterized over a tool's argument shape) and anexamplesproperty on theToolinterface for defining tool-call examples once as data. - Added
renderToolExamples(via@oh-my-pi/pi-ai/grammar) to render a tool's examples into an<examples>block in the model's native tool-call syntax, with an optional_iintent-field placeholder injected when intent tracing is active. - Added per-grammar
renderToolCallrendering of a single tool-call invocation (the inner element only, without the parallel-call block envelope), distinct fromrenderAssistantToolCallswhich renders a complete block of one or more parallel calls. - Added a
GrammarRenderOptions.exampleflag torenderToolCall: when set, the invocation renders as the bare payload — Harmony emits just the JSON arguments, dropping the verbose<|start|>…<|message|>…<|call|>envelope — sorenderToolExampleskeeps<examples>blocks legible. - Added an
abortOnFabricationparameter towrapInbandToolStream(defaulttrue): whenfalse, a fabricated in-band tool-result continuation is discarded without aborting the provider request instead of cutting the turn short. - Added
@oh-my-pi/pi-ai/utils/harmony-leakexport with helpers to detect, audit, and recover GPT-5 Harmony tool-call header leaks - Added the
@oh-my-pi/pi-ai/grammarpublic entrypoint for grammar factories, prompt/call rendering, in-band scanning, history encoding, and related typed utilities - Added a unified in-band tool-call grammar engine with syntax-owned scanners, prompts, history rendering, tool-result rendering, and stream adaptation for GLM, Hermes/Qwen, Kimi, XML/Anthropic, DeepSeek, Harmony, and pi-native formats.
Changed
- Changed Harmony in-band tool-call rendering to omit the
<|constrain|>jsonmarker before the payload incommentarychannel calls - Changed tool inventory rendering to present each tool’s
Parameterssection as a simplified TypeScript-style signature derived from its wire schema - Added raw in-band tool-call block capture to parsed owned tool calls so debugging can inspect the exact model-emitted call syntax.
- Moved the canonical
ToolCallSyntaxunion to@oh-my-pi/pi-catalog/identityand re-exported it from@oh-my-pi/pi-ai/grammarso the catalog can own the syntax vocabulary without an@oh-my-pi/pi-airuntime import; all existing import paths are unchanged. - Made tool-call argument validation more lenient for schema-directed scalar coercions, including object/array stringification and 0/1 boolean coercion.
- Changed
renderToolInventory(the verbose system-prompt inventory and/dump) to render each tool as a# Tool: <name>markdown section instead of a<tool name="…">…</tool>wrapper.
Fixed
- Fixed Harmony leak handling support by adding
recoverHarmonyToolCallplus leak-detection workflows for contaminated assistant messages so recoverable tool-call arguments can be safely truncated and retried - Fixed false-positive gating in Harmony leak heuristics using signal-based checks so unrelated text containing
to=functions...is not treated as leaked tool-call markup - Routed Kimi, DeepSeek DSML, and plain thinking markup healing through the shared in-band scanners so provider leak repair and owned tool calling parse the same wire formats.
- Fixed Cursor provider (
cursor-agentAPI) streaming dropping large MCP tool-call arguments — most visibly the built-intasktool'stasksarray on multi-subagent dispatches, which failed downstream schema validation withtasks: Invalid input: expected array, received undefined. Two upstream behaviors were fighting the stream handler inpackages/ai/src/providers/cursor.ts: (1)args_text_deltacarries the cumulative args text so far peragent.proto, but the handler concatenated each snapshot onto the buffer, garbling the JSON; (2)tool_call_completedcarries anMcpArgsmap that omits oversized parameters entirely and downgrades unparsable values to their raw string fallback, but the handler unconditionally overwrote the streamed args with that map. The handler now strips the already-buffered prefix from eachargs_text_deltasnapshot (falling back to append when the snapshot doesn't extend the buffer) and merges the decodedMcpArgsmap into the streamed args — preserving streamed keys the completion frame omits and the structured value when the completion frame downgrades to a string. (#2615) - Fixed Codex Responses stream mis-routing interleaved
function_call_arguments.deltaevents when more than one tool call was open concurrently. The runtime tracked a singletoncurrentItem/currentBlock, so every delta — regardless ofitem_id— was appended to whichever item was most recently added, andoutput_item.donefor the earlier call then overwrote a sibling's stored arguments (visible astasks: Invalid input: expected array, received undefinedon thetasktool). Open items are now keyed byitem_idwithoutput_indexfallback; deltas/done events route to the matching block, late deltas whose item already closed are dropped instead of corrupting a sibling, andtoolcall_*stream events emit the rightcontentIndexper call (#2619).
@oh-my-pi/pi-catalog
Added
- Added the
ToolCallSyntaxunion andFALLBACK_TOOL_SYNTAXconstant to@oh-my-pi/pi-catalog/identity(re-exported from@oh-my-pi/pi-ai/grammar). - Added
preferredToolSyntax(modelId)to@oh-my-pi/pi-catalog/identity, resolving a model's native tool-call syntax affinity from its family token (Claude→anthropic, GLM→glm, Kimi→kimi, Qwen→qwen3, DeepSeek→deepseek, OpenAI/gpt-oss→harmony, else thexmlfallback). - Added
flux-1-schnell-fp8to the Fireworks serverless model catalog - Added
gpt-oss-20bto the Fireworks model catalog - Added
qwen3-embedding-8bto the Fireworks model catalog - Added
qwen3-reranker-8bto the Fireworks model catalog - Added
Gemma 4 E2B ITandGemma 4 E4B ITto the Google model catalog - Added
qwen/qwen3-asr-flashto the Zenmux model catalog - Added sparse
supportsToolsmodel metadata so providers can mark models that require in-band tool-call formatting.
Changed
- Kept non-tool-capable Fireworks serverless models in discovery results and marked them with
supportsTools: falsefor fallback-aware handling - Extended
modelFamilyToken(modelId)to classify Claude/OpenAI ids the structured parser misses (older dated forms such asclaude-3-5-sonnet-20241022andgpt-4o), returninganthropic/openaiinstead of an empty token.
@oh-my-pi/pi-coding-agent
Added
- Added tool examples data to exported RPC session tool metadata, so tool dumps and other clients can receive model-call examples
- Added
supportsToolsto model definitions and overrides so custom model configs can declare whether a model supports native tool calls - Added
tools.formatfor choosing native tool calling or a specific owned in-band format (glm,hermes,kimi,xml), withautofalling back to GLM only for models marked as not supporting native tools. - Added a conditional easter-egg tip recommending nerd fonts when using the unicode symbol preset.
- Added the
tools.abortOnFabricatedResultsetting (default on): with in-band tool calls, stop the model the moment it starts hallucinating a tool result mid-turn, or disable it to let the model finish and discard the fabricated continuation instead.
Changed
- Changed
/dumptool catalog output to render tools through the shared inventory renderer with readable TypeScript-style signatures and native-syntax<examples>blocks - Changed todo tool result rendering so that collapsed phases truncate from the beginning, showing the latest/active tasks and displaying the "more todos" summary at the top.
- Expanded
tools.formatto support additional in-band tool-call syntaxes, includinganthropic,deepseek,harmony,pi, andqwen3 - Changed the 13 tools that documented hand-written
<examples>blocks (eval,browser,todo,irc,ssh,ast_edit,ast_grep,debug,find,inspect_image,ask, plus thepatch/apply_patchedit modes) to define examples as typedexamplesdata on the tool (ToolExample<z.input<typeof schema>>); the AI layer now renders them in the model's native tool-call syntax and the markdown<examples>blocks were removed. - Changed the experimental owned tool-calling prompt from a GLM-only toggle to syntax-specific grammar prompts and result formats.
PI_OWNED_TOOLS=1still forces GLM;PI_OWNED_TOOLS=<syntax>forces that syntax. - Changed the large-paste menu to offer attachment XML blocks (
<attachment>), local-file attachments, or inline paste as explicit actions. - Changed the system-prompt tool inventory: moved the
# Inventoryblock to the bottom of the TOOLS section, and it now renders a compact tool-name list only when native tool calling is active and tool descriptions are not repeated; otherwise it emits full# Tool: <name>sections.
Fixed
- Fixed Auto-Promote Context being pre-empted by compaction: the pre-prompt context check ran compaction directly, so snapcompact (or any strategy) fired before promotion ever got a chance. It now tries promotion to a larger-context model first — mirroring the post-turn threshold path — and only compacts when no larger-context target is available. Snapcompact (auto and manual) also falls back to a context-full LLM summary when its frame archive plus kept history would still overflow the model's usable window, instead of leaving the session over the limit.
- Fixed
evalJS cells intermittently failing after ~15s with exit code 1 under load (e.g.bun test --parallel, where each file runs in a worker subprocess and the eval worker is nested). The host swallowed asynchronous worker spawn/load/crash failures —new Workerreports module-load errors via an asyncerrorevent, not a synchronous throw, so the spawntry/catch(and its inline-worker fallback) never fired, and noerror/messageerrorlistener was wired — leaving a dead worker indistinguishable from a slow one and blocking the full worker-init timeout. The init handshake now rejects immediately on a workererror/messageerrorevent and falls back to the inline worker, and thereadylistener is attached synchronously afternew Worker(Bun does not buffer messages posted before a listener exists) so a fast worker'sreadycan no longer be dropped.
@oh-my-pi/hashline
Breaking Changes
- Renamed all hashline DSL operators to concise abbreviated keywords:
replace->SWAPdelete->DELinsert before/after/head/tail->INS.PRE/POST/HEAD/TAILreplace_block->SWAP.BLKdelete_block->DEL.BLKinsert_after_block->INS.BLK.POST
What's Changed
Full Changelog: v15.13.1...v15.13.2