@mono-agent/agent-runtime 0.15.0 → 0.15.1
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/MIGRATION.md +135 -67
- package/README.md +57 -2
- package/package.json +1 -1
- package/src/agent/compaction.js +0 -11
- package/src/agent/prompt/skill-index.js +5 -1
- package/src/ai/index.js +7 -0
- package/src/ai/pi-interop.js +156 -0
- package/src/ai/providers/claude-sdk.js +2 -1
- package/src/ai/providers/codex-app.js +42 -13
- package/src/ai/runtime/live-input-events.js +94 -0
- package/src/ai/runtime/router.js +21 -0
- package/src/ai/types.js +1 -0
- package/src/runtime.js +3 -0
- package/types/agent/compaction.d.ts +0 -2
- package/types/agent/prompt/skill-index.d.ts +3 -0
- package/types/ai/index.d.ts +1 -0
- package/types/ai/pi-interop.d.ts +113 -0
- package/types/ai/runtime/live-input-events.d.ts +22 -0
- package/types/ai/types.d.ts +5 -0
- package/types/ai/backend.d.ts +0 -57
- package/types/ai/registry.d.ts +0 -1
package/MIGRATION.md
CHANGED
|
@@ -13,7 +13,88 @@ primary route.
|
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
##
|
|
16
|
+
## 0.15.1
|
|
17
|
+
|
|
18
|
+
- **Runtime-owned Pi interoperability:** consumers that directly import
|
|
19
|
+
`@earendil-works/pi-ai` only for catalog, reasoning, or OAuth behavior should
|
|
20
|
+
switch to `listPiBuiltinModels`, `getPiBuiltinModel`,
|
|
21
|
+
`reasoningLevelsForPiModel`, `resolvePiOAuthApiKey`, and `loginPiOAuth` from
|
|
22
|
+
`@mono-agent/agent-runtime/ai`. The runtime keeps Pi AI and Pi Agent Core
|
|
23
|
+
exact-pinned at `0.80.6`; the façade returns cloned model and credential
|
|
24
|
+
snapshots rather than exposing mutable upstream registries.
|
|
25
|
+
- **Claude test seam:** downstream tests should pass
|
|
26
|
+
`RuntimeRunOptions.claudeAgentQuery` instead of mocking
|
|
27
|
+
`@anthropic-ai/claude-agent-sdk` by package name. Normal runs omit this option
|
|
28
|
+
and use the runtime-owned SDK. Pi AI's `@anthropic-ai/sdk@0.91.1` pin and the
|
|
29
|
+
Claude Agent SDK's `@anthropic-ai/sdk>=0.93.0` requirement intentionally
|
|
30
|
+
remain as two isolated SDK versions.
|
|
31
|
+
- **Compaction policy cleanup:** the inert
|
|
32
|
+
`toolPayloadCompactionTriggerChars` and `toolPruneTriggerTokens` properties
|
|
33
|
+
were removed from `AgentCompactionPolicy`, policy resolution, defaults, and
|
|
34
|
+
declarations. They had no supported typed/config path and did not activate
|
|
35
|
+
runtime pruning, so no replacement is required.
|
|
36
|
+
- **Codex live-input teardown:** a Codex app-server transport death now also
|
|
37
|
+
terminates a pending live-input read. Runs settle with the existing
|
|
38
|
+
`provider_unavailable` / `codex_app_server_closed` classification instead of
|
|
39
|
+
waiting forever for the input iterator. If a host `acknowledge` or `reject`
|
|
40
|
+
callback throws, the already-decided native steering result remains
|
|
41
|
+
authoritative and the runtime emits a bounded
|
|
42
|
+
`live_input_callback_failed` warning.
|
|
43
|
+
|
|
44
|
+
## 0.15.x baseline
|
|
45
|
+
|
|
46
|
+
This is the current published baseline for the detailed pre-1.0 reference
|
|
47
|
+
below. It includes the explicit exports map, the five-bridge lazy registry,
|
|
48
|
+
typed runtime policies, runtime-owned provider dependencies, and the
|
|
49
|
+
public-surface cleanup described in this guide.
|
|
50
|
+
|
|
51
|
+
## 0.12.x
|
|
52
|
+
|
|
53
|
+
- Persistent provider context overflow is classified as `context_limit`, which
|
|
54
|
+
lets a fallback router try its next model without conflating context capacity
|
|
55
|
+
with quota, output, or max-turn `usage_limit` failures.
|
|
56
|
+
- Omitted Pi compaction values resolve from effective context window `W`:
|
|
57
|
+
trigger ratio `0.70`, retained context `10%`, summary output `4%`, and minimum
|
|
58
|
+
proactive savings `10%`, subject to the documented scalar clamps. Numeric
|
|
59
|
+
provider limits and generic overflow evidence may lower a learned
|
|
60
|
+
process-local ceiling; `contextWindowOverride` remains the persistent
|
|
61
|
+
correction.
|
|
62
|
+
|
|
63
|
+
## 0.10.x
|
|
64
|
+
|
|
65
|
+
- `ReadSkill` returns complete skill instructions by default, including content
|
|
66
|
+
beyond the former 12,000-character boundary. Programmatic callers of
|
|
67
|
+
`formatSkillBodyWithPathNote()` opt into truncation by passing a positive
|
|
68
|
+
`maxChars`; omitting it means no helper-level cap. The standard 256 KiB
|
|
69
|
+
tool-payload guard remains in effect.
|
|
70
|
+
|
|
71
|
+
## 0.7.x
|
|
72
|
+
|
|
73
|
+
- Omitting Claude SDK effort now preserves the provider default instead of
|
|
74
|
+
deriving a `thinking` option. Supported effort values are forwarded exactly;
|
|
75
|
+
explicit `none` is unsupported (`skipped_capability_mismatch` through the
|
|
76
|
+
bridge, while direct `claudeEffortOptions("none")` calls throw).
|
|
77
|
+
- Cancellation uses a private abort controller and closes the active Claude SDK
|
|
78
|
+
`Query` with `Query.close()`. Test doubles must honor both boundaries rather
|
|
79
|
+
than implementing only iterator `return()`.
|
|
80
|
+
- `Glob` and `Grep` prefer an explicit `ripgrepPath`, then the packaged
|
|
81
|
+
`@vscode/ripgrep` binary on supported platforms, and finally `PATH`.
|
|
82
|
+
|
|
83
|
+
## 0.6.2
|
|
84
|
+
|
|
85
|
+
- Codex file edits use a flat top-level `file_change` event instead of synthetic
|
|
86
|
+
assistant/user `file_edit` tool-use/tool-result pairs.
|
|
87
|
+
- The synthetic `createClaudeFileEditHooks`,
|
|
88
|
+
`createFileEditToolUseEvent`, and `createFileEditToolResultEvent` exports were
|
|
89
|
+
removed. Consumers should observe normalized runtime events or use the
|
|
90
|
+
remaining file-change statistics helpers rather than recreating provider hook
|
|
91
|
+
behavior.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Detailed pre-1.0 reference
|
|
96
|
+
|
|
97
|
+
### Pre-1.0 public-surface cleanup
|
|
17
98
|
|
|
18
99
|
The compatibility entrypoints `./ai/backend.js` and `./ai/registry.js` were
|
|
19
100
|
removed after repository-wide reachability checks found no supported caller.
|
|
@@ -24,7 +105,7 @@ instead. Runtime behavior and the canonical bridge descriptors are unchanged.
|
|
|
24
105
|
|
|
25
106
|
---
|
|
26
107
|
|
|
27
|
-
|
|
108
|
+
### 1. Pi is now native-only (`pi-sdk.js` → `pi-native.js`)
|
|
28
109
|
|
|
29
110
|
The hand-rolled Pi bridge that drove the low-level `Agent` was replaced by a
|
|
30
111
|
bridge built on `@earendil-works/pi-agent-core`'s high-level `AgentHarness`. The
|
|
@@ -43,7 +124,7 @@ registry resolves `pi` → the native bridge unconditionally; there is no
|
|
|
43
124
|
`@mono-agent/agent-runtime/ai/failure.js`. The `pi*Backend` aliases are gone —
|
|
44
125
|
all Pi routes through the native bridge.
|
|
45
126
|
|
|
46
|
-
|
|
127
|
+
### 2. Removed run options: `piReasoningSummary`, `piCodexTransport`
|
|
47
128
|
|
|
48
129
|
These were Pi-bridge knobs the native path does not consume.
|
|
49
130
|
|
|
@@ -54,7 +135,7 @@ These were Pi-bridge knobs the native path does not consume.
|
|
|
54
135
|
`runtime.reasoningSummary` config field has also been removed.
|
|
55
136
|
- `piCodexTransport` was doc-only and is removed. No replacement is needed.
|
|
56
137
|
|
|
57
|
-
|
|
138
|
+
### 3. Pi context compaction: bridge-driven via AgentHarness.compact()
|
|
58
139
|
|
|
59
140
|
`AgentHarness` has no automatic compaction, so the pi bridge drives it directly
|
|
60
141
|
(the legacy low-level `transformContext` / `afterToolCall` hooks and
|
|
@@ -76,7 +157,7 @@ These were Pi-bridge knobs the native path does not consume.
|
|
|
76
157
|
correction. Deprecated programmatic `agent_compaction_*` settings and
|
|
77
158
|
`resolveAgentCompactionPolicy` remain compatibility surfaces.
|
|
78
159
|
|
|
79
|
-
|
|
160
|
+
### 4. Durable Pi session resume: create-on-miss semantics
|
|
80
161
|
|
|
81
162
|
When a run supplies a `providerSessionId` (or the legacy `sessionId` alias) **and**
|
|
82
163
|
durable storage is configured (`piSessionsRoot`), Pi-native now **creates the
|
|
@@ -91,7 +172,7 @@ passed an arbitrary `providerSessionId` to a durable run expecting a hard
|
|
|
91
172
|
The in-memory (non-durable) resume path still fast-fails `session_not_found` on a
|
|
92
173
|
miss.
|
|
93
174
|
|
|
94
|
-
|
|
175
|
+
### 5. Fallback router enforces requested native-subagent capability
|
|
95
176
|
|
|
96
177
|
Pi advertises `supports_native_subagents: false`. The fallback router now infers
|
|
97
178
|
a `supports_native_subagents` requirement when a run passes
|
|
@@ -103,7 +184,7 @@ a `supports_native_subagents` requirement when a run passes
|
|
|
103
184
|
native-subagent runs, ensure at least one entry supports native subagents, or the
|
|
104
185
|
run reports exhausted instead of degrading silently.
|
|
105
186
|
|
|
106
|
-
|
|
187
|
+
### 6. Diagnostics & internal behavior changes (no API change)
|
|
107
188
|
|
|
108
189
|
- **Pi multimodal**: image inputs are delivered to the model as image content
|
|
109
190
|
blocks (internal fix; affects behavior, not the call shape).
|
|
@@ -119,7 +200,7 @@ run reports exhausted instead of degrading silently.
|
|
|
119
200
|
resumed sessions roll back to their pre-turn leaf on host-side (outer-catch)
|
|
120
201
|
failures. These are correctness fixes with no API surface change.
|
|
121
202
|
|
|
122
|
-
|
|
203
|
+
### 7. Sandbox enforcement is now an injectable seam (agent-runtime has zero workspace-package dependencies)
|
|
123
204
|
|
|
124
205
|
`@mono-agent/agent-runtime` does not depend on `@mono-agent/runtime-adapter`. Sandbox
|
|
125
206
|
enforcement (command sandboxing, network-policy checks, and monotonic policy
|
|
@@ -147,7 +228,7 @@ mono-agent hosts — no action needed if you build your runtime through
|
|
|
147
228
|
`@mono-agent/runtime-adapter`, also pass a `sandbox` implementation, or drop
|
|
148
229
|
the policy.
|
|
149
230
|
|
|
150
|
-
|
|
231
|
+
### 8. Typed run options replace the `settings` bag (`toolLimits` / `compaction` / `prompts`)
|
|
151
232
|
|
|
152
233
|
The flat `options.settings` bag is **deprecated** as the way to configure
|
|
153
234
|
tool-output clamps and context compaction. The supported replacements are typed,
|
|
@@ -177,7 +258,7 @@ mapper's fallback window.
|
|
|
177
258
|
**Action:** migrate `settings` → `toolLimits` / `compaction`; until then the shim
|
|
178
259
|
keeps working with one deprecation warning per run.
|
|
179
260
|
|
|
180
|
-
|
|
261
|
+
### 9. New per-run overrides: `sandbox`, `sandboxPolicy`, `prompts`
|
|
181
262
|
|
|
182
263
|
Beyond `toolLimits` / `compaction`, `RuntimeRunOptions` gained:
|
|
183
264
|
|
|
@@ -193,7 +274,7 @@ Beyond `toolLimits` / `compaction`, `RuntimeRunOptions` gained:
|
|
|
193
274
|
(byte-identical default). These are also accepted on `AgentRuntimeHostOptions`
|
|
194
275
|
as the host-level default.
|
|
195
276
|
|
|
196
|
-
|
|
277
|
+
### 10. Pi 0.80 auth: `Models` credential store (`resolvePiApiKey` semantics preserved)
|
|
197
278
|
|
|
198
279
|
Pi 0.80 removed the harness `getApiKeyAndHeaders` hook; request auth now resolves
|
|
199
280
|
through a `Models` collection's `CredentialStore`. The bridge's **per-run
|
|
@@ -208,7 +289,7 @@ now `0.80.6`** (the initial Pi 0.80 migration landed at `0.80.5`, from
|
|
|
208
289
|
`^0.79.1`). Compaction is driven natively (section 3). The `0.80.6` refresh also
|
|
209
290
|
preserves model-native `max` reasoning and Pi's request-wide pricing tiers.
|
|
210
291
|
|
|
211
|
-
|
|
292
|
+
### 11. Exports map: wildcards removed (explicit deep-path map)
|
|
212
293
|
|
|
213
294
|
The package's `./ai/*` and `./agent/*` **wildcard exports were replaced by an
|
|
214
295
|
explicit `exports` map**: 3 barrels (`.`, `./ai`, `./agent`) plus the generated
|
|
@@ -257,64 +338,51 @@ a compatibility subpath.
|
|
|
257
338
|
|
|
258
339
|
## Version
|
|
259
340
|
|
|
260
|
-
This guide describes the published `0.
|
|
341
|
+
This guide describes the published `0.15.x` package contract. Keep
|
|
261
342
|
`@mono-agent/agent-runtime`, `@mono-agent/runtime-adapter`, and other
|
|
262
343
|
`@mono-agent/*` packages on the same lockstep version when upgrading. The paired
|
|
263
344
|
runtime adapter no longer exposes `piReasoningSummary` in its run-options type.
|
|
264
345
|
|
|
265
346
|
---
|
|
266
347
|
|
|
267
|
-
## Appendix —
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
`TOOL_CONTEXT_KEYS`)*; and every `RuntimeResult` field worklab's
|
|
309
|
-
`worker/agent-turn.js` reads exists on the result *(verified: `cancelled`,
|
|
310
|
-
`providerSessionId`, `error`, `failureKind`, `errorDetails`, `diagnostics`,
|
|
311
|
-
`runtimeWarnings`, plus `text`/`usage`/`model`/`effort`/`numTurns`/
|
|
312
|
-
`structuredResult`/`capabilitiesUsed`/`durationMs`/`failoverHistory`;
|
|
313
|
-
`observerSnapshot` is worklab-side, folded from its own metrics observer)*.
|
|
314
|
-
8. **`options.settings` day one.** Works via the deprecated shim (section 8) with
|
|
315
|
-
one `deprecated_settings_option` warning per run; worklab later maps
|
|
316
|
-
`settings` → the typed policy objects in its `core/ai.js`.
|
|
317
|
-
9. **Test layout + no-build consumption.** `src/__tests__` + vitest already match;
|
|
318
|
-
the package is fully consumable from raw `src/` with **no build**
|
|
319
|
-
*(verified: a smoke import of `createRuntime` / `createRouterRuntime` from
|
|
320
|
-
`src/index.js` constructs a runtime with no model call)*.
|
|
348
|
+
## Appendix — Worklab shared-kernel adoption
|
|
349
|
+
|
|
350
|
+
Worklab should consume the published `@mono-agent/agent-runtime` package rather
|
|
351
|
+
than vendor or rename its source. The products remain separate, but provider
|
|
352
|
+
execution has one owner. Apply this downstream checklist when removing
|
|
353
|
+
Worklab's runtime fork:
|
|
354
|
+
|
|
355
|
+
1. **Install the lockstep runtime package.** Keep the `@mono-agent/*` packages a
|
|
356
|
+
Worklab release uses on the same published version. Preserve the shared
|
|
357
|
+
kernel's `GPL-3.0-only` distribution boundary.
|
|
358
|
+
2. **Remove direct provider ownership.** Delete Worklab production imports from
|
|
359
|
+
`@earendil-works/pi-ai`, its separate Pi version constraint, and local copies
|
|
360
|
+
of provider bridge code. Move tests off Pi's faux-provider helpers too; until
|
|
361
|
+
that is complete, isolate the fixture or pin its development-only Pi
|
|
362
|
+
dependency to exact `0.80.6` rather than a floating range. Do not restore the
|
|
363
|
+
removed `pi-sdk.js` subpath.
|
|
364
|
+
3. **Use the public Pi surfaces.** Run models through
|
|
365
|
+
`generatePiNativeResponse` or the runtime registry. Use
|
|
366
|
+
`listPiBuiltinModels`, `getPiBuiltinModel`,
|
|
367
|
+
`reasoningLevelsForPiModel`, `resolvePiOAuthApiKey`, and `loginPiOAuth` for
|
|
368
|
+
catalog and OAuth integration. Those façades keep Pi mutable state and the
|
|
369
|
+
exact `0.80.6` compatibility pin inside the runtime. OAuth login adapters
|
|
370
|
+
must supply `onAuth`, `onDeviceCode`, `onPrompt`, and `onSelect`; the façade
|
|
371
|
+
rejects an incomplete callback contract before starting provider login.
|
|
372
|
+
4. **Inject Claude tests.** Replace package-level mocks of
|
|
373
|
+
`@anthropic-ai/claude-agent-sdk` with
|
|
374
|
+
`RuntimeRunOptions.claudeAgentQuery`. Production calls omit the seam. Expect
|
|
375
|
+
the runtime installation to retain Pi's Anthropic SDK `0.91.1` beside the
|
|
376
|
+
newer Anthropic SDK required by Claude; do not force-deduplicate them.
|
|
377
|
+
5. **Preserve the sandbox boundary.** A direct runtime consumer that supplies
|
|
378
|
+
`sandboxPolicy` must also inject a `RuntimeSandbox`; otherwise the runtime
|
|
379
|
+
intentionally fails closed. With neither a policy nor an implementation,
|
|
380
|
+
passthrough behavior remains unchanged.
|
|
381
|
+
6. **Use supported contracts.** Keep host callbacks within
|
|
382
|
+
`AgentRuntimeHostOptions`, tool state within the exported tool-runtime
|
|
383
|
+
context, and reads within `RuntimeResult`. Replace deprecated
|
|
384
|
+
`options.settings` with typed `toolLimits` and `compaction` objects.
|
|
385
|
+
7. **Verify the installed package.** Run Worklab's provider and worker tests
|
|
386
|
+
against the packed or published package, assert that no production import
|
|
387
|
+
resolves Pi directly, and prove the injected Claude query performs no
|
|
388
|
+
network call.
|
package/README.md
CHANGED
|
@@ -93,6 +93,8 @@ the [architecture guide](https://github.com/robertsreberski/mono-agent/blob/main
|
|
|
93
93
|
| `parseRuntimeModelReference()` | Convert a canonical `claude:`, `codex:`, `opencode:`, or `pi:` string into the object required by `run()` |
|
|
94
94
|
| `listRuntimeBridges()` / `runtimeCapabilities()` | Inspect the five built-in bridge descriptors without loading provider implementations |
|
|
95
95
|
| `createPiOAuthApiKeyResolver()` | Bind a host-owned Pi auth file with refresh-safe writes |
|
|
96
|
+
| `listPiBuiltinModels()` / `getPiBuiltinModel()` | Read cloned snapshots from the runtime-owned, exact-pinned Pi model catalog without importing Pi directly |
|
|
97
|
+
| `resolvePiOAuthApiKey()` / `loginPiOAuth()` | Use the runtime-owned Pi OAuth implementation without importing Pi's mutable provider registry |
|
|
96
98
|
| `createMetricsObserver()` | Aggregate normalized event, token, cache, cost, tool, error, turn, and approval metrics |
|
|
97
99
|
|
|
98
100
|
Most hosts should use `@mono-agent/runtime-adapter` instead of importing deep
|
|
@@ -143,11 +145,14 @@ disposeAllProviderSessions
|
|
|
143
145
|
disposeProviderSession
|
|
144
146
|
executionModeIncompatibilityReason
|
|
145
147
|
generatePiNativeResponse
|
|
148
|
+
getPiBuiltinModel
|
|
146
149
|
inferAllowlistMode
|
|
147
150
|
invalidateProviderSession
|
|
148
151
|
isLikelyContextTermination
|
|
149
152
|
isModelCompatibleWithExecutionMode
|
|
153
|
+
listPiBuiltinModels
|
|
150
154
|
listRuntimeBridges
|
|
155
|
+
loginPiOAuth
|
|
151
156
|
normalizeAllowlistMode
|
|
152
157
|
normalizeClaudeSdkCatalog
|
|
153
158
|
normalizeClaudeSdkModelId
|
|
@@ -158,12 +163,14 @@ parseStoredAllowlist
|
|
|
158
163
|
piNativeRuntimeBridge
|
|
159
164
|
readRuntimeBrand
|
|
160
165
|
readToolRuntime
|
|
166
|
+
reasoningLevelsForPiModel
|
|
161
167
|
refreshProviderSession
|
|
162
168
|
renderResumeSnapshot
|
|
163
169
|
resetToolRuntime
|
|
164
170
|
resolveAgentCompactionPolicy
|
|
165
171
|
resolveAllowlist
|
|
166
172
|
resolveAllowlistMap
|
|
173
|
+
resolvePiOAuthApiKey
|
|
167
174
|
resolveRuntimeBrand
|
|
168
175
|
resolveRuntimeBridge
|
|
169
176
|
runtimeCapabilities
|
|
@@ -310,15 +317,20 @@ disposeAllProviderSessions
|
|
|
310
317
|
disposeProviderSession
|
|
311
318
|
executionModeIncompatibilityReason
|
|
312
319
|
generatePiNativeResponse
|
|
320
|
+
getPiBuiltinModel
|
|
313
321
|
invalidateProviderSession
|
|
314
322
|
isModelCompatibleWithExecutionMode
|
|
323
|
+
listPiBuiltinModels
|
|
315
324
|
listRuntimeBridges
|
|
325
|
+
loginPiOAuth
|
|
316
326
|
normalizeClaudeSdkCatalog
|
|
317
327
|
normalizeClaudeSdkModelId
|
|
318
328
|
normalizeRuntimeModelReference
|
|
319
329
|
parseRuntimeModelReference
|
|
320
330
|
piNativeRuntimeBridge
|
|
331
|
+
reasoningLevelsForPiModel
|
|
321
332
|
refreshProviderSession
|
|
333
|
+
resolvePiOAuthApiKey
|
|
322
334
|
resolveRuntimeBridge
|
|
323
335
|
runtimeCapabilities
|
|
324
336
|
sdkFromModelReference
|
|
@@ -602,6 +614,21 @@ The resolver reads provider credentials from the configured file, delegates toke
|
|
|
602
614
|
refresh to `@earendil-works/pi-ai/oauth`, and writes refreshed credentials back
|
|
603
615
|
with `0600` permissions.
|
|
604
616
|
|
|
617
|
+
Consumers that need lower-level Pi interoperability should still import only
|
|
618
|
+
`@mono-agent/agent-runtime/ai`. `listPiBuiltinModels(providerId)` returns fresh,
|
|
619
|
+
defensively cloned model snapshots; `getPiBuiltinModel(providerId, modelId)`
|
|
620
|
+
returns one cloned snapshot or `undefined`; and
|
|
621
|
+
`reasoningLevelsForPiModel(model)` translates a Pi model into mono-agent's
|
|
622
|
+
reasoning vocabulary, including `none` rather than Pi's `off`.
|
|
623
|
+
`resolvePiOAuthApiKey(providerId, credentials)` refreshes a caller-owned
|
|
624
|
+
credential snapshot and returns `{ apiKey, newCredentials }` or `null`, while
|
|
625
|
+
`loginPiOAuth(providerId, callbacks)` runs the selected supported login flow.
|
|
626
|
+
Login callers must implement Pi's four required interaction callbacks:
|
|
627
|
+
`onAuth`, `onDeviceCode`, `onPrompt`, and `onSelect`; optional progress,
|
|
628
|
+
manual-code, and abort callbacks pass through unchanged.
|
|
629
|
+
These functions deliberately do not expose Pi's mutable model collections or
|
|
630
|
+
OAuth-provider registry.
|
|
631
|
+
|
|
605
632
|
Returns:
|
|
606
633
|
|
|
607
634
|
- `run(systemPrompt, options)` — async, runs one agent turn against the chosen backend.
|
|
@@ -628,8 +655,9 @@ Per-call options (a non-exhaustive selection):
|
|
|
628
655
|
| `maxTurns` | `number` | Hard cap on agent turns. |
|
|
629
656
|
| `outputSchema` | `JSONSchema` | Requests structured JSON on capable bridges; see “Structured output” below for bridge-specific return behavior. |
|
|
630
657
|
| `abortSignal` | `AbortSignal` | Cancel the run. |
|
|
631
|
-
| `liveInput` | `AsyncIterable<{ body: string; id?: string; receivedAt?: string; acknowledge?: () => void; reject?: (error?: unknown) => void }>` | Stream of in-flight user messages for steering on capable bridges. A bridge acknowledges only after its native steering boundary accepts the message; per-attempt rejection permits router replay. |
|
|
632
|
-
| `
|
|
658
|
+
| `liveInput` | `AsyncIterable<{ body: string; id?: string; receivedAt?: string; acknowledge?: () => void; reject?: (error?: unknown) => void }>` | Stream of in-flight user messages for steering on capable bridges. A bridge acknowledges only after its native steering boundary accepts the message; per-attempt rejection permits router replay. Acknowledgement emits metadata-only `live_input_applied` telemetry. |
|
|
659
|
+
| `claudeAgentQuery` | `typeof query` | Advanced programmatic/test seam for the Claude SDK bridge. When omitted, the bridge uses the runtime's pinned Claude Agent SDK. This is not a config field or telemetry value. |
|
|
660
|
+
| `onEvent` | `(event) => void` | Fired for every runtime event (assistant text, tool calls/results, applied live input, runtime warnings, structured output). |
|
|
633
661
|
| `runId` | `string` | Tag this run for downstream callbacks (e.g. `onCompactionRecorded`). |
|
|
634
662
|
| `providerSessionId` | `string` | Resume a prior provider session. |
|
|
635
663
|
| `runArtifactDir` | `string` | Used by some providers as the Playwright MCP filename target. |
|
|
@@ -639,6 +667,13 @@ Per-call options (a non-exhaustive selection):
|
|
|
639
667
|
Live input is native on the Claude SDK, Codex app-server, and Pi bridges. The
|
|
640
668
|
one-shot Claude CLI and direct OpenCode bridges advertise it as unsupported so
|
|
641
669
|
routers skip them when a direct runtime call requires steering.
|
|
670
|
+
After a native bridge invokes `acknowledge()`, the runtime emits exactly one
|
|
671
|
+
`{ type: "live_input_applied", inputId, receivedAt? }` event for that logical
|
|
672
|
+
run. It deliberately omits the guidance body. A fallback router reuses the same
|
|
673
|
+
instrumented input stream, so replay or duplicate acknowledgement cannot emit a
|
|
674
|
+
second applied event. A throwing host `acknowledge` or `reject` callback cannot
|
|
675
|
+
change the native steering outcome; the Codex bridge reports it as a bounded
|
|
676
|
+
`live_input_callback_failed` runtime warning.
|
|
642
677
|
|
|
643
678
|
Returns:
|
|
644
679
|
|
|
@@ -707,6 +742,13 @@ The agent kernel's managed tools are `Read`, `Write`, `Edit`, `Glob`, `Grep`, `B
|
|
|
707
742
|
|
|
708
743
|
`NodeRepl` uses Node's default `node:repl` evaluator, so variables, `_`, `_error`, and loaded modules persist across calls in the same run. It supports multiline input and top-level `await`, resolves workspace-installed packages, and is closed with the run. Its child is prepared through the same sandbox seam as `Bash`; abort, the fixed 120-second timeout, child exit, or hard output overflow resets the session. It deliberately has no session ids, persistent history, terminal commands, or package-install surface.
|
|
709
744
|
|
|
745
|
+
Pi runs with selected skills also expose `ReadSkill`. It returns the complete
|
|
746
|
+
skill instructions by default, including content beyond the former
|
|
747
|
+
12,000-character boundary. Programmatic callers of
|
|
748
|
+
`formatSkillBodyWithPathNote()` may pass a positive `maxChars` only when
|
|
749
|
+
truncation is explicitly desired; omitting it is not a separate hidden limit.
|
|
750
|
+
The standard 256 KiB tool-payload guard still applies to oversized tool results.
|
|
751
|
+
|
|
710
752
|
Override or extend the tool surface by passing `mcpServers` for MCP-backed tools.
|
|
711
753
|
|
|
712
754
|
### Structured output
|
|
@@ -917,6 +959,19 @@ dependencies are `@anthropic-ai/claude-agent-sdk`, `@anthropic-ai/sdk`,
|
|
|
917
959
|
`@modelcontextprotocol/sdk`, `@opencode-ai/sdk`, `@vscode/ripgrep`,
|
|
918
960
|
`cross-spawn`, and `zod`.
|
|
919
961
|
|
|
962
|
+
The runtime owns and exact-pins the compatible Pi pair at `0.80.6`; consumers
|
|
963
|
+
use the runtime's Pi façade rather than coordinating a second direct
|
|
964
|
+
`@earendil-works/pi-ai` dependency. Do not attempt to flatten the resulting
|
|
965
|
+
Anthropic dependency tree: Pi AI pins `@anthropic-ai/sdk@0.91.1`, while the
|
|
966
|
+
Claude Agent SDK requires `@anthropic-ai/sdk>=0.93.0` and the runtime supplies
|
|
967
|
+
its compatible newer SDK. Two isolated Anthropic SDK versions are therefore
|
|
968
|
+
expected. `RuntimeRunOptions.claudeAgentQuery` provides deterministic Claude
|
|
969
|
+
tests without mocking package resolution or sending real SDK traffic.
|
|
970
|
+
If a downstream test suite still needs Pi's faux-provider helpers, isolate that
|
|
971
|
+
fixture or keep its development-only Pi dependency on the runtime's exact
|
|
972
|
+
`0.80.6` version until the fixture is removed; a broad host range can otherwise
|
|
973
|
+
float Pi Agent Core's own upstream dependency independently of this façade.
|
|
974
|
+
|
|
920
975
|
Sandbox enforcement is an injectable `RuntimeSandbox` seam.
|
|
921
976
|
`@mono-agent/runtime-adapter` supplies the mono-agent implementation; a direct
|
|
922
977
|
consumer that configures a sandbox policy must inject an implementation or the
|
package/package.json
CHANGED
package/src/agent/compaction.js
CHANGED
|
@@ -22,8 +22,6 @@
|
|
|
22
22
|
* @property {number} summaryMaxTokens
|
|
23
23
|
* @property {boolean} fixedOverheadEnabled
|
|
24
24
|
* @property {number} compactionMinSavingsTokens
|
|
25
|
-
* @property {number} toolPayloadCompactionTriggerChars
|
|
26
|
-
* @property {number} toolPruneTriggerTokens
|
|
27
25
|
* @property {number} toolTextLimitChars
|
|
28
26
|
* @property {number} bashOutputLimitChars
|
|
29
27
|
* @property {number} mcpTextLimitChars
|
|
@@ -36,8 +34,6 @@
|
|
|
36
34
|
|
|
37
35
|
const DEFAULT_CONTEXT_WINDOW = 128000;
|
|
38
36
|
const DEFAULT_TRIGGER_RATIO = 0.70;
|
|
39
|
-
const DEFAULT_TOOL_PAYLOAD_COMPACTION_TRIGGER_CHARS = 0;
|
|
40
|
-
const DEFAULT_TOOL_PRUNE_TRIGGER_TOKENS = 40000;
|
|
41
37
|
// intelligence-ramp Phase 3: lifted from 16K/20K/12K. Mid-task tool reads
|
|
42
38
|
// (large file edits, long bash output, deep MCP results) were being silently
|
|
43
39
|
// clipped before the agent could reason about them. The 256KB hard ceiling
|
|
@@ -134,13 +130,6 @@ export function resolveAgentCompactionPolicy(settings = {}, model = {}) {
|
|
|
134
130
|
0,
|
|
135
131
|
500000,
|
|
136
132
|
),
|
|
137
|
-
toolPayloadCompactionTriggerChars: clampInteger(
|
|
138
|
-
settings.agent_tool_payload_compaction_trigger_chars,
|
|
139
|
-
DEFAULT_TOOL_PAYLOAD_COMPACTION_TRIGGER_CHARS,
|
|
140
|
-
0,
|
|
141
|
-
10 * 1024 * 1024,
|
|
142
|
-
),
|
|
143
|
-
toolPruneTriggerTokens: clampInteger(settings.agent_tool_prune_trigger_tokens, DEFAULT_TOOL_PRUNE_TRIGGER_TOKENS, 0, 500000),
|
|
144
133
|
toolTextLimitChars: clampInteger(settings.agent_tool_text_limit_chars, DEFAULT_TOOL_TEXT_LIMIT_CHARS, 1000, 200000),
|
|
145
134
|
bashOutputLimitChars: clampInteger(settings.agent_bash_output_limit_chars, DEFAULT_BASH_OUTPUT_LIMIT_CHARS, 1000, 200000),
|
|
146
135
|
mcpTextLimitChars: clampInteger(settings.agent_mcp_text_limit_chars, DEFAULT_MCP_TEXT_LIMIT_CHARS, 1000, 200000),
|
|
@@ -35,6 +35,9 @@ export function buildSkillPathNote({ assetsPath, skillsRoot } = {}) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
+
* Render a complete skill body plus its path note. Omitting `maxChars` returns
|
|
39
|
+
* the full text; pass a positive `maxChars` only when explicit truncation is
|
|
40
|
+
* required by the caller.
|
|
38
41
|
* @param {{body?: string, assetsPath?: string, skillsRoot?: any, maxChars?: number}} [options]
|
|
39
42
|
*/
|
|
40
43
|
export function formatSkillBodyWithPathNote({ body, assetsPath, skillsRoot, maxChars } = {}) {
|
|
@@ -42,7 +45,8 @@ export function formatSkillBodyWithPathNote({ body, assetsPath, skillsRoot, maxC
|
|
|
42
45
|
buildSkillPathNote({ assetsPath, skillsRoot }),
|
|
43
46
|
String(body || "").trim(),
|
|
44
47
|
].filter(Boolean).join("\n\n");
|
|
45
|
-
|
|
48
|
+
const limit = Number(maxChars);
|
|
49
|
+
return Number.isFinite(limit) && limit > 0 ? text.slice(0, Math.floor(limit)) : text;
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
export function buildSkillIndex(skills) {
|
package/src/ai/index.js
CHANGED
|
@@ -12,6 +12,13 @@ export {
|
|
|
12
12
|
} from "./runtime/sessions.js";
|
|
13
13
|
export { createMetricsObserver, createObserverHub } from "./observer.js";
|
|
14
14
|
export { generatePiNativeResponse, piNativeRuntimeBridge } from "./providers/pi-native.js";
|
|
15
|
+
export {
|
|
16
|
+
getPiBuiltinModel,
|
|
17
|
+
listPiBuiltinModels,
|
|
18
|
+
loginPiOAuth,
|
|
19
|
+
reasoningLevelsForPiModel,
|
|
20
|
+
resolvePiOAuthApiKey,
|
|
21
|
+
} from "./pi-interop.js";
|
|
15
22
|
export {
|
|
16
23
|
CLAUDE_SDK_CATALOG_VERSION,
|
|
17
24
|
createClaudeSdkDiscoveryIsolation,
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// Runtime-owned interoperability facade for Pi's built-in model and OAuth
|
|
2
|
+
// surfaces. Consumers should use these functions instead of importing pi-ai
|
|
3
|
+
// directly so the runtime's known-good Pi version remains authoritative.
|
|
4
|
+
|
|
5
|
+
import { getBuiltinModel, getBuiltinModels } from "@earendil-works/pi-ai/providers/all";
|
|
6
|
+
import { getOAuthApiKey, getOAuthProvider } from "@earendil-works/pi-ai/oauth";
|
|
7
|
+
import { reasoningLevelsForPiModel as resolveReasoningLevels } from "./providers/pi-models.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {{
|
|
11
|
+
* id: string,
|
|
12
|
+
* name: string,
|
|
13
|
+
* api: string,
|
|
14
|
+
* provider: string,
|
|
15
|
+
* baseUrl: string,
|
|
16
|
+
* reasoning: boolean,
|
|
17
|
+
* input: Array<"text"|"image">,
|
|
18
|
+
* cost: {
|
|
19
|
+
* input: number,
|
|
20
|
+
* output: number,
|
|
21
|
+
* cacheRead: number,
|
|
22
|
+
* cacheWrite: number,
|
|
23
|
+
* tiers?: Array<{
|
|
24
|
+
* inputTokensAbove: number,
|
|
25
|
+
* input: number,
|
|
26
|
+
* output: number,
|
|
27
|
+
* cacheRead: number,
|
|
28
|
+
* cacheWrite: number
|
|
29
|
+
* }>
|
|
30
|
+
* },
|
|
31
|
+
* contextWindow: number,
|
|
32
|
+
* maxTokens: number,
|
|
33
|
+
* thinkingLevelMap?: Object<string, string|null>,
|
|
34
|
+
* compat?: Object<string, *>,
|
|
35
|
+
* headers?: Object<string, string>,
|
|
36
|
+
* [key: string]: *
|
|
37
|
+
* }} PiBuiltinModelSnapshot
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @typedef {"none"|"minimal"|"low"|"medium"|"high"|"xhigh"|"max"} PiReasoningLevel
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @typedef {{
|
|
46
|
+
* refresh: string,
|
|
47
|
+
* access: string,
|
|
48
|
+
* expires: number,
|
|
49
|
+
* [key: string]: *
|
|
50
|
+
* }} PiOAuthCredentialsSnapshot
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @typedef {Object} PiOAuthLoginCallbacks
|
|
55
|
+
* @property {(info: {url: string, instructions?: string}) => void} onAuth
|
|
56
|
+
* @property {(info: {userCode: string, verificationUri: string, intervalSeconds?: number, expiresInSeconds?: number}) => void} onDeviceCode
|
|
57
|
+
* @property {(prompt: {message: string, placeholder?: string, allowEmpty?: boolean}) => Promise<string>} onPrompt
|
|
58
|
+
* @property {(message: string) => void} [onProgress]
|
|
59
|
+
* @property {() => Promise<string>} [onManualCodeInput]
|
|
60
|
+
* @property {(prompt: {message: string, options: Array<{id: string, label: string}>}) => Promise<string|undefined>} onSelect
|
|
61
|
+
* @property {AbortSignal} [signal]
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Clone provider-owned data before it crosses the public runtime boundary.
|
|
66
|
+
* Pi's built-in models and OAuth credentials are structured data on the
|
|
67
|
+
* supported version, and the package requires a Node release with
|
|
68
|
+
* `structuredClone`.
|
|
69
|
+
*
|
|
70
|
+
* @template T
|
|
71
|
+
* @param {T} value
|
|
72
|
+
* @returns {T}
|
|
73
|
+
*/
|
|
74
|
+
function cloneInteropValue(value) {
|
|
75
|
+
return structuredClone(value);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* List defensive snapshots of Pi's built-in models for one provider.
|
|
80
|
+
*
|
|
81
|
+
* @param {string} providerId
|
|
82
|
+
* @returns {PiBuiltinModelSnapshot[]}
|
|
83
|
+
*/
|
|
84
|
+
export function listPiBuiltinModels(providerId) {
|
|
85
|
+
const models = getBuiltinModels(/** @type {any} */ (providerId));
|
|
86
|
+
return /** @type {PiBuiltinModelSnapshot[]} */ (cloneInteropValue(models));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Read a defensive snapshot of one Pi built-in model.
|
|
91
|
+
*
|
|
92
|
+
* @param {string} providerId
|
|
93
|
+
* @param {string} modelId
|
|
94
|
+
* @returns {PiBuiltinModelSnapshot|undefined}
|
|
95
|
+
*/
|
|
96
|
+
export function getPiBuiltinModel(providerId, modelId) {
|
|
97
|
+
const model = getBuiltinModel(
|
|
98
|
+
/** @type {any} */ (providerId),
|
|
99
|
+
/** @type {any} */ (modelId),
|
|
100
|
+
);
|
|
101
|
+
return model === undefined
|
|
102
|
+
? undefined
|
|
103
|
+
: /** @type {PiBuiltinModelSnapshot} */ (cloneInteropValue(model));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Translate Pi's model-native thinking levels to mono-agent effort spelling.
|
|
108
|
+
*
|
|
109
|
+
* @param {PiBuiltinModelSnapshot} model
|
|
110
|
+
* @returns {PiReasoningLevel[]}
|
|
111
|
+
*/
|
|
112
|
+
export function reasoningLevelsForPiModel(model) {
|
|
113
|
+
return /** @type {PiReasoningLevel[]} */ (resolveReasoningLevels(model));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Resolve an OAuth-backed API key without allowing Pi to mutate the caller's
|
|
118
|
+
* credential record or returning Pi-owned credential objects.
|
|
119
|
+
*
|
|
120
|
+
* @param {string} providerId
|
|
121
|
+
* @param {Object<string, PiOAuthCredentialsSnapshot>} credentials
|
|
122
|
+
* @returns {Promise<{apiKey: string, newCredentials: PiOAuthCredentialsSnapshot}|null>}
|
|
123
|
+
*/
|
|
124
|
+
export async function resolvePiOAuthApiKey(providerId, credentials) {
|
|
125
|
+
const result = await getOAuthApiKey(
|
|
126
|
+
providerId,
|
|
127
|
+
/** @type {any} */ (cloneInteropValue(credentials)),
|
|
128
|
+
);
|
|
129
|
+
if (!result) return null;
|
|
130
|
+
return {
|
|
131
|
+
apiKey: result.apiKey,
|
|
132
|
+
newCredentials: cloneInteropValue(result.newCredentials),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Run a supported Pi OAuth login flow without exposing Pi's mutable provider
|
|
138
|
+
* registry or provider instances.
|
|
139
|
+
*
|
|
140
|
+
* @param {string} providerId
|
|
141
|
+
* @param {PiOAuthLoginCallbacks} callbacks
|
|
142
|
+
* @returns {Promise<PiOAuthCredentialsSnapshot>}
|
|
143
|
+
*/
|
|
144
|
+
export async function loginPiOAuth(providerId, callbacks) {
|
|
145
|
+
const provider = getOAuthProvider(providerId);
|
|
146
|
+
if (!provider || typeof provider.login !== "function") {
|
|
147
|
+
throw new Error(`Pi OAuth provider is unavailable: ${providerId}`);
|
|
148
|
+
}
|
|
149
|
+
for (const callbackName of ["onAuth", "onDeviceCode", "onPrompt", "onSelect"]) {
|
|
150
|
+
if (typeof callbacks?.[callbackName] !== "function") {
|
|
151
|
+
throw new TypeError(`loginPiOAuth requires callbacks.${callbackName}()`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const credentials = await provider.login(/** @type {any} */ ({ ...callbacks }));
|
|
155
|
+
return cloneInteropValue(credentials);
|
|
156
|
+
}
|
|
@@ -748,6 +748,7 @@ export async function generateClaudeResponse(systemPrompt, options) {
|
|
|
748
748
|
const prompt = options.liveInput
|
|
749
749
|
? livePromptMessages({ initialPrompt: promptString, liveInput: options.liveInput, sessionId: reusableProviderSessionId || randomUUID(), prompts: options.prompts })
|
|
750
750
|
: promptString;
|
|
751
|
+
const claudeAgentQuery = options.claudeAgentQuery ?? query;
|
|
751
752
|
const providerRequestStartedAt = Date.now();
|
|
752
753
|
emitEvent({
|
|
753
754
|
type: "provider_request_started",
|
|
@@ -805,7 +806,7 @@ export async function generateClaudeResponse(systemPrompt, options) {
|
|
|
805
806
|
}
|
|
806
807
|
|
|
807
808
|
try {
|
|
808
|
-
stream =
|
|
809
|
+
stream = claudeAgentQuery({ prompt: /** @type {any} */ (prompt), options: queryOptions });
|
|
809
810
|
for await (const event of stream) {
|
|
810
811
|
const nextSessionId = sessionIdFromEvent(event);
|
|
811
812
|
if (nextSessionId) providerSessionId = nextSessionId;
|
|
@@ -1143,7 +1143,9 @@ export async function generateCodexAppResponse(systemPrompt, options = {}) {
|
|
|
1143
1143
|
let serverRequestViolation = null;
|
|
1144
1144
|
let resolveTurn;
|
|
1145
1145
|
let resolveTurnReady;
|
|
1146
|
+
let resolveLiveInputStop;
|
|
1146
1147
|
let turnReadyResolved = false;
|
|
1148
|
+
let liveInputStopped = false;
|
|
1147
1149
|
const fileChangeSnapshots = new Map();
|
|
1148
1150
|
const codexItemContext = {
|
|
1149
1151
|
fileChangePayload: (raw) => createFileChangePayload(raw, {
|
|
@@ -1153,6 +1155,13 @@ export async function generateCodexAppResponse(systemPrompt, options = {}) {
|
|
|
1153
1155
|
};
|
|
1154
1156
|
const turnDone = new Promise((resolve) => { resolveTurn = resolve; });
|
|
1155
1157
|
const turnReady = new Promise((resolve) => { resolveTurnReady = resolve; });
|
|
1158
|
+
const liveInputStop = new Promise((resolve) => { resolveLiveInputStop = resolve; });
|
|
1159
|
+
|
|
1160
|
+
function stopLiveInput() {
|
|
1161
|
+
if (liveInputStopped) return;
|
|
1162
|
+
liveInputStopped = true;
|
|
1163
|
+
resolveLiveInputStop();
|
|
1164
|
+
}
|
|
1156
1165
|
|
|
1157
1166
|
function setActiveTurnId(turnId, { steerReady = false } = {}) {
|
|
1158
1167
|
activeTurnId = turnId || activeTurnId;
|
|
@@ -1175,6 +1184,21 @@ export async function generateCodexAppResponse(systemPrompt, options = {}) {
|
|
|
1175
1184
|
options.onEvent?.(safeEvent);
|
|
1176
1185
|
}
|
|
1177
1186
|
|
|
1187
|
+
function invokeLiveInputCallback(message, callbackName, ...args) {
|
|
1188
|
+
const callback = message?.[callbackName];
|
|
1189
|
+
if (typeof callback !== "function") return;
|
|
1190
|
+
try {
|
|
1191
|
+
callback.apply(message, args);
|
|
1192
|
+
} catch (err) {
|
|
1193
|
+
const detail = safeDiagnostic(err, 512);
|
|
1194
|
+
emitEvent({
|
|
1195
|
+
type: "runtime_warning",
|
|
1196
|
+
warning_kind: "live_input_callback_failed",
|
|
1197
|
+
message: safeDiagnostic(`Live-input ${callbackName} callback failed: ${detail}`, 1_024),
|
|
1198
|
+
});
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1178
1202
|
const compactionTurnKey = (params = {}) => `${params.threadId || threadId || "thread"}:${params.turnId || activeTurnId || "turn"}`;
|
|
1179
1203
|
|
|
1180
1204
|
/**
|
|
@@ -1269,6 +1293,7 @@ export async function generateCodexAppResponse(systemPrompt, options = {}) {
|
|
|
1269
1293
|
client?.request("turn/interrupt", { threadId, turnId: activeTurnId }).catch(() => {});
|
|
1270
1294
|
}
|
|
1271
1295
|
turnCompleted = true;
|
|
1296
|
+
stopLiveInput();
|
|
1272
1297
|
resolveTurn({ id: activeTurnId, status: "interrupted" });
|
|
1273
1298
|
}
|
|
1274
1299
|
|
|
@@ -1293,6 +1318,7 @@ export async function generateCodexAppResponse(systemPrompt, options = {}) {
|
|
|
1293
1318
|
message: errorMessage,
|
|
1294
1319
|
});
|
|
1295
1320
|
turnCompleted = true;
|
|
1321
|
+
stopLiveInput();
|
|
1296
1322
|
resolveTurn({ id: activeTurnId, status: "interrupted" });
|
|
1297
1323
|
}
|
|
1298
1324
|
|
|
@@ -1323,6 +1349,7 @@ export async function generateCodexAppResponse(systemPrompt, options = {}) {
|
|
|
1323
1349
|
if (method === "turn/completed") {
|
|
1324
1350
|
setActiveTurnId(params.turn?.id);
|
|
1325
1351
|
turnCompleted = true;
|
|
1352
|
+
stopLiveInput();
|
|
1326
1353
|
if (params.turn?.status === "failed") {
|
|
1327
1354
|
errorMessage = safeDiagnostic(params.turn?.error?.message || params.turn?.error || "Codex turn failed");
|
|
1328
1355
|
failureKind = "provider_unavailable";
|
|
@@ -1482,6 +1509,7 @@ export async function generateCodexAppResponse(systemPrompt, options = {}) {
|
|
|
1482
1509
|
|
|
1483
1510
|
const abortHandler = () => {
|
|
1484
1511
|
abortRequested = true;
|
|
1512
|
+
stopLiveInput();
|
|
1485
1513
|
if (threadId && activeTurnId && !interruptSent) {
|
|
1486
1514
|
interruptSent = true;
|
|
1487
1515
|
client?.request("turn/interrupt", { threadId, turnId: activeTurnId }).catch(() => {});
|
|
@@ -1495,20 +1523,19 @@ export async function generateCodexAppResponse(systemPrompt, options = {}) {
|
|
|
1495
1523
|
if (!options.liveInput) return;
|
|
1496
1524
|
const iterator = options.liveInput[Symbol.asyncIterator]();
|
|
1497
1525
|
try {
|
|
1498
|
-
while (!turnCompleted) {
|
|
1526
|
+
while (!turnCompleted && !liveInputStopped) {
|
|
1499
1527
|
const next = await Promise.race([
|
|
1500
1528
|
iterator.next(),
|
|
1501
|
-
|
|
1529
|
+
liveInputStop.then(() => ({ done: true, value: undefined })),
|
|
1502
1530
|
]);
|
|
1503
|
-
if (next.done || turnCompleted) break;
|
|
1531
|
+
if (next.done || turnCompleted || liveInputStopped) break;
|
|
1504
1532
|
const message = next.value;
|
|
1505
1533
|
if (!threadId || !activeTurnId || !turnReadyResolved) {
|
|
1506
1534
|
await Promise.race([
|
|
1507
1535
|
turnReady,
|
|
1508
|
-
|
|
1509
|
-
client.closed.then((err) => { throw err; }),
|
|
1536
|
+
liveInputStop,
|
|
1510
1537
|
]);
|
|
1511
|
-
if (turnCompleted || !turnReadyResolved) break;
|
|
1538
|
+
if (turnCompleted || liveInputStopped || !turnReadyResolved) break;
|
|
1512
1539
|
}
|
|
1513
1540
|
const input = userTextInput(formatLiveInputGuidance(message.body, options.prompts));
|
|
1514
1541
|
try {
|
|
@@ -1518,16 +1545,15 @@ export async function generateCodexAppResponse(systemPrompt, options = {}) {
|
|
|
1518
1545
|
input,
|
|
1519
1546
|
});
|
|
1520
1547
|
activeTurnId = response?.turnId || activeTurnId;
|
|
1521
|
-
message
|
|
1548
|
+
invokeLiveInputCallback(message, "acknowledge");
|
|
1522
1549
|
} catch (err) {
|
|
1523
1550
|
const providerError = err?.responseError;
|
|
1524
1551
|
if (isNoActiveTurnToSteer(providerError || err)) {
|
|
1525
1552
|
await Promise.race([
|
|
1526
1553
|
turnReady,
|
|
1527
|
-
|
|
1528
|
-
client.closed.then((closedErr) => { throw closedErr; }),
|
|
1554
|
+
liveInputStop,
|
|
1529
1555
|
]);
|
|
1530
|
-
if (turnCompleted) break;
|
|
1556
|
+
if (turnCompleted || liveInputStopped) break;
|
|
1531
1557
|
try {
|
|
1532
1558
|
const response = await client.request("turn/steer", {
|
|
1533
1559
|
threadId,
|
|
@@ -1535,10 +1561,10 @@ export async function generateCodexAppResponse(systemPrompt, options = {}) {
|
|
|
1535
1561
|
input,
|
|
1536
1562
|
});
|
|
1537
1563
|
activeTurnId = response?.turnId || activeTurnId;
|
|
1538
|
-
message
|
|
1564
|
+
invokeLiveInputCallback(message, "acknowledge");
|
|
1539
1565
|
continue;
|
|
1540
1566
|
} catch (retryErr) {
|
|
1541
|
-
message
|
|
1567
|
+
invokeLiveInputCallback(message, "reject", retryErr);
|
|
1542
1568
|
const retryProviderError = retryErr?.responseError
|
|
1543
1569
|
? safeResponseError(retryErr.responseError)
|
|
1544
1570
|
: null;
|
|
@@ -1552,7 +1578,7 @@ export async function generateCodexAppResponse(systemPrompt, options = {}) {
|
|
|
1552
1578
|
break;
|
|
1553
1579
|
}
|
|
1554
1580
|
}
|
|
1555
|
-
message
|
|
1581
|
+
invokeLiveInputCallback(message, "reject", err);
|
|
1556
1582
|
emitEvent({
|
|
1557
1583
|
type: "runtime_warning",
|
|
1558
1584
|
warning_kind: isActiveTurnNotSteerable(providerError) ? "active_turn_not_steerable" : "live_input_rejected",
|
|
@@ -1789,6 +1815,7 @@ export async function generateCodexAppResponse(systemPrompt, options = {}) {
|
|
|
1789
1815
|
closedSignal.then((err) => {
|
|
1790
1816
|
if (!turnCompleted) {
|
|
1791
1817
|
prematureClose = true;
|
|
1818
|
+
stopLiveInput();
|
|
1792
1819
|
throw err || new Error("codex app-server closed");
|
|
1793
1820
|
}
|
|
1794
1821
|
return null;
|
|
@@ -1803,6 +1830,7 @@ export async function generateCodexAppResponse(systemPrompt, options = {}) {
|
|
|
1803
1830
|
}
|
|
1804
1831
|
} finally {
|
|
1805
1832
|
abortRaceCleanup();
|
|
1833
|
+
stopLiveInput();
|
|
1806
1834
|
}
|
|
1807
1835
|
turnCompleted = true;
|
|
1808
1836
|
await steerTask;
|
|
@@ -1923,6 +1951,7 @@ export async function generateCodexAppResponse(systemPrompt, options = {}) {
|
|
|
1923
1951
|
}),
|
|
1924
1952
|
};
|
|
1925
1953
|
} finally {
|
|
1954
|
+
stopLiveInput();
|
|
1926
1955
|
if (activeCompactions.size > 0) {
|
|
1927
1956
|
const cancelled = !!options.abortSignal?.aborted;
|
|
1928
1957
|
finalizeOpenCompactions(
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Metadata-only live-input acknowledgement instrumentation.
|
|
2
|
+
//
|
|
3
|
+
// Provider bridges already call message.acknowledge() only after their native
|
|
4
|
+
// steering boundary accepts guidance. Wrapping that callback here creates one
|
|
5
|
+
// adapter-neutral `live_input_applied` event without copying the guidance body
|
|
6
|
+
// into runtime telemetry. A wrapper owns one logical-run dedupe set and is
|
|
7
|
+
// intentionally reused by the fallback router across provider attempts.
|
|
8
|
+
|
|
9
|
+
// @ts-check
|
|
10
|
+
|
|
11
|
+
const LIVE_INPUT_APPLIED_INSTRUMENTED = Symbol("mono-agent.live-input-applied-instrumented");
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {{body: string, id?: string, receivedAt?: string, acknowledge?: () => void, reject?: (reason?: unknown) => void}} RuntimeLiveInputMessage
|
|
15
|
+
* @typedef {{type: "live_input_applied", inputId: string, receivedAt?: string}} LiveInputAppliedEvent
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {AsyncIterable<RuntimeLiveInputMessage>|undefined} liveInput
|
|
20
|
+
* @param {(event: LiveInputAppliedEvent) => void} onApplied
|
|
21
|
+
* @returns {AsyncIterable<RuntimeLiveInputMessage>|undefined}
|
|
22
|
+
*/
|
|
23
|
+
export function instrumentLiveInputAppliedEvents(liveInput, onApplied) {
|
|
24
|
+
if (liveInput === undefined || isInstrumented(liveInput)) return liveInput;
|
|
25
|
+
|
|
26
|
+
const appliedInputIds = new Set();
|
|
27
|
+
const instrumented = {
|
|
28
|
+
[LIVE_INPUT_APPLIED_INSTRUMENTED]: true,
|
|
29
|
+
[Symbol.asyncIterator]() {
|
|
30
|
+
const iterator = liveInput[Symbol.asyncIterator]();
|
|
31
|
+
let ordinal = 0;
|
|
32
|
+
return {
|
|
33
|
+
async next() {
|
|
34
|
+
const next = await iterator.next();
|
|
35
|
+
if (next.done === true) return next;
|
|
36
|
+
ordinal += 1;
|
|
37
|
+
const message = next.value;
|
|
38
|
+
const inputId = stableInputId(message?.id, ordinal);
|
|
39
|
+
const receivedAt = typeof message?.receivedAt === "string" && message.receivedAt.length > 0
|
|
40
|
+
? message.receivedAt
|
|
41
|
+
: undefined;
|
|
42
|
+
const acknowledge = typeof message?.acknowledge === "function"
|
|
43
|
+
? message.acknowledge.bind(message)
|
|
44
|
+
: undefined;
|
|
45
|
+
return {
|
|
46
|
+
done: false,
|
|
47
|
+
value: {
|
|
48
|
+
...message,
|
|
49
|
+
acknowledge: () => {
|
|
50
|
+
acknowledge?.();
|
|
51
|
+
if (appliedInputIds.has(inputId)) return;
|
|
52
|
+
appliedInputIds.add(inputId);
|
|
53
|
+
try {
|
|
54
|
+
onApplied({
|
|
55
|
+
type: "live_input_applied",
|
|
56
|
+
inputId,
|
|
57
|
+
...(receivedAt === undefined ? {} : { receivedAt }),
|
|
58
|
+
});
|
|
59
|
+
} catch {
|
|
60
|
+
// Telemetry must never turn accepted guidance into a provider
|
|
61
|
+
// failure after the native steering call already succeeded.
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
async return(value) {
|
|
68
|
+
return typeof iterator.return === "function"
|
|
69
|
+
? iterator.return(value)
|
|
70
|
+
: { done: true, value };
|
|
71
|
+
},
|
|
72
|
+
async throw(error) {
|
|
73
|
+
if (typeof iterator.throw === "function") return iterator.throw(error);
|
|
74
|
+
throw error;
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
return /** @type {AsyncIterable<RuntimeLiveInputMessage>} */ (instrumented);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** @param {unknown} value */
|
|
83
|
+
function isInstrumented(value) {
|
|
84
|
+
return typeof value === "object"
|
|
85
|
+
&& value !== null
|
|
86
|
+
&& value[LIVE_INPUT_APPLIED_INSTRUMENTED] === true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** @param {unknown} value @param {number} ordinal */
|
|
90
|
+
function stableInputId(value, ordinal) {
|
|
91
|
+
return typeof value === "string" && value.trim().length > 0
|
|
92
|
+
? value
|
|
93
|
+
: `anonymous:${ordinal}`;
|
|
94
|
+
}
|
package/src/ai/runtime/router.js
CHANGED
|
@@ -41,6 +41,8 @@ import { runtimeCapabilities } from "./capabilities.js";
|
|
|
41
41
|
import { buildTranscriptTailSnapshot, renderResumeSnapshot } from "../../agent/transcript.js";
|
|
42
42
|
import { passthroughSandbox } from "../../agent/sandbox-seam.js";
|
|
43
43
|
import { resolveRuntimeBrand } from "../../runtime-brand.js";
|
|
44
|
+
import { createObserverHub } from "../observer.js";
|
|
45
|
+
import { instrumentLiveInputAppliedEvents } from "./live-input-events.js";
|
|
44
46
|
|
|
45
47
|
/**
|
|
46
48
|
* @typedef {import('../types.js').RuntimeModelRef} RuntimeModelRef
|
|
@@ -127,6 +129,22 @@ export function createRouterRuntime({ host = {}, chain = [], routeSafety = "unif
|
|
|
127
129
|
* @returns {Promise<RuntimeResult>}
|
|
128
130
|
*/
|
|
129
131
|
async run(systemPrompt, options = {}) {
|
|
132
|
+
const liveInputHub = options.liveInput === undefined
|
|
133
|
+
? undefined
|
|
134
|
+
: createObserverHub({
|
|
135
|
+
observers: [
|
|
136
|
+
...(Array.isArray(host.observers) ? host.observers : []),
|
|
137
|
+
...(Array.isArray(options.observers) ? options.observers : []),
|
|
138
|
+
],
|
|
139
|
+
onEvent: options.onEvent,
|
|
140
|
+
});
|
|
141
|
+
if (options.liveInput !== undefined && liveInputHub !== undefined) {
|
|
142
|
+
options = {
|
|
143
|
+
...options,
|
|
144
|
+
liveInput: instrumentLiveInputAppliedEvents(options.liveInput, liveInputHub.emit),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
130
148
|
/** @type {Array<{model: RuntimeModelRef, failureKind: (string|null), requestId?: (string|null|undefined), retryableSubkind?: (string|null|undefined), requirements?: (Object<string,*>|null), routeSafety?: import('../types.js').RuntimeRouteSafetyMode, safetyContract?: import('../types.js').RuntimeRouteSafetyContract}>} */
|
|
131
149
|
const failoverHistory = [];
|
|
132
150
|
/** @type {RuntimeResult|null} */
|
|
@@ -374,6 +392,9 @@ export function createRouterRuntime({ host = {}, chain = [], routeSafety = "unif
|
|
|
374
392
|
failoverHistory,
|
|
375
393
|
routeSafetyHistory,
|
|
376
394
|
};
|
|
395
|
+
} finally {
|
|
396
|
+
await liveInputHub?.flush();
|
|
397
|
+
}
|
|
377
398
|
},
|
|
378
399
|
chain: () => entries.slice(),
|
|
379
400
|
configureTools(next = {}) {
|
package/src/ai/types.js
CHANGED
|
@@ -131,6 +131,7 @@
|
|
|
131
131
|
* @property {string} [executionMode] "sdk" (default) or "cli"; selects which bridge variant handles the model.
|
|
132
132
|
* @property {string} [sessionId] Host conversation/session key for resumable bridges.
|
|
133
133
|
* @property {string} [providerSessionId] Provider-owned resume id for resumable bridges.
|
|
134
|
+
* @property {typeof import("@anthropic-ai/claude-agent-sdk").query} [claudeAgentQuery] Advanced programmatic/test seam for the Claude SDK route; omitted runs use the runtime's pinned SDK query implementation.
|
|
134
135
|
* @property {boolean} [sessionKeepAlive] Keep resumable provider state alive after the turn.
|
|
135
136
|
* @property {number} [sessionIdleTimeoutMs] Idle TTL for resumable provider state.
|
|
136
137
|
* @property {AsyncIterable<{body: string, id?: string, receivedAt?: string, acknowledge?: () => void, reject?: (error?: unknown) => void}>} [liveInput] Stream of in-flight user messages for steering an active run. Providers acknowledge only after accepting a message into the active turn.
|
package/src/runtime.js
CHANGED
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
import { createToolContext, updateToolContext } from "./agent/tools/shared/tool-context.js";
|
|
41
41
|
import { resolveRuntimeBrand } from "./runtime-brand.js";
|
|
42
42
|
import { retireDurableNativeSession } from "./ai/providers/pi-native/session-lifecycle.js";
|
|
43
|
+
import { instrumentLiveInputAppliedEvents } from "./ai/runtime/live-input-events.js";
|
|
43
44
|
|
|
44
45
|
/**
|
|
45
46
|
* @typedef {import('./ai/types.js').AgentRuntimeHostOptions} AgentRuntimeHostOptions
|
|
@@ -159,6 +160,7 @@ export function createRuntime(host = {}) {
|
|
|
159
160
|
observers: [...hostObservers, ...callObservers],
|
|
160
161
|
onEvent: options.onEvent,
|
|
161
162
|
});
|
|
163
|
+
const liveInput = instrumentLiveInputAppliedEvents(options.liveInput, hub.emit);
|
|
162
164
|
const prompts = resolvePrompts(host.prompts, options.prompts);
|
|
163
165
|
const result = await bridge.execute(systemPrompt, {
|
|
164
166
|
...hostDefaults,
|
|
@@ -172,6 +174,7 @@ export function createRuntime(host = {}) {
|
|
|
172
174
|
toolContext,
|
|
173
175
|
observerHub: hub,
|
|
174
176
|
onEvent: hub.emit,
|
|
177
|
+
...(liveInput === undefined ? {} : { liveInput }),
|
|
175
178
|
// Merged AFTER the spreads so the per-field run>host>default precedence
|
|
176
179
|
// wins over either bag's whole-object `prompts`.
|
|
177
180
|
...(prompts === undefined ? {} : { prompts }),
|
|
@@ -84,8 +84,6 @@ export type AgentCompactionPolicy = {
|
|
|
84
84
|
summaryMaxTokens: number;
|
|
85
85
|
fixedOverheadEnabled: boolean;
|
|
86
86
|
compactionMinSavingsTokens: number;
|
|
87
|
-
toolPayloadCompactionTriggerChars: number;
|
|
88
|
-
toolPruneTriggerTokens: number;
|
|
89
87
|
toolTextLimitChars: number;
|
|
90
88
|
bashOutputLimitChars: number;
|
|
91
89
|
mcpTextLimitChars: number;
|
|
@@ -8,6 +8,9 @@ export function buildSkillPathNote({ assetsPath, skillsRoot }?: {
|
|
|
8
8
|
skillsRoot?: any;
|
|
9
9
|
}): string;
|
|
10
10
|
/**
|
|
11
|
+
* Render a complete skill body plus its path note. Omitting `maxChars` returns
|
|
12
|
+
* the full text; pass a positive `maxChars` only when explicit truncation is
|
|
13
|
+
* required by the caller.
|
|
11
14
|
* @param {{body?: string, assetsPath?: string, skillsRoot?: any, maxChars?: number}} [options]
|
|
12
15
|
*/
|
|
13
16
|
export function formatSkillBodyWithPathNote({ body, assetsPath, skillsRoot, maxChars }?: {
|
package/types/ai/index.d.ts
CHANGED
|
@@ -3,5 +3,6 @@ export * from "./runtime/registry.js";
|
|
|
3
3
|
export { createSessionRegistry, disposeAllProviderSessions, disposeProviderSession, invalidateProviderSession, refreshProviderSession, syncProviderSession } from "./runtime/sessions.js";
|
|
4
4
|
export { createMetricsObserver, createObserverHub } from "./observer.js";
|
|
5
5
|
export { generatePiNativeResponse, piNativeRuntimeBridge } from "./providers/pi-native.js";
|
|
6
|
+
export { getPiBuiltinModel, listPiBuiltinModels, loginPiOAuth, reasoningLevelsForPiModel, resolvePiOAuthApiKey } from "./pi-interop.js";
|
|
6
7
|
export { CLAUDE_SDK_CATALOG_VERSION, createClaudeSdkDiscoveryIsolation, curatedClaudeSdkModels, discoverClaudeSdkModels, normalizeClaudeSdkCatalog, normalizeClaudeSdkModelId } from "./providers/claude-sdk-discovery.js";
|
|
7
8
|
export { buildCapabilitiesUsed, toolCompactionAppliedFromWarnings, UNKNOWN_CAPABILITY } from "./runtime/capabilities-used.js";
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List defensive snapshots of Pi's built-in models for one provider.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} providerId
|
|
5
|
+
* @returns {PiBuiltinModelSnapshot[]}
|
|
6
|
+
*/
|
|
7
|
+
export function listPiBuiltinModels(providerId: string): PiBuiltinModelSnapshot[];
|
|
8
|
+
/**
|
|
9
|
+
* Read a defensive snapshot of one Pi built-in model.
|
|
10
|
+
*
|
|
11
|
+
* @param {string} providerId
|
|
12
|
+
* @param {string} modelId
|
|
13
|
+
* @returns {PiBuiltinModelSnapshot|undefined}
|
|
14
|
+
*/
|
|
15
|
+
export function getPiBuiltinModel(providerId: string, modelId: string): PiBuiltinModelSnapshot | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Translate Pi's model-native thinking levels to mono-agent effort spelling.
|
|
18
|
+
*
|
|
19
|
+
* @param {PiBuiltinModelSnapshot} model
|
|
20
|
+
* @returns {PiReasoningLevel[]}
|
|
21
|
+
*/
|
|
22
|
+
export function reasoningLevelsForPiModel(model: PiBuiltinModelSnapshot): PiReasoningLevel[];
|
|
23
|
+
/**
|
|
24
|
+
* Resolve an OAuth-backed API key without allowing Pi to mutate the caller's
|
|
25
|
+
* credential record or returning Pi-owned credential objects.
|
|
26
|
+
*
|
|
27
|
+
* @param {string} providerId
|
|
28
|
+
* @param {Object<string, PiOAuthCredentialsSnapshot>} credentials
|
|
29
|
+
* @returns {Promise<{apiKey: string, newCredentials: PiOAuthCredentialsSnapshot}|null>}
|
|
30
|
+
*/
|
|
31
|
+
export function resolvePiOAuthApiKey(providerId: string, credentials: {
|
|
32
|
+
[x: string]: PiOAuthCredentialsSnapshot;
|
|
33
|
+
}): Promise<{
|
|
34
|
+
apiKey: string;
|
|
35
|
+
newCredentials: PiOAuthCredentialsSnapshot;
|
|
36
|
+
} | null>;
|
|
37
|
+
/**
|
|
38
|
+
* Run a supported Pi OAuth login flow without exposing Pi's mutable provider
|
|
39
|
+
* registry or provider instances.
|
|
40
|
+
*
|
|
41
|
+
* @param {string} providerId
|
|
42
|
+
* @param {PiOAuthLoginCallbacks} callbacks
|
|
43
|
+
* @returns {Promise<PiOAuthCredentialsSnapshot>}
|
|
44
|
+
*/
|
|
45
|
+
export function loginPiOAuth(providerId: string, callbacks: PiOAuthLoginCallbacks): Promise<PiOAuthCredentialsSnapshot>;
|
|
46
|
+
export type PiBuiltinModelSnapshot = {
|
|
47
|
+
id: string;
|
|
48
|
+
name: string;
|
|
49
|
+
api: string;
|
|
50
|
+
provider: string;
|
|
51
|
+
baseUrl: string;
|
|
52
|
+
reasoning: boolean;
|
|
53
|
+
input: Array<"text" | "image">;
|
|
54
|
+
cost: {
|
|
55
|
+
input: number;
|
|
56
|
+
output: number;
|
|
57
|
+
cacheRead: number;
|
|
58
|
+
cacheWrite: number;
|
|
59
|
+
tiers?: Array<{
|
|
60
|
+
inputTokensAbove: number;
|
|
61
|
+
input: number;
|
|
62
|
+
output: number;
|
|
63
|
+
cacheRead: number;
|
|
64
|
+
cacheWrite: number;
|
|
65
|
+
}>;
|
|
66
|
+
};
|
|
67
|
+
contextWindow: number;
|
|
68
|
+
maxTokens: number;
|
|
69
|
+
thinkingLevelMap?: {
|
|
70
|
+
[x: string]: string | null;
|
|
71
|
+
};
|
|
72
|
+
compat?: {
|
|
73
|
+
[x: string]: any;
|
|
74
|
+
};
|
|
75
|
+
headers?: {
|
|
76
|
+
[x: string]: string;
|
|
77
|
+
};
|
|
78
|
+
[key: string]: any;
|
|
79
|
+
};
|
|
80
|
+
export type PiReasoningLevel = "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
81
|
+
export type PiOAuthCredentialsSnapshot = {
|
|
82
|
+
refresh: string;
|
|
83
|
+
access: string;
|
|
84
|
+
expires: number;
|
|
85
|
+
[key: string]: any;
|
|
86
|
+
};
|
|
87
|
+
export type PiOAuthLoginCallbacks = {
|
|
88
|
+
onAuth: (info: {
|
|
89
|
+
url: string;
|
|
90
|
+
instructions?: string;
|
|
91
|
+
}) => void;
|
|
92
|
+
onDeviceCode: (info: {
|
|
93
|
+
userCode: string;
|
|
94
|
+
verificationUri: string;
|
|
95
|
+
intervalSeconds?: number;
|
|
96
|
+
expiresInSeconds?: number;
|
|
97
|
+
}) => void;
|
|
98
|
+
onPrompt: (prompt: {
|
|
99
|
+
message: string;
|
|
100
|
+
placeholder?: string;
|
|
101
|
+
allowEmpty?: boolean;
|
|
102
|
+
}) => Promise<string>;
|
|
103
|
+
onProgress?: (message: string) => void;
|
|
104
|
+
onManualCodeInput?: () => Promise<string>;
|
|
105
|
+
onSelect: (prompt: {
|
|
106
|
+
message: string;
|
|
107
|
+
options: Array<{
|
|
108
|
+
id: string;
|
|
109
|
+
label: string;
|
|
110
|
+
}>;
|
|
111
|
+
}) => Promise<string | undefined>;
|
|
112
|
+
signal?: AbortSignal;
|
|
113
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {{body: string, id?: string, receivedAt?: string, acknowledge?: () => void, reject?: (reason?: unknown) => void}} RuntimeLiveInputMessage
|
|
3
|
+
* @typedef {{type: "live_input_applied", inputId: string, receivedAt?: string}} LiveInputAppliedEvent
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @param {AsyncIterable<RuntimeLiveInputMessage>|undefined} liveInput
|
|
7
|
+
* @param {(event: LiveInputAppliedEvent) => void} onApplied
|
|
8
|
+
* @returns {AsyncIterable<RuntimeLiveInputMessage>|undefined}
|
|
9
|
+
*/
|
|
10
|
+
export function instrumentLiveInputAppliedEvents(liveInput: AsyncIterable<RuntimeLiveInputMessage> | undefined, onApplied: (event: LiveInputAppliedEvent) => void): AsyncIterable<RuntimeLiveInputMessage> | undefined;
|
|
11
|
+
export type RuntimeLiveInputMessage = {
|
|
12
|
+
body: string;
|
|
13
|
+
id?: string;
|
|
14
|
+
receivedAt?: string;
|
|
15
|
+
acknowledge?: () => void;
|
|
16
|
+
reject?: (reason?: unknown) => void;
|
|
17
|
+
};
|
|
18
|
+
export type LiveInputAppliedEvent = {
|
|
19
|
+
type: "live_input_applied";
|
|
20
|
+
inputId: string;
|
|
21
|
+
receivedAt?: string;
|
|
22
|
+
};
|
package/types/ai/types.d.ts
CHANGED
|
@@ -102,6 +102,7 @@
|
|
|
102
102
|
* @property {string} [executionMode] "sdk" (default) or "cli"; selects which bridge variant handles the model.
|
|
103
103
|
* @property {string} [sessionId] Host conversation/session key for resumable bridges.
|
|
104
104
|
* @property {string} [providerSessionId] Provider-owned resume id for resumable bridges.
|
|
105
|
+
* @property {typeof import("@anthropic-ai/claude-agent-sdk").query} [claudeAgentQuery] Advanced programmatic/test seam for the Claude SDK route; omitted runs use the runtime's pinned SDK query implementation.
|
|
105
106
|
* @property {boolean} [sessionKeepAlive] Keep resumable provider state alive after the turn.
|
|
106
107
|
* @property {number} [sessionIdleTimeoutMs] Idle TTL for resumable provider state.
|
|
107
108
|
* @property {AsyncIterable<{body: string, id?: string, receivedAt?: string, acknowledge?: () => void, reject?: (error?: unknown) => void}>} [liveInput] Stream of in-flight user messages for steering an active run. Providers acknowledge only after accepting a message into the active turn.
|
|
@@ -481,6 +482,10 @@ export type RuntimeRunOptions = {
|
|
|
481
482
|
* Provider-owned resume id for resumable bridges.
|
|
482
483
|
*/
|
|
483
484
|
providerSessionId?: string;
|
|
485
|
+
/**
|
|
486
|
+
* Advanced programmatic/test seam for the Claude SDK route; omitted runs use the runtime's pinned SDK query implementation.
|
|
487
|
+
*/
|
|
488
|
+
claudeAgentQuery?: typeof import("@anthropic-ai/claude-agent-sdk").query;
|
|
484
489
|
/**
|
|
485
490
|
* Keep resumable provider state alive after the turn.
|
|
486
491
|
*/
|
package/types/ai/backend.d.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
export function backendCapabilities(sdkOrModel: any): any;
|
|
2
|
-
export function backendUsesExecenvConfig(sdk: any): boolean;
|
|
3
|
-
export function backendSupportsSessionResume(sdk: any): boolean;
|
|
4
|
-
export const BACKEND_CAPABILITIES: {
|
|
5
|
-
claude: {
|
|
6
|
-
supports_session_resume: boolean;
|
|
7
|
-
streaming: boolean;
|
|
8
|
-
structured_output: boolean;
|
|
9
|
-
native_runtime_config: any;
|
|
10
|
-
supports_mcp: boolean;
|
|
11
|
-
supports_skills: boolean;
|
|
12
|
-
supports_builtin_tools: boolean;
|
|
13
|
-
supports_live_input: boolean;
|
|
14
|
-
supports_native_subagents: boolean;
|
|
15
|
-
supports_fast_mode: boolean;
|
|
16
|
-
runtime: string;
|
|
17
|
-
};
|
|
18
|
-
pi: {
|
|
19
|
-
supports_session_resume: boolean;
|
|
20
|
-
supports_native_subagents: boolean;
|
|
21
|
-
streaming: boolean;
|
|
22
|
-
structured_output: boolean;
|
|
23
|
-
native_runtime_config: any;
|
|
24
|
-
supports_mcp: boolean;
|
|
25
|
-
supports_skills: boolean;
|
|
26
|
-
supports_builtin_tools: boolean;
|
|
27
|
-
supports_live_input: boolean;
|
|
28
|
-
supports_fast_mode: boolean;
|
|
29
|
-
runtime: string;
|
|
30
|
-
};
|
|
31
|
-
codex: {
|
|
32
|
-
supports_session_resume: boolean;
|
|
33
|
-
supports_fast_mode: boolean;
|
|
34
|
-
streaming: boolean;
|
|
35
|
-
structured_output: boolean;
|
|
36
|
-
native_runtime_config: any;
|
|
37
|
-
supports_mcp: boolean;
|
|
38
|
-
supports_skills: boolean;
|
|
39
|
-
supports_builtin_tools: boolean;
|
|
40
|
-
supports_live_input: boolean;
|
|
41
|
-
supports_native_subagents: boolean;
|
|
42
|
-
runtime: string;
|
|
43
|
-
};
|
|
44
|
-
opencode: {
|
|
45
|
-
structured_output: boolean;
|
|
46
|
-
supports_session_resume: boolean;
|
|
47
|
-
supports_mcp: boolean;
|
|
48
|
-
supports_skills: boolean;
|
|
49
|
-
supports_live_input: boolean;
|
|
50
|
-
supports_native_subagents: boolean;
|
|
51
|
-
streaming: boolean;
|
|
52
|
-
native_runtime_config: any;
|
|
53
|
-
supports_builtin_tools: boolean;
|
|
54
|
-
supports_fast_mode: boolean;
|
|
55
|
-
runtime: string;
|
|
56
|
-
};
|
|
57
|
-
};
|
package/types/ai/registry.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { listRuntimeBridges as listProviders, resolveRuntimeBridge as findProviderForModel, runtimeCapabilities } from "./runtime/registry.js";
|