@oh-my-pi/pi-agent-core 15.13.0 → 15.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +219 -71
- package/dist/types/agent-loop.d.ts +2 -1
- package/dist/types/agent.d.ts +12 -2
- package/dist/types/append-only-context.d.ts +2 -0
- package/dist/types/index.d.ts +0 -1
- package/dist/types/types.d.ts +23 -1
- package/package.json +6 -6
- package/src/agent-loop.ts +91 -11
- package/src/agent.ts +19 -3
- package/src/append-only-context.ts +4 -1
- package/src/index.ts +0 -1
- package/src/types.ts +23 -1
- package/dist/types/harmony-leak.d.ts +0 -118
- package/src/harmony-leak.ts +0 -456
package/CHANGELOG.md
CHANGED
|
@@ -2,68 +2,158 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [15.13.2] - 2026-06-15
|
|
6
|
+
|
|
5
7
|
### Breaking Changes
|
|
6
8
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
|
|
9
|
+
- Removed `harmony-leak` exports from the `@oh-my-pi/pi-agent-core` package entrypoint
|
|
10
|
+
- Replaced the experimental `promptToolCalls` agent/loop option with `toolCallSyntax`, selecting an explicit in-band tool-call grammar instead of a boolean GLM-only mode.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Added support for selecting owned in-band tool-call syntax via `PI_OWNED_TOOLS=<syntax>` (for example `hermes` or `qwen3`) while preserving legacy `PI_OWNED_TOOLS=1/true` as GLM mode
|
|
15
|
+
- 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.
|
|
16
|
+
- Added tool-example folding to `normalizeTools`: when given a model's affinity syntax (resolved via `preferredToolSyntax`), it renders each tool's `examples` into an `<examples>` block in that native syntax and appends it to the wire description. Wired through both context paths (fresh build and append-only `takeSnapshot`/`build` via a new `exampleSyntax` build option), with the `_i` intent-field placeholder added to examples when intent tracing injects it.
|
|
17
|
+
- Added the `abortOnFabricatedToolResult` option to `AgentOptions`/`AgentLoopConfig` (default `true`): when owned tool calling is active and the model fabricates a tool result mid-turn, `true` aborts the provider request immediately while `false` lets it finish and discards the fabricated continuation.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Added owned in-band syntax support to `Agent` loop configuration resolution by selecting syntax from `toolCallSyntax` or `PI_OWNED_TOOLS` when present
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Fixed append-only context cache fingerprinting to account for `exampleSyntax`, so switching tool-call syntax rebuilds cached prompts with the correct injected tool examples
|
|
26
|
+
- Fixed owned in-band tool-calling requests to omit `toolChoice` after stripping native tools, preventing invalid tool-choice requests
|
|
27
|
+
- 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.
|
|
28
|
+
|
|
29
|
+
## [15.13.1] - 2026-06-15
|
|
10
30
|
|
|
11
31
|
### Added
|
|
12
32
|
|
|
13
33
|
- Added repetition-loop detection to the streaming agent loop for Gemini-family providers. A runaway run of a repeated text or thinking unit is detected mid-stream from a bounded rolling tail (O(1) per delta), the provider request is aborted, the repeated tail is collapsed to a single representative copy, and the turn ends gracefully with an `error` stop reason. Legitimate all-numeric/whitespace/punctuation runs (hexdumps, zero-fills, numeric tables) are not misclassified as loops ([#2549](https://github.com/can1357/oh-my-pi/pull/2549) by [@usr-bin-roygbiv](https://github.com/usr-bin-roygbiv)).
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
|
|
37
|
+
- Fixed repetition loop handling to collapse repeated `thinking` blocks to a single representative copy when a loop is detected
|
|
38
|
+
- Fixed repetition-loop detection to ignore repeats that contain only digits, whitespace, or punctuation so legitimate numeric outputs no longer stop with a repetition-loop error
|
|
39
|
+
- Fixed false-positive repetition-loop checks across `text` and `thinking` stream boundaries by tracking loop detection per block type
|
|
40
|
+
|
|
41
|
+
## [15.12.6] - 2026-06-14
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- Fixed dynamic forced tool choices from queue hooks being filtered against the active per-turn tool set before provider dispatch. ([#1701](https://github.com/can1357/oh-my-pi/issues/1701))
|
|
46
|
+
|
|
47
|
+
## [15.12.4] - 2026-06-13
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
|
|
51
|
+
- Fixed remote compaction input trimming to use unlimited context when `model.contextWindow` is unset
|
|
52
|
+
|
|
53
|
+
## [15.12.1] - 2026-06-12
|
|
54
|
+
|
|
55
|
+
### Breaking Changes
|
|
56
|
+
|
|
57
|
+
- Changed `pruneSupersededToolResults` to allow `supersedeKey` to be omitted so useless-result pruning can run without read-style supersede grouping
|
|
58
|
+
|
|
59
|
+
### Added
|
|
60
|
+
|
|
14
61
|
- Added `pruneUseless` controls to `PruneConfig` and `SupersedePruneConfig` so callers can toggle compaction of `toolResult` entries marked `useless`
|
|
15
62
|
- Added the ability to disable useless-result pruning by setting `pruneUseless` to false
|
|
16
63
|
- Tools can flag a result contextually useless (`AgentToolResult.useless`; overridable via `AfterToolCallResult.useless`): the agent loop copies the flag onto the persisted `ToolResultMessage` (errors always win), and compaction consumes it — the cache-aware supersede pass and the threshold prune blank flagged results to the exact `USELESS_NOTICE` placeholder (bypassing the protect window, skipping results smaller than the notice), shake collects them inside the protect-recent window, and `serializeConversation` drops the whole tool call/result pair from summarizer input
|
|
64
|
+
|
|
65
|
+
### Changed
|
|
66
|
+
|
|
67
|
+
- Changed `pruneSupersededToolResults` to allow omitted `supersedeKey` when `pruneUseless` is enabled, so useless-result pruning can run without read-style supersede grouping
|
|
68
|
+
|
|
69
|
+
## [15.11.4] - 2026-06-12
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
|
|
17
73
|
- Added `hasSteeringMessages` to `AgentLoopConfig` (wired by `Agent` to its steering queue): a peek used by the immediate-interrupt poll during tool execution, so the loop can detect queued steering without dequeuing and the queue keeps owning its messages until the injection boundary
|
|
18
74
|
- The agent loop now re-samples after a non-terminal stop (`stopReason: "stop"` with `stopDetails: { type: "pause_turn" }`, emitted by the Codex providers for `end_turn: false` commentary-only responses): the assistant message is committed to history and the model is called again without ending the turn. Consecutive pause continuations without an intervening tool call are capped at 8 to bound a backend that never stops pausing.
|
|
75
|
+
|
|
76
|
+
### Changed
|
|
77
|
+
|
|
78
|
+
- Changed steering handling so queued steering messages are now dequeued only at injection boundaries, with immediate mid-batch interrupt polling using `hasSteeringMessages`. Consumers constructing `AgentLoopConfig` directly with only `getSteeringMessages` no longer get mid-batch interrupts — steering degrades to boundary-only delivery until they also supply `hasSteeringMessages`
|
|
79
|
+
- Compaction, handoff, short-summary, and branch-summarization helpers now accept an `ApiKey` (static string or resolver) instead of a pre-resolved string, so a 401 mid-compaction force-refreshes and rotates the credential through the central auth-retry policy before any model-level fallback. The remote OpenAI compaction request is wrapped in `withAuth` and its HTTP failures now carry `.status`, so the retry classifier actually fires on remote-compaction 401s.
|
|
80
|
+
- `transformProviderContext` now receives the dispatch model as a second argument (`(context, model) => Context`), so per-request transforms can gate on model capabilities (vision input, provider, API family). Existing single-argument implementations keep working unchanged.
|
|
81
|
+
- Remote-compaction and summarization failures now throw pi-ai's typed `ProviderHttpError` instead of mutating plain `Error`s with a `.status` property; the generic `requestRemoteCompaction` error now carries `.status` (and response headers) too.
|
|
82
|
+
|
|
83
|
+
### Fixed
|
|
84
|
+
|
|
85
|
+
- Fixed a regression where steering messages could be injected into history during an aborted in-flight tool batch, leaving them hidden from queue consumers for post-abort continue
|
|
86
|
+
|
|
87
|
+
## [15.11.2] - 2026-06-11
|
|
88
|
+
|
|
89
|
+
### Added
|
|
90
|
+
|
|
19
91
|
- `AgentTool.concurrency` now also accepts a per-call resolver function `(args) => "shared" | "exclusive"`, letting tools pick the scheduling mode from the call's arguments (a throwing resolver falls back to `"exclusive"`)
|
|
92
|
+
|
|
93
|
+
### Fixed
|
|
94
|
+
|
|
95
|
+
- Fixed whitespace-only error tool results so Anthropic requests no longer 400 with `tool_result: content cannot be empty if is_error is true` and wedge the session on every subsequent turn
|
|
96
|
+
|
|
97
|
+
## [15.11.0] - 2026-06-10
|
|
98
|
+
|
|
99
|
+
### Breaking Changes
|
|
100
|
+
|
|
101
|
+
- Removed `compaction/index.ts` re-export of snapcompact helpers, so snapcompact utilities are no longer available from the agent compaction barrel and should be imported from `@oh-my-pi/snapcompact`
|
|
102
|
+
- Removed the `convertToLlm` alias export from `compaction/messages` — it duplicated `defaultConvertToLlm` under a second name. Import `defaultConvertToLlm` (array form) or the new `convertMessageToLlm` (single-message form) instead
|
|
103
|
+
|
|
104
|
+
### Added
|
|
105
|
+
|
|
20
106
|
- Added `convertMessageToLlm()`: the single-message core transformer behind `defaultConvertToLlm()`. Embedders with app-specific message roles should handle their own roles and delegate every core role (`user`/`developer`/`assistant`/`toolResult`/`custom`/`hookMessage`/`branchSummary`/`compactionSummary`) to it instead of duplicating the conversion — a duplicated `compactionSummary` case is how snapcompact frames once silently dropped off provider requests
|
|
21
107
|
- Added `pruneSupersededToolResults()` and the opt-in `PruneConfig.supersedeKey` hook so harnesses can prune stale tool results superseded by a newer read of the same file; superseded results are pruned ahead of age-based victims during overflow pruning and replaced with a `[Superseded by a newer read of this file]` placeholder. Without the new config, `pruneToolOutputs()` behavior is unchanged.
|
|
22
108
|
- Added `readToolSupersedeKey()` implementing the read-tool path/selector grammar (selector-free reads supersede range reads of the same file; URL-scheme paths exempt). Pruning honors prompt-cache economics: per-turn prunes only fire when the post-candidate suffix is small or the cache is cold (idle gap).
|
|
23
109
|
- Added the `snapcompact` compaction strategy via `@oh-my-pi/snapcompact`: instead of an LLM summary, discarded history is printed onto dense bitmap frames and re-attached to the compaction summary message as image blocks. `CompactionSummaryMessage` gains an optional `images` field, `estimateTokens()` charges per attached frame, and frames persist under `preserveData.snapcompact` with an 8-frame middle-out eviction budget.
|
|
24
110
|
- Snapcompact frames are now rendered in a provider-aware shape (`SNAPCOMPACT_SHAPES` + `resolveSnapcompactShape(api)`), following the snapcompact 200k-token monolithic evals: Anthropic-family and unknown APIs get `8x8r-bw` (unscii-8 square cells, black ink, every line printed twice with the copy on a pale highlight band — read at F1 parity with raw text at ~2x lower cost and the most refusal-robust), Google gets `8x8r-sent` (sentence-hue ink, ~2.9x cheaper), and OpenAI gets `6x6u-sent` (unscii Lanczos-stretched to 6x6 cells — OpenAI bills a flat ~2.9k tokens per image, so frame count is the only cost lever) with `detail: "original"` on the frame images. `snapcompactCompact()` accepts `model`/`shape` options, frames persist their shape metadata, mixed-shape archives (provider switches, legacy 5x8 frames) are flagged in the reading instructions, and `snapcompactGeometry()`/`renderSnapcompactFrame()` now take a shape
|
|
25
|
-
- Added `AgentLoopConfig.getDisableReasoning` so callers can override `disableReasoning` per LLM call, mirroring `getReasoning`.
|
|
26
|
-
- Added `transformProviderContext` to `AgentOptions`/`AgentLoopConfig`: an optional hook applied to the assembled provider context after conversion, normalization, and append-only handling, but before telemetry capture and provider send.
|
|
27
|
-
- Added optional `fetch` overrides to `SummaryOptions` and `compact`/`generateSummary` so remote compaction can use custom HTTP clients
|
|
28
|
-
- Added optional `fetch` option to `ProxyStreamOptions` to control the HTTP request used by `streamProxy`
|
|
29
|
-
- Added optional `fetch` overrides to `requestOpenAiRemoteCompaction` and `requestRemoteCompaction` for injectable HTTP transport
|
|
30
|
-
- Added the upstream provider that served a request (`AssistantMessage.upstreamProvider`, e.g. OpenRouter's routed provider) as a `pi.gen_ai.response.upstream_provider` chat-span telemetry attribute, alongside the existing response id and time-to-first-chunk.
|
|
31
|
-
- Added a non-interrupting "aside" message channel to the agent loop (`AgentLoopConfig.getAsideMessages` / `Agent.setAsideMessageProvider`). Asides are drained at each step boundary (after a tool batch, before the next model call) and at the yield check, so passive notifications (e.g. background-job completions, late LSP diagnostics) reach the model *between requests* without waiting for the agent to stop and without aborting in-flight tools the way steering does.
|
|
32
|
-
- Added optional `promptCacheKey` support to `AgentOptions` and `Agent` via a new `promptCacheKey` property so providers can receive a caller-provided prompt cache key
|
|
33
|
-
- Added optional `ApiKeyResolveContext` parameter to `getApiKey` in `AgentOptions` and `AgentLoopConfig` so key resolvers can receive retry context
|
|
34
|
-
- Added `getReadToolPath(context)` to `@oh-my-pi/pi-agent-core/compaction/tool-protection` to extract a paired `read` tool call's `path` for embedders building read-targeted protection matchers
|
|
35
|
-
- Added `getReadToolPath(context)` to `@oh-my-pi/pi-agent-core/compaction/tool-protection`: the shared primitive that extracts a paired `read` tool call's `path` argument, so embedders can build their own read-targeted compaction protection matchers (e.g. plan-file reads) the same way `isSkillReadToolResult` does.
|
|
36
|
-
- Added optional `AgentTool.matcherDigest(args)` hook: tools whose streamed arguments encode content in a wire grammar (patch formats, escaped strings) can expose the real content they introduce, so stream-content matchers (e.g. TTSR rules) run against plain source text instead of the wire format.
|
|
37
|
-
- Added `shake` compaction primitives (`collectShakeRegions`, `applyShakeRegion`, `applyShakeRegions`, `summarizeShakeRegions`, `DEFAULT_SHAKE_CONFIG`, `AGGRESSIVE_SHAKE_CONFIG`, plus the `ShakeRegion`/`ShakeConfig`/`ShakeSummaryItem`/`ShakeSummaryComplete`/`ProtectedToolMatcher` types) under `@oh-my-pi/pi-agent-core/compaction`. These detect heavy context regions — whole tool-call results plus large fenced/XML blocks — and either elide them with placeholders or extractively compress them through an injected completion backend (no LLM summary cut-point). The compressor is provider-agnostic: callers wire it to a local on-device model. Pure detection/mutation; no I/O.
|
|
38
111
|
|
|
39
112
|
### Changed
|
|
40
113
|
|
|
41
|
-
- Changed `pruneSupersededToolResults` to allow omitted `supersedeKey` when `pruneUseless` is enabled, so useless-result pruning can run without read-style supersede grouping
|
|
42
|
-
- Changed steering handling so queued steering messages are now dequeued only at injection boundaries, with immediate mid-batch interrupt polling using `hasSteeringMessages`. Consumers constructing `AgentLoopConfig` directly with only `getSteeringMessages` no longer get mid-batch interrupts — steering degrades to boundary-only delivery until they also supply `hasSteeringMessages`
|
|
43
|
-
- Compaction, handoff, short-summary, and branch-summarization helpers now accept an `ApiKey` (static string or resolver) instead of a pre-resolved string, so a 401 mid-compaction force-refreshes and rotates the credential through the central auth-retry policy before any model-level fallback. The remote OpenAI compaction request is wrapped in `withAuth` and its HTTP failures now carry `.status`, so the retry classifier actually fires on remote-compaction 401s.
|
|
44
|
-
- `transformProviderContext` now receives the dispatch model as a second argument (`(context, model) => Context`), so per-request transforms can gate on model capabilities (vision input, provider, API family). Existing single-argument implementations keep working unchanged.
|
|
45
|
-
- Remote-compaction and summarization failures now throw pi-ai's typed `ProviderHttpError` instead of mutating plain `Error`s with a `.status` property; the generic `requestRemoteCompaction` error now carries `.status` (and response headers) too.
|
|
46
114
|
- Compaction and branch-summary file lists are now a single `<files>` tag instead of `<read-files>`/`<modified-files>`: paths render as the grouped, prefix-folded directory tree the find/search tools emit (`# dir/` headers, bare basenames), each annotated `(Read)`, `(Write)`, or `(RW)` — modified files that were also read get `(RW)`. Legacy tags in summaries written by earlier versions are still stripped and self-heal on the next compaction
|
|
47
|
-
- Editorial pass over the compaction prompts: fixed garbled grammar and missing articles, RFC-keyed prohibitions, deduped restated instructions; parsed markers (`<read-files>`/`<modified-files>`/`<previous-summary>`) and all output-format headings left byte-identical
|
|
48
|
-
- Catalog imports moved to the new `@oh-my-pi/pi-catalog` package: subpath imports (`calculateCost`, Codex wire constants) plus catalog values previously taken from the `@oh-my-pi/pi-ai` root (`getBundledModel`, `clampThinkingLevelForModel`), which pi-ai no longer re-exports; type-only `Model`/`Api`/`Effort` imports from pi-ai are unchanged
|
|
49
|
-
- Changed core custom and hook messages to convert to `developer` messages for provider context.
|
|
50
|
-
- Enabled streaming API calls to re-resolve credentials through the `getApiKey` callback when retries occur after authentication-related errors
|
|
51
|
-
- `Agent.abort(reason?)` now forwards `reason` to the underlying `AbortController`, and the synthesized aborted assistant message carries that reason on `errorMessage` (string or non-`AbortError` `Error` message) instead of always defaulting to `"Request was aborted"`. Bare `abort()` is unchanged.
|
|
52
|
-
- Changed `Agent.appendMessage`, `popMessage`, `clearMessages`, and `reset` to mutate `state.messages` and `state.pendingToolCalls` in place instead of allocating a fresh array/Set on every transition. Subscribers that capture `state.messages` by reference now observe updates without needing to re-read `state` after each event. The public type signature is unchanged (always `AgentMessage[]` / `Set<string>`).
|
|
53
115
|
|
|
54
116
|
### Fixed
|
|
55
117
|
|
|
56
|
-
- Fixed repetition loop handling to collapse repeated `thinking` blocks to a single representative copy when a loop is detected
|
|
57
|
-
- Fixed repetition-loop detection to ignore repeats that contain only digits, whitespace, or punctuation so legitimate numeric outputs no longer stop with a repetition-loop error
|
|
58
|
-
- Fixed false-positive repetition-loop checks across `text` and `thinking` stream boundaries by tracking loop detection per block type
|
|
59
|
-
- Fixed dynamic forced tool choices from queue hooks being filtered against the active per-turn tool set before provider dispatch. ([#1701](https://github.com/can1357/oh-my-pi/issues/1701))
|
|
60
|
-
- Fixed remote compaction input trimming to use unlimited context when `model.contextWindow` is unset
|
|
61
|
-
- Fixed a regression where steering messages could be injected into history during an aborted in-flight tool batch, leaving them hidden from queue consumers for post-abort continue
|
|
62
|
-
- Fixed whitespace-only error tool results so Anthropic requests no longer 400 with `tool_result: content cannot be empty if is_error is true` and wedge the session on every subsequent turn
|
|
63
118
|
- Fixed queued steering messages being drained into an externally aborted run: interrupting mid-tool execution (e.g. Enter with a pending steer) dequeued the steer into the dying run — it landed in history without a response and the post-abort resume saw an empty queue, so the agent stopped instead of continuing. Steering/follow-up/aside queue polls are now skipped once the run's abort signal fires, leaving the queue intact for `Agent.continue()`.
|
|
64
119
|
- Fixed `<read-files>` compaction lists recording the same file once per line-range/raw selector (`src/foo.ts:50-200`, `:raw`, `:1-50:raw`, …): read-tool selectors are now stripped before tracking, so reads dedupe to the base path and match their write/edit path when splitting read-only vs modified lists. Selector-polluted lists stored by earlier compactions self-heal on the next compaction. `readToolSupersedeKey()` now shares the same splitter (`splitReadSelector()`), gaining the `..` range alias and `L`-prefix forms it previously missed.
|
|
65
120
|
- Fixed `estimateTokens()` undercounting thinking-heavy assistant messages on replay: `thinkingSignature` payloads (OpenAI Responses encrypted reasoning items, Anthropic signed thinking blocks, etc.) and `redactedThinking.data` are now charged alongside the visible thinking text, so the local estimate tracks provider-reported usage instead of straddling the threshold on every turn ([#2275](https://github.com/can1357/oh-my-pi/issues/2275)).
|
|
121
|
+
|
|
122
|
+
## [15.10.12] - 2026-06-10
|
|
123
|
+
|
|
124
|
+
### Added
|
|
125
|
+
|
|
126
|
+
- Added `AgentLoopConfig.getDisableReasoning` so callers can override `disableReasoning` per LLM call, mirroring `getReasoning`.
|
|
127
|
+
- Added `transformProviderContext` to `AgentOptions`/`AgentLoopConfig`: an optional hook applied to the assembled provider context after conversion, normalization, and append-only handling, but before telemetry capture and provider send.
|
|
128
|
+
|
|
129
|
+
### Fixed
|
|
130
|
+
|
|
66
131
|
- Fixed `Agent` runs so explicit reasoning disablement is forwarded to provider stream options and re-resolved per continuation, keeping mid-run thinking-off changes in sync with the next provider request.
|
|
132
|
+
|
|
133
|
+
## [15.10.11] - 2026-06-10
|
|
134
|
+
|
|
135
|
+
### Changed
|
|
136
|
+
|
|
137
|
+
- Editorial pass over the compaction prompts: fixed garbled grammar and missing articles, RFC-keyed prohibitions, deduped restated instructions; parsed markers (`<read-files>`/`<modified-files>`/`<previous-summary>`) and all output-format headings left byte-identical
|
|
138
|
+
- Catalog imports moved to the new `@oh-my-pi/pi-catalog` package: subpath imports (`calculateCost`, Codex wire constants) plus catalog values previously taken from the `@oh-my-pi/pi-ai` root (`getBundledModel`, `clampThinkingLevelForModel`), which pi-ai no longer re-exports; type-only `Model`/`Api`/`Effort` imports from pi-ai are unchanged
|
|
139
|
+
|
|
140
|
+
## [15.10.8] - 2026-06-09
|
|
141
|
+
|
|
142
|
+
### Added
|
|
143
|
+
|
|
144
|
+
- Added optional `fetch` overrides to `SummaryOptions` and `compact`/`generateSummary` so remote compaction can use custom HTTP clients
|
|
145
|
+
- Added optional `fetch` option to `ProxyStreamOptions` to control the HTTP request used by `streamProxy`
|
|
146
|
+
- Added optional `fetch` overrides to `requestOpenAiRemoteCompaction` and `requestRemoteCompaction` for injectable HTTP transport
|
|
147
|
+
- Added the upstream provider that served a request (`AssistantMessage.upstreamProvider`, e.g. OpenRouter's routed provider) as a `pi.gen_ai.response.upstream_provider` chat-span telemetry attribute, alongside the existing response id and time-to-first-chunk.
|
|
148
|
+
|
|
149
|
+
## [15.10.5] - 2026-06-08
|
|
150
|
+
|
|
151
|
+
### Removed
|
|
152
|
+
|
|
153
|
+
- Removed the `maxToolCallsPerTurn` option from `AgentOptions` and `AgentLoopConfig`, so assistant turns are no longer capped after a configured number of completed tool calls
|
|
154
|
+
|
|
155
|
+
### Fixed
|
|
156
|
+
|
|
67
157
|
- Fixed stalled aborted assistant responses so the run now stops without waiting for provider iterator cleanup and returns the aborted message promptly
|
|
68
158
|
- Fixed `afterToolCall` handling so it now runs for completed tool executions even after a run is aborted so tool post-processing still applies
|
|
69
159
|
- Fixed `agentLoopDetailed().detailed()` so run telemetry and coverage are captured before `stream.result()` resolves.
|
|
@@ -74,64 +164,96 @@
|
|
|
74
164
|
- Fixed tool-call completion so assistant messages on abort keep only completed tool-call blocks and continue processing tool calls when a length stop still included results
|
|
75
165
|
- Fixed deliberate aborts (TTSR rule matches, user-interrupt labels) so a mid-stream tool-call block that never reached `toolcall_end` is retained on the aborted assistant message and paired with a placeholder result labeled by the abort reason, instead of being dropped; anonymous aborts (bare `abort()`) still drop incomplete tool calls whose partial arguments are unsafe to replay
|
|
76
166
|
- Fixed runs that stopped with reason `length` after returning tool results so execution continues to handle additional tool calls
|
|
167
|
+
|
|
168
|
+
## [15.10.3] - 2026-06-08
|
|
169
|
+
|
|
170
|
+
### Added
|
|
171
|
+
|
|
172
|
+
- Added a non-interrupting "aside" message channel to the agent loop (`AgentLoopConfig.getAsideMessages` / `Agent.setAsideMessageProvider`). Asides are drained at each step boundary (after a tool batch, before the next model call) and at the yield check, so passive notifications (e.g. background-job completions, late LSP diagnostics) reach the model *between requests* without waiting for the agent to stop and without aborting in-flight tools the way steering does.
|
|
173
|
+
|
|
174
|
+
### Changed
|
|
175
|
+
|
|
176
|
+
- Changed core custom and hook messages to convert to `developer` messages for provider context.
|
|
177
|
+
|
|
178
|
+
### Fixed
|
|
179
|
+
|
|
77
180
|
- Fixed the compaction spinner freezing (only repainting on a terminal resize) when compacting very large codex/OpenAI contexts. `buildOpenAiNativeHistory` re-collected the full known/custom tool-call id sets on every history-bearing message, rescanning the entire growing native history each time — O(N²) in history items — which blocked the event loop for seconds and starved the loader's animation timer and render scheduler. The sets are now maintained incrementally (linear), so building the compaction request no longer monopolizes the main thread.
|
|
78
|
-
- Fixed proxy stream silently returning a zero-token success response when the server disconnects without sending a `done` or `error` terminal SSE event. The stream now throws an error, surfacing the disconnect as an `error` event with `stopReason: "error"` and resolving `finalResultPromise`, instead of defaulting to `stopReason: "stop"` with empty content and leaving `stream.result()` callers hanging indefinitely.
|
|
79
|
-
- Fixed handling of short-lived API keys so that expired tokens are retried with a refreshed value during 401/usage-limit failures
|
|
80
|
-
- Ensured fallback API key resolution uses the initially configured static `apiKey` when `getApiKey` is present
|
|
81
|
-
- Wrapped oneshot LLM completions (`instrumentedCompleteSimple`: handoff, compaction/branch summaries) in an `EventLoopKeepalive`. These run outside the agent `#runLoop`, so without the keepalive Bun's event loop stopped servicing timers while parked on the completion promise — freezing host spinners (e.g. the `/handoff` loader) until an unrelated terminal resize poked the loop into rendering again.
|
|
82
|
-
- Surfaced Anthropic stream failures whose message starts with `Output blocked by conten` as normal assistant error lifecycle events, so interactive clients render content-filter blocks instead of silently dropping the streaming bubble at `agent_end`.
|
|
83
|
-
- Fixed the agent loop wedging the model when a `write`/`edit` tool call is truncated by `stop_reason: length` (e.g. an OpenCode Zen / Claude-3.5-Haiku turn that emits >~1000 lines of code, blowing past the 8K `max_tokens` output cap). The skipped tool result now surfaces an actionable hint — naming `stop_reason: length` and telling the model to split the payload into multiple smaller calls — instead of the generic "Tool call was not executed because the assistant ended its turn" placeholder, which left the auto-continue loop re-emitting the same oversized payload until the user gave up. Tools are still NOT executed when the arguments are truncated. ([#1785](https://github.com/can1357/oh-my-pi/issues/1785))
|
|
84
|
-
- Engaged GPT-5 Harmony leak detection on the committed assistant message (openai-codex only). `detectHarmonyLeakInAssistantMessage` now runs on the streamed `done`/`error` result and the trailing fallback, so a leaked final response is aborted-and-retried by the existing mitigation instead of being committed as-is. Tool-argument (`tool_arg`) scanning is gated on the trailing-garbage `T` co-signal and only fires when a caller supplies a parse boundary via `detectHarmonyLeakInAssistantMessage`'s new optional `toolArgParseEnd` resolver. The agent loop passes none — it cannot bound a streamed tool DSL — so that surface stays inert and a legitimate codex tool call whose content legitimately carries `to=functions.*` next to a channel word or non-Latin script (e.g. editing the harmony fixtures) is never hard-aborted.
|
|
85
|
-
- Fixed tool-output pruning and shake protection for `read`: ordinary file/URL reads are now eligible for compaction, while `read` calls whose `path` starts with `skill://` remain protected like native `skill` results.
|
|
86
181
|
|
|
87
182
|
### Removed
|
|
88
183
|
|
|
89
|
-
- Removed the `maxToolCallsPerTurn` option from `AgentOptions` and `AgentLoopConfig`, so assistant turns are no longer capped after a configured number of completed tool calls
|
|
90
184
|
- Removed the now-dead `<turn-aborted>` marker from the OpenAI compaction output user-message filter, since `transformMessages` no longer emits that note.
|
|
91
185
|
- Removed stale synthetic user-message tag filters from OpenAI remote compaction output preservation; developer messages are now dropped by role instead.
|
|
92
186
|
- Tool executions now receive the active turn `AbortSignal` unconditionally.
|
|
93
|
-
- Removed the local-model `summarizeShakeRegions` compressor and related shake-summary prompt/types; shake now only provides mechanical artifact-backed elision primitives.
|
|
94
187
|
|
|
95
|
-
## [15.
|
|
188
|
+
## [15.10.2] - 2026-06-08
|
|
96
189
|
|
|
97
|
-
|
|
190
|
+
### Fixed
|
|
98
191
|
|
|
99
|
-
|
|
192
|
+
- Fixed proxy stream silently returning a zero-token success response when the server disconnects without sending a `done` or `error` terminal SSE event. The stream now throws an error, surfacing the disconnect as an `error` event with `stopReason: "error"` and resolving `finalResultPromise`, instead of defaulting to `stopReason: "stop"` with empty content and leaving `stream.result()` callers hanging indefinitely.
|
|
100
193
|
|
|
101
|
-
## [15.
|
|
194
|
+
## [15.10.1] - 2026-06-07
|
|
102
195
|
|
|
103
|
-
|
|
196
|
+
### Added
|
|
104
197
|
|
|
105
|
-
|
|
198
|
+
- Added optional `promptCacheKey` support to `AgentOptions` and `Agent` via a new `promptCacheKey` property so providers can receive a caller-provided prompt cache key
|
|
199
|
+
- Added optional `ApiKeyResolveContext` parameter to `getApiKey` in `AgentOptions` and `AgentLoopConfig` so key resolvers can receive retry context
|
|
106
200
|
|
|
107
|
-
|
|
201
|
+
### Changed
|
|
108
202
|
|
|
109
|
-
|
|
203
|
+
- Enabled streaming API calls to re-resolve credentials through the `getApiKey` callback when retries occur after authentication-related errors
|
|
204
|
+
- `Agent.abort(reason?)` now forwards `reason` to the underlying `AbortController`, and the synthesized aborted assistant message carries that reason on `errorMessage` (string or non-`AbortError` `Error` message) instead of always defaulting to `"Request was aborted"`. Bare `abort()` is unchanged.
|
|
110
205
|
|
|
111
|
-
|
|
206
|
+
### Fixed
|
|
112
207
|
|
|
113
|
-
|
|
208
|
+
- Fixed handling of short-lived API keys so that expired tokens are retried with a refreshed value during 401/usage-limit failures
|
|
209
|
+
- Ensured fallback API key resolution uses the initially configured static `apiKey` when `getApiKey` is present
|
|
210
|
+
- Wrapped oneshot LLM completions (`instrumentedCompleteSimple`: handoff, compaction/branch summaries) in an `EventLoopKeepalive`. These run outside the agent `#runLoop`, so without the keepalive Bun's event loop stopped servicing timers while parked on the completion promise — freezing host spinners (e.g. the `/handoff` loader) until an unrelated terminal resize poked the loop into rendering again.
|
|
114
211
|
|
|
115
|
-
## [15.
|
|
212
|
+
## [15.9.5] - 2026-06-05
|
|
116
213
|
|
|
117
|
-
|
|
214
|
+
### Fixed
|
|
118
215
|
|
|
119
|
-
|
|
216
|
+
- Surfaced Anthropic stream failures whose message starts with `Output blocked by conten` as normal assistant error lifecycle events, so interactive clients render content-filter blocks instead of silently dropping the streaming bubble at `agent_end`.
|
|
120
217
|
|
|
121
|
-
## [15.
|
|
218
|
+
## [15.8.3] - 2026-06-03
|
|
122
219
|
|
|
123
|
-
|
|
220
|
+
### Added
|
|
124
221
|
|
|
125
|
-
|
|
222
|
+
- Added `getReadToolPath(context)` to `@oh-my-pi/pi-agent-core/compaction/tool-protection` to extract a paired `read` tool call's `path` for embedders building read-targeted protection matchers
|
|
223
|
+
- Added `getReadToolPath(context)` to `@oh-my-pi/pi-agent-core/compaction/tool-protection`: the shared primitive that extracts a paired `read` tool call's `path` argument, so embedders can build their own read-targeted compaction protection matchers (e.g. plan-file reads) the same way `isSkillReadToolResult` does.
|
|
126
224
|
|
|
127
225
|
## [15.8.2] - 2026-06-03
|
|
128
226
|
|
|
227
|
+
### Added
|
|
228
|
+
|
|
229
|
+
- Added optional `AgentTool.matcherDigest(args)` hook: tools whose streamed arguments encode content in a wire grammar (patch formats, escaped strings) can expose the real content they introduce, so stream-content matchers (e.g. TTSR rules) run against plain source text instead of the wire format.
|
|
230
|
+
|
|
231
|
+
### Fixed
|
|
232
|
+
|
|
233
|
+
- Fixed the agent loop wedging the model when a `write`/`edit` tool call is truncated by `stop_reason: length` (e.g. an OpenCode Zen / Claude-3.5-Haiku turn that emits >~1000 lines of code, blowing past the 8K `max_tokens` output cap). The skipped tool result now surfaces an actionable hint — naming `stop_reason: length` and telling the model to split the payload into multiple smaller calls — instead of the generic "Tool call was not executed because the assistant ended its turn" placeholder, which left the auto-continue loop re-emitting the same oversized payload until the user gave up. Tools are still NOT executed when the arguments are truncated. ([#1785](https://github.com/can1357/oh-my-pi/issues/1785))
|
|
234
|
+
|
|
129
235
|
## [15.8.0] - 2026-06-02
|
|
130
236
|
|
|
237
|
+
### Fixed
|
|
238
|
+
|
|
239
|
+
- Engaged GPT-5 Harmony leak detection on the committed assistant message (openai-codex only). `detectHarmonyLeakInAssistantMessage` now runs on the streamed `done`/`error` result and the trailing fallback, so a leaked final response is aborted-and-retried by the existing mitigation instead of being committed as-is. Tool-argument (`tool_arg`) scanning is gated on the trailing-garbage `T` co-signal and only fires when a caller supplies a parse boundary via `detectHarmonyLeakInAssistantMessage`'s new optional `toolArgParseEnd` resolver. The agent loop passes none — it cannot bound a streamed tool DSL — so that surface stays inert and a legitimate codex tool call whose content legitimately carries `to=functions.*` next to a channel word or non-Latin script (e.g. editing the harmony fixtures) is never hard-aborted.
|
|
240
|
+
|
|
131
241
|
## [15.7.4] - 2026-05-31
|
|
132
242
|
|
|
243
|
+
### Removed
|
|
244
|
+
|
|
245
|
+
- Removed the local-model `summarizeShakeRegions` compressor and related shake-summary prompt/types; shake now only provides mechanical artifact-backed elision primitives.
|
|
246
|
+
|
|
133
247
|
## [15.7.3] - 2026-05-31
|
|
134
248
|
|
|
249
|
+
### Added
|
|
250
|
+
|
|
251
|
+
- Added `shake` compaction primitives (`collectShakeRegions`, `applyShakeRegion`, `applyShakeRegions`, `summarizeShakeRegions`, `DEFAULT_SHAKE_CONFIG`, `AGGRESSIVE_SHAKE_CONFIG`, plus the `ShakeRegion`/`ShakeConfig`/`ShakeSummaryItem`/`ShakeSummaryComplete`/`ProtectedToolMatcher` types) under `@oh-my-pi/pi-agent-core/compaction`. These detect heavy context regions — whole tool-call results plus large fenced/XML blocks — and either elide them with placeholders or extractively compress them through an injected completion backend (no LLM summary cut-point). The compressor is provider-agnostic: callers wire it to a local on-device model. Pure detection/mutation; no I/O.
|
|
252
|
+
|
|
253
|
+
### Fixed
|
|
254
|
+
|
|
255
|
+
- Fixed tool-output pruning and shake protection for `read`: ordinary file/URL reads are now eligible for compaction, while `read` calls whose `path` starts with `skill://` remain protected like native `skill` results.
|
|
256
|
+
|
|
135
257
|
## [15.5.15] - 2026-05-30
|
|
136
258
|
|
|
137
259
|
### Added
|
|
@@ -567,7 +689,7 @@
|
|
|
567
689
|
|
|
568
690
|
### Changed
|
|
569
691
|
|
|
570
|
-
- Switched from local `@oh-my-pi/pi-ai` to upstream `@
|
|
692
|
+
- Switched from local `@oh-my-pi/pi-ai` to upstream `@mariozechner/pi-ai` package
|
|
571
693
|
|
|
572
694
|
### Added
|
|
573
695
|
|
|
@@ -620,39 +742,65 @@
|
|
|
620
742
|
|
|
621
743
|
Initial release under @oh-my-pi scope. See previous releases at [badlogic/pi-mono](https://github.com/badlogic/pi-mono).
|
|
622
744
|
|
|
745
|
+
## [0.38.0] - 2026-01-08
|
|
746
|
+
|
|
747
|
+
### Added
|
|
748
|
+
|
|
749
|
+
- `thinkingBudgets` option on `Agent` and `AgentOptions` to customize token budgets per thinking level ([#529](https://github.com/badlogic/pi-mono/pull/529) by [@melihmucuk](https://github.com/melihmucuk))
|
|
750
|
+
|
|
751
|
+
## [0.37.3] - 2026-01-06
|
|
752
|
+
|
|
753
|
+
### Added
|
|
754
|
+
|
|
755
|
+
- `sessionId` option on `Agent` to forward session identifiers to LLM providers for session-based caching.
|
|
756
|
+
|
|
757
|
+
## [0.37.0] - 2026-01-05
|
|
758
|
+
|
|
759
|
+
### Fixed
|
|
760
|
+
|
|
761
|
+
- `minimal` thinking level now maps to `minimal` reasoning effort instead of being treated as `low`.
|
|
762
|
+
|
|
763
|
+
## [0.32.0] - 2026-01-03
|
|
764
|
+
|
|
765
|
+
### Breaking Changes
|
|
766
|
+
|
|
767
|
+
- **Queue API replaced with steer/followUp**: The `queueMessage()` method has been split into two methods with different delivery semantics ([#403](https://github.com/badlogic/pi-mono/issues/403)):
|
|
768
|
+
- `steer(msg)`: Interrupts the agent mid-run. Delivered after current tool execution, skips remaining tools.
|
|
769
|
+
- `followUp(msg)`: Waits until the agent finishes. Delivered only when there are no more tool calls or steering messages.
|
|
770
|
+
- **Queue mode renamed**: `queueMode` option renamed to `steeringMode`. Added new `followUpMode` option. Both control whether messages are delivered one-at-a-time or all at once.
|
|
771
|
+
- **AgentLoopConfig callbacks renamed**: `getQueuedMessages` split into `getSteeringMessages` and `getFollowUpMessages`.
|
|
772
|
+
- **Agent methods renamed**:
|
|
773
|
+
- `queueMessage()` → `steer()` and `followUp()`
|
|
774
|
+
- `clearMessageQueue()` → `clearSteeringQueue()`, `clearFollowUpQueue()`, `clearAllQueues()`
|
|
775
|
+
- `setQueueMode()`/`getQueueMode()` → `setSteeringMode()`/`getSteeringMode()` and `setFollowUpMode()`/`getFollowUpMode()`
|
|
776
|
+
|
|
777
|
+
### Fixed
|
|
778
|
+
|
|
779
|
+
- `prompt()` and `continue()` now throw if called while the agent is already streaming, preventing race conditions and corrupted state. Use `steer()` or `followUp()` to queue messages during streaming, or `await` the previous call.
|
|
780
|
+
|
|
623
781
|
## [0.31.0] - 2026-01-02
|
|
624
782
|
|
|
625
783
|
### Breaking Changes
|
|
626
784
|
|
|
627
785
|
- **Transport abstraction removed**: `ProviderTransport`, `AppTransport`, and `AgentTransport` interface have been removed. Use the `streamFn` option directly for custom streaming implementations.
|
|
628
|
-
|
|
629
786
|
- **Agent options renamed**:
|
|
630
787
|
- `transport` → removed (use `streamFn` instead)
|
|
631
788
|
- `messageTransformer` → `convertToLlm`
|
|
632
789
|
- `preprocessor` → `transformContext`
|
|
633
|
-
|
|
634
790
|
- **`AppMessage` renamed to `AgentMessage`**: All references to `AppMessage` have been renamed to `AgentMessage` for consistency.
|
|
635
|
-
|
|
636
791
|
- **`CustomMessages` renamed to `CustomAgentMessages`**: The declaration merging interface has been renamed.
|
|
637
|
-
|
|
638
792
|
- **`UserMessageWithAttachments` and `Attachment` types removed**: Attachment handling is now the responsibility of the `convertToLlm` function.
|
|
639
|
-
|
|
640
793
|
- **Agent loop moved from `@oh-my-pi/pi-ai`**: The `agentLoop`, `agentLoopContinue`, and related types have moved to this package. Import from `@oh-my-pi/pi-agent` instead.
|
|
641
794
|
|
|
642
795
|
### Added
|
|
643
796
|
|
|
644
797
|
- `streamFn` option on `Agent` for custom stream implementations. Default uses `streamSimple` from pi-ai.
|
|
645
|
-
|
|
646
798
|
- `streamProxy()` utility function for browser apps that need to proxy LLM calls through a backend server. Replaces the removed `AppTransport`.
|
|
647
|
-
|
|
648
799
|
- `getApiKey` option for dynamic API key resolution (useful for expiring OAuth tokens like GitHub Copilot).
|
|
649
|
-
|
|
650
800
|
- `agentLoop()` and `agentLoopContinue()` low-level functions for running the agent loop without the `Agent` class wrapper.
|
|
651
|
-
|
|
652
801
|
- New exported types: `AgentLoopConfig`, `AgentContext`, `AgentTool`, `AgentToolResult`, `AgentToolUpdateCallback`, `StreamFn`.
|
|
653
802
|
|
|
654
803
|
### Changed
|
|
655
804
|
|
|
656
805
|
- `Agent` constructor now has all options optional (empty options use defaults).
|
|
657
|
-
|
|
658
806
|
- `queueMessage()` is now synchronous (no longer returns a Promise).
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Transforms to Message[] only at the LLM call boundary.
|
|
4
4
|
*/
|
|
5
5
|
import { type Context, EventStream } from "@oh-my-pi/pi-ai";
|
|
6
|
+
import { type ToolCallSyntax } from "@oh-my-pi/pi-ai/grammar";
|
|
6
7
|
import { type AgentRunCoverage, type AgentRunSummary } from "./run-collector";
|
|
7
8
|
import type { AgentContext, AgentEvent, AgentLoopConfig, AgentMessage, StreamFn } from "./types";
|
|
8
9
|
/**
|
|
@@ -52,7 +53,7 @@ export declare function agentLoopContinueDetailed(context: AgentContext, config:
|
|
|
52
53
|
readonly detailed: () => Promise<AgentLoopDetailedResult>;
|
|
53
54
|
};
|
|
54
55
|
export declare const INTENT_FIELD = "_i";
|
|
55
|
-
export declare function normalizeTools(tools: AgentContext["tools"], injectIntent: boolean): Context["tools"];
|
|
56
|
+
export declare function normalizeTools(tools: AgentContext["tools"], injectIntent: boolean, exampleSyntax?: ToolCallSyntax): Context["tools"];
|
|
56
57
|
/** Resolve the human-readable reason an abort carried. A caller that aborts via
|
|
57
58
|
* `AbortController.abort(reason)` with a string or a non-`AbortError` `Error`
|
|
58
59
|
* (e.g. the coding agent's user-interrupt label) gets that text surfaced on the
|
package/dist/types/agent.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ApiKeyResolveContext, type AssistantMessage, type AssistantMessageEvent, type Context, type CursorExecHandlers, type CursorToolResultHandler, type Effort, type ImageContent, type Message, type Model, type ProviderSessionState, type ServiceTier, type SimpleStreamOptions, type ThinkingBudgets, type ToolChoice } from "@oh-my-pi/pi-ai";
|
|
2
|
+
import type { ToolCallSyntax } from "@oh-my-pi/pi-ai/grammar";
|
|
3
|
+
import type { HarmonyAuditEvent } from "@oh-my-pi/pi-ai/utils/harmony-leak";
|
|
2
4
|
import type { AppendOnlyContextManager } from "./append-only-context";
|
|
3
|
-
import type { HarmonyAuditEvent } from "./harmony-leak";
|
|
4
5
|
import type { AgentEvent, AgentLoopConfig, AgentMessage, AgentState, AgentTool, AgentToolContext, AsideMessage, StreamFn, ToolCallContext } from "./types";
|
|
5
6
|
export declare class AgentBusyError extends Error {
|
|
6
7
|
constructor(message?: string);
|
|
@@ -126,6 +127,15 @@ export interface AgentOptions {
|
|
|
126
127
|
transformToolCallArguments?: (args: Record<string, unknown>, toolName: string) => Record<string, unknown>;
|
|
127
128
|
/** Enable intent tracing schema injection/stripping in the harness. */
|
|
128
129
|
intentTracing?: boolean;
|
|
130
|
+
/** Owned tool-calling syntax. Undefined keeps provider-native tool calling. */
|
|
131
|
+
toolCallSyntax?: ToolCallSyntax;
|
|
132
|
+
/**
|
|
133
|
+
* When owned tool calling is active and the model fabricates a tool result
|
|
134
|
+
* mid-turn: `true` (default) aborts the provider request immediately; `false`
|
|
135
|
+
* drains the request and discards the fabricated continuation. Forwarded to
|
|
136
|
+
* the loop's {@link AgentLoopConfig.abortOnFabricatedToolResult}.
|
|
137
|
+
*/
|
|
138
|
+
abortOnFabricatedToolResult?: boolean;
|
|
129
139
|
/** Dynamic tool choice override, resolved per LLM call. */
|
|
130
140
|
getToolChoice?: () => ToolChoice | undefined;
|
|
131
141
|
/**
|
|
@@ -296,7 +306,7 @@ export declare class Agent {
|
|
|
296
306
|
*/
|
|
297
307
|
setAsideMessageProvider(fn: (() => AsideMessage[] | Promise<AsideMessage[]>) | undefined): void;
|
|
298
308
|
emitExternalEvent(event: AgentEvent): void;
|
|
299
|
-
setSystemPrompt(v: string[]): void;
|
|
309
|
+
setSystemPrompt(v: string[] | string): void;
|
|
300
310
|
setModel(m: Model): void;
|
|
301
311
|
setThinkingLevel(l: Effort | undefined): void;
|
|
302
312
|
setDisableReasoning(disabled: boolean): void;
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* message delta is a cache miss each turn.
|
|
15
15
|
*/
|
|
16
16
|
import type { Context, Message, Tool } from "@oh-my-pi/pi-ai";
|
|
17
|
+
import type { ToolCallSyntax } from "@oh-my-pi/pi-ai/grammar";
|
|
17
18
|
import type { AgentContext } from "./types";
|
|
18
19
|
/** Frozen system prompt + tool spec snapshot. */
|
|
19
20
|
export interface StablePrefixSnapshot {
|
|
@@ -25,6 +26,7 @@ export interface StablePrefixSnapshot {
|
|
|
25
26
|
export interface BuildOptions {
|
|
26
27
|
/** Inject the `_i` intent field into tool schemas (must match agent-loop's normalizeTools). */
|
|
27
28
|
intentTracing: boolean;
|
|
29
|
+
exampleSyntax?: ToolCallSyntax;
|
|
28
30
|
}
|
|
29
31
|
/**
|
|
30
32
|
* A frozen prefix (system prompt + tools) that produces stable byte
|
package/dist/types/index.d.ts
CHANGED
package/dist/types/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ApiKeyResolveContext, AssistantMessage, AssistantMessageEvent, AssistantMessageEventStream, Context, Effort, ImageContent, Message, Model, SimpleStreamOptions, Static, streamSimple, TextContent, Tool, ToolChoice, ToolResultMessage, TSchema } from "@oh-my-pi/pi-ai";
|
|
2
|
+
import type { ToolCallSyntax } from "@oh-my-pi/pi-ai/grammar";
|
|
3
|
+
import type { HarmonyAuditEvent } from "@oh-my-pi/pi-ai/utils/harmony-leak";
|
|
2
4
|
import type { AppendOnlyContextManager } from "./append-only-context";
|
|
3
|
-
import type { HarmonyAuditEvent } from "./harmony-leak";
|
|
4
5
|
import type { AgentRunCoverage, AgentRunSummary } from "./run-collector";
|
|
5
6
|
import type { AgentTelemetryConfig } from "./telemetry";
|
|
6
7
|
/** Stream function - can return sync or Promise for async config lookup */
|
|
@@ -162,6 +163,27 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
|
|
|
162
163
|
* then strips from arguments before executing tools.
|
|
163
164
|
*/
|
|
164
165
|
intentTracing?: boolean;
|
|
166
|
+
/**
|
|
167
|
+
* Owned tool calling syntax.
|
|
168
|
+
*
|
|
169
|
+
* Undefined keeps provider-native tool calling. A syntax value sends no
|
|
170
|
+
* native `tools`, forces `toolChoice` off, appends that syntax's tool catalog
|
|
171
|
+
* instructions, re-encodes prior tool calls/results as text, and parses the
|
|
172
|
+
* model's text output back into canonical `toolCall` blocks.
|
|
173
|
+
*/
|
|
174
|
+
toolCallSyntax?: ToolCallSyntax;
|
|
175
|
+
/**
|
|
176
|
+
* When owned (in-band) tool calling is active and the model starts
|
|
177
|
+
* fabricating a tool result inside its own turn, control how the loop reacts:
|
|
178
|
+
* - `true` (default): abort the provider request immediately so it stops
|
|
179
|
+
* generating the hallucinated continuation (cheaper, lower latency).
|
|
180
|
+
* - `false`: let the request finish and silently discard everything past the
|
|
181
|
+
* fabrication boundary (keeps the connection alive but pays for the tokens
|
|
182
|
+
* the model spends on the discarded tail).
|
|
183
|
+
* Only meaningful when {@link toolCallSyntax} (or `PI_OWNED_TOOLS`) selects an
|
|
184
|
+
* owned syntax; native tool calling never fabricates results in text.
|
|
185
|
+
*/
|
|
186
|
+
abortOnFabricatedToolResult?: boolean;
|
|
165
187
|
/**
|
|
166
188
|
* Append-only context mode — stabilizes system prompt + tool spec bytes
|
|
167
189
|
* across turns so provider prefix caches hit at maximum rate.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-agent-core",
|
|
4
|
-
"version": "15.13.
|
|
4
|
+
"version": "15.13.2",
|
|
5
5
|
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
"fmt": "biome format --write ."
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@oh-my-pi/pi-ai": "15.13.
|
|
39
|
-
"@oh-my-pi/pi-catalog": "15.13.
|
|
40
|
-
"@oh-my-pi/pi-natives": "15.13.
|
|
41
|
-
"@oh-my-pi/pi-utils": "15.13.
|
|
42
|
-
"@oh-my-pi/snapcompact": "15.13.
|
|
38
|
+
"@oh-my-pi/pi-ai": "15.13.2",
|
|
39
|
+
"@oh-my-pi/pi-catalog": "15.13.2",
|
|
40
|
+
"@oh-my-pi/pi-natives": "15.13.2",
|
|
41
|
+
"@oh-my-pi/pi-utils": "15.13.2",
|
|
42
|
+
"@oh-my-pi/snapcompact": "15.13.2",
|
|
43
43
|
"@opentelemetry/api": "^1.9.1"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|