@mono-agent/agent-runtime 0.11.2 → 0.11.4

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 CHANGED
@@ -190,35 +190,49 @@ falls back to its own env vars, exactly as returning `undefined` from the old ho
190
190
  did). **No host action needed** — `resolvePiApiKey` behaves as before.
191
191
 
192
192
  Dependency bump: **`@earendil-works/pi-ai` and `@earendil-works/pi-agent-core` are
193
- now `^0.80.x`** (were `^0.79.1`). Compaction is driven natively (section 3).
193
+ now `0.80.6`** (the initial Pi 0.80 migration landed at `0.80.5`, from
194
+ `^0.79.1`). Compaction is driven natively (section 3). The `0.80.6` refresh also
195
+ preserves model-native `max` reasoning and Pi's request-wide pricing tiers.
194
196
 
195
197
  ## 11. Exports map: wildcards removed (explicit deep-path map)
196
198
 
197
199
  The package's `./ai/*` and `./agent/*` **wildcard exports were replaced by an
198
- explicit `exports` map**: 3 barrels (`.`, `./ai`, `./agent`) plus **21 named deep
199
- `.js` subpaths**, each carrying its own generated `types` condition. A deep import
200
- that is not on the map **no longer resolves** — a wildcard used to silently
201
- resolve anything under `src/`, so a moved/renamed/mistyped subpath is now a loud
202
- failure (guarded by `scripts/verify-deep-imports.mjs`).
203
-
204
- The 21 supported deep paths:
205
-
206
- ```
207
- ./ai/failure.js ./agent/tools/index.js
208
- ./ai/cost.js ./agent/tools/shared/runtime-context.js
209
- ./ai/backend.js ./agent/tools/shared/ripgrep.js
210
- ./ai/runtime/model-refs.js ./agent/prompt/skill-index.js
211
- ./ai/runtime/registry.js ./agent/allowlists.js
212
- ./ai/runtime/context-windows.js ./agent/transcript.js
213
- ./ai/runtime/fast-mode.js ./agent/compaction.js
214
- ./ai/streaming/codex-events.js
215
- ./ai/live-input-prompt.js
216
- ./ai/file-change-stats.js
217
- ./ai/providers/claude-sdk.js
218
- ./ai/providers/claude-cli.js
219
- ./ai/providers/codex-app.js
220
- ./ai/providers/opencode-discovery.js
200
+ explicit `exports` map**: 3 barrels (`.`, `./ai`, `./agent`) plus the generated
201
+ deep-path inventory below, with every entry carrying its own `types` condition.
202
+ A deep import that is not on the map **no longer resolves** — a wildcard used to
203
+ silently resolve anything under `src/`, so a moved/renamed/mistyped subpath is
204
+ now a loud failure (guarded by `scripts/verify-deep-imports.mjs`).
205
+
206
+ <!-- public-api-js-subpaths:start -->
207
+ <!-- Generated by scripts/generate-public-api-docs.mjs. Do not edit by hand. -->
208
+
209
+ The package exposes **22 named deep `.js` subpaths**:
210
+
211
+ ```text
212
+ @mono-agent/agent-runtime/agent/allowlists.js
213
+ @mono-agent/agent-runtime/agent/compaction.js
214
+ @mono-agent/agent-runtime/agent/prompt/skill-index.js
215
+ @mono-agent/agent-runtime/agent/tools/index.js
216
+ @mono-agent/agent-runtime/agent/tools/shared/ripgrep.js
217
+ @mono-agent/agent-runtime/agent/tools/shared/runtime-context.js
218
+ @mono-agent/agent-runtime/agent/transcript.js
219
+ @mono-agent/agent-runtime/ai/backend.js
220
+ @mono-agent/agent-runtime/ai/cost.js
221
+ @mono-agent/agent-runtime/ai/failure.js
222
+ @mono-agent/agent-runtime/ai/file-change-stats.js
223
+ @mono-agent/agent-runtime/ai/live-input-prompt.js
224
+ @mono-agent/agent-runtime/ai/providers/claude-cli.js
225
+ @mono-agent/agent-runtime/ai/providers/claude-sdk-discovery.js
226
+ @mono-agent/agent-runtime/ai/providers/claude-sdk.js
227
+ @mono-agent/agent-runtime/ai/providers/codex-app.js
228
+ @mono-agent/agent-runtime/ai/providers/opencode-discovery.js
229
+ @mono-agent/agent-runtime/ai/runtime/context-windows.js
230
+ @mono-agent/agent-runtime/ai/runtime/fast-mode.js
231
+ @mono-agent/agent-runtime/ai/runtime/model-refs.js
232
+ @mono-agent/agent-runtime/ai/runtime/registry.js
233
+ @mono-agent/agent-runtime/ai/streaming/codex-events.js
221
234
  ```
235
+ <!-- public-api-js-subpaths:end -->
222
236
 
223
237
  **Action:** if you deep-import a subpath not in this list, switch to the closest
224
238
  supported one, a barrel (`./ai` / `./agent`), or the public runtime registry.
@@ -254,9 +268,9 @@ Run these before/at the port:
254
268
  in `src/`.)*
255
269
  2. **Dependencies.** Post-decoupling the kernel has **zero workspace-package
256
270
  deps**; only the third-party pins need aligning: `@earendil-works/pi-ai` +
257
- `@earendil-works/pi-agent-core` (`^0.80.x`), `@modelcontextprotocol/sdk`,
271
+ `@earendil-works/pi-agent-core` (`0.80.6`), `@modelcontextprotocol/sdk`,
258
272
  `@opencode-ai/sdk`, `@anthropic-ai/claude-agent-sdk`, `zod`.
259
- 3. **Pi bump `^0.74.0` → `^0.80.x` in lockstep.** worklab tests that use old pi
273
+ 3. **Pi bump `^0.74.0` → `0.80.6` in lockstep.** worklab tests that use old pi
260
274
  APIs are rewritten at the port. Do not restore the old `pi-sdk.js` deep
261
275
  import; use `generatePiNativeResponse` from `@mono-agent/agent-runtime/ai`.
262
276
  4. **Sandbox.** worklab passes **no** `sandbox` implementation → `passthroughSandbox`,
package/README.md CHANGED
@@ -10,14 +10,397 @@ Provides five runtime bridges (Claude SDK, Claude Code CLI, Codex app-server, Op
10
10
 
11
11
  ## Public API
12
12
 
13
- - `createRuntime` — runtime factory dispatching to the backend bridges
14
- - `ai/runtime/model-refs.js` `parseRuntimeModelReference`, `executionModeIncompatibilityReason`
15
- - `ai/runtime/registry.js` — `listRuntimeBridges`
16
- - `ai/providers/claude-sdk-discovery.js` isolated Claude SDK model discovery without importing ambient auth/config
17
- - `createRouterRuntime({ chain, routeSafety, resolveAttempt })` — ordered fallback routing with exact route effort and bounded safety/failover telemetry
18
- - Provider bridges for `claude` (SDK + CLI), `codex` (app-server), `pi` (Pi SDK), and `opencode`
19
- - Provider session support: bridges accept `sessionId` in run options and report `provider_session_id`; the runtime exposes best-effort disposal, strict cold-refresh, exact-id durable retirement, invalidation, and whole-runtime shutdown operations
20
- - Sandbox-aware built-in tools and stdio MCP startup through an injectable `RuntimeSandbox` seam (`agent/sandbox-seam.js`) — no direct dependency on `@mono-agent/runtime-adapter`
13
+ <!-- public-api-inventory:start -->
14
+ <!-- Generated by scripts/generate-public-api-docs.mjs. Do not edit by hand. -->
15
+
16
+ Every symbol exported by each public code entrypoint is listed below.
17
+
18
+ **`@mono-agent/agent-runtime`**
19
+
20
+ ```text
21
+ ACTIVE_RUNTIME_KINDS
22
+ ALLOWLIST_MODE_ALL
23
+ ALLOWLIST_MODE_CUSTOM
24
+ APPROVAL_DECISIONS
25
+ BINARY_BLOAT_TOOLS
26
+ BridgeSpec
27
+ CLAUDE_SDK_CATALOG_VERSION
28
+ DEFAULT_RUNTIME_BRAND
29
+ DEFAULT_TOOL_BLOAT_CONFIG
30
+ MAX_TOOL_RESULT_BYTES
31
+ RESERVED_RUNTIME_KINDS
32
+ RISK_TIERS
33
+ RUNTIME_CAPABILITIES
34
+ RuntimeBridge
35
+ RuntimeBridgeDescriptor
36
+ RuntimeBridgeId
37
+ RuntimeModelRef
38
+ UNKNOWN_CAPABILITY
39
+ buildCapabilitiesUsed
40
+ buildTranscriptTailSnapshot
41
+ canonicalizeLegacyModelReference
42
+ configureToolRuntime
43
+ createApprovalManager
44
+ createClaudeSdkDiscoveryIsolation
45
+ createMetricsObserver
46
+ createObserverHub
47
+ createPiOAuthApiKeyResolver
48
+ createRouterRuntime
49
+ createRuntime
50
+ createSessionRegistry
51
+ curatedClaudeSdkModels
52
+ discoverClaudeSdkModels
53
+ disposeAllProviderSessions
54
+ disposeProviderSession
55
+ executionModeIncompatibilityReason
56
+ findProviderForModel
57
+ generatePiNativeResponse
58
+ inferAllowlistMode
59
+ invalidateProviderSession
60
+ isLikelyContextTermination
61
+ isModelCompatibleWithExecutionMode
62
+ listProviders
63
+ listRuntimeBridges
64
+ normalizeAllowlistMode
65
+ normalizeClaudeSdkCatalog
66
+ normalizeClaudeSdkModelId
67
+ normalizeList
68
+ normalizeRuntimeModelReference
69
+ parseRuntimeModelReference
70
+ parseStoredAllowlist
71
+ piNativeRuntimeBridge
72
+ readRuntimeBrand
73
+ readToolRuntime
74
+ refreshProviderSession
75
+ renderResumeSnapshot
76
+ resetToolRuntime
77
+ resolveAgentCompactionPolicy
78
+ resolveAllowlist
79
+ resolveAllowlistMap
80
+ resolveRuntimeBrand
81
+ resolveRuntimeBridge
82
+ runtimeCapabilities
83
+ sdkFromModelReference
84
+ storedAllowlistMode
85
+ syncProviderSession
86
+ toolCompactionAppliedFromWarnings
87
+ wrapToolsWithApprovalGate
88
+ ```
89
+
90
+ **`@mono-agent/agent-runtime/agent`**
91
+
92
+ ```text
93
+ ALLOWLIST_MODE_ALL
94
+ ALLOWLIST_MODE_CUSTOM
95
+ APPROVAL_DECISIONS
96
+ BINARY_BLOAT_TOOLS
97
+ DEFAULT_TOOL_BLOAT_CONFIG
98
+ MAX_TOOL_RESULT_BYTES
99
+ RISK_TIERS
100
+ buildTranscriptTailSnapshot
101
+ createApprovalManager
102
+ inferAllowlistMode
103
+ isLikelyContextTermination
104
+ normalizeAllowlistMode
105
+ normalizeList
106
+ parseStoredAllowlist
107
+ renderResumeSnapshot
108
+ resolveAgentCompactionPolicy
109
+ resolveAllowlist
110
+ resolveAllowlistMap
111
+ storedAllowlistMode
112
+ wrapToolsWithApprovalGate
113
+ ```
114
+
115
+ **`@mono-agent/agent-runtime/agent/allowlists.js`**
116
+
117
+ ```text
118
+ ALLOWLIST_MODE_ALL
119
+ ALLOWLIST_MODE_CUSTOM
120
+ inferAllowlistMode
121
+ normalizeAllowlistMode
122
+ normalizeList
123
+ parseStoredAllowlist
124
+ resolveAllowlist
125
+ resolveAllowlistMap
126
+ storedAllowlistMode
127
+ ```
128
+
129
+ **`@mono-agent/agent-runtime/agent/compaction.js`**
130
+
131
+ ```text
132
+ AgentCompactionPolicy
133
+ DEPRECATED_SETTINGS_WARNING_KIND
134
+ deprecatedSettingsWarning
135
+ estimateFixedOverheadTokens
136
+ isLikelyContextTermination
137
+ resolveAgentCompactionPolicy
138
+ resolveRuntimePolicyInputs
139
+ ```
140
+
141
+ **`@mono-agent/agent-runtime/agent/prompt/skill-index.js`**
142
+
143
+ ```text
144
+ buildSkillIndex
145
+ buildSkillPathNote
146
+ formatSkillBodyWithPathNote
147
+ getSkillAccessDirs
148
+ inferSkillsRoot
149
+ ```
150
+
151
+ **`@mono-agent/agent-runtime/agent/tools/index.js`**
152
+
153
+ ```text
154
+ bashToolImpl
155
+ editToolImpl
156
+ globToolImpl
157
+ grepToolImpl
158
+ isPathAllowed
159
+ isWorkdirAllowed
160
+ normalizeBashTimeoutMs
161
+ readToolImpl
162
+ resolveRgPath
163
+ webFetchToolImpl
164
+ webSearchToolImpl
165
+ writeToolImpl
166
+ ```
167
+
168
+ **`@mono-agent/agent-runtime/agent/tools/shared/ripgrep.js`**
169
+
170
+ ```text
171
+ cachedRgPath
172
+ capLines
173
+ excludedGlobArgs
174
+ excludedPathSummary
175
+ formatSearchLines
176
+ normalizeGlobPattern
177
+ resolveRgPath
178
+ ripgrepMissingMessage
179
+ ```
180
+
181
+ **`@mono-agent/agent-runtime/agent/tools/shared/runtime-context.js`**
182
+
183
+ ```text
184
+ ToolContext
185
+ ToolRuntimeContext
186
+ configureToolRuntime
187
+ readRuntimeBrand
188
+ readToolRuntime
189
+ resetToolRuntime
190
+ resolveSandboxPolicy
191
+ ```
192
+
193
+ **`@mono-agent/agent-runtime/agent/transcript.js`**
194
+
195
+ ```text
196
+ RESUME_SNAPSHOT_DEFAULTS
197
+ buildTranscriptTailSnapshot
198
+ renderResumeSnapshot
199
+ ```
200
+
201
+ **`@mono-agent/agent-runtime/ai`**
202
+
203
+ ```text
204
+ ACTIVE_RUNTIME_KINDS
205
+ BridgeSpec
206
+ CLAUDE_SDK_CATALOG_VERSION
207
+ RESERVED_RUNTIME_KINDS
208
+ RUNTIME_CAPABILITIES
209
+ RuntimeBridge
210
+ RuntimeBridgeDescriptor
211
+ RuntimeBridgeId
212
+ RuntimeModelRef
213
+ UNKNOWN_CAPABILITY
214
+ buildCapabilitiesUsed
215
+ canonicalizeLegacyModelReference
216
+ createClaudeSdkDiscoveryIsolation
217
+ createMetricsObserver
218
+ createObserverHub
219
+ createSessionRegistry
220
+ curatedClaudeSdkModels
221
+ discoverClaudeSdkModels
222
+ disposeAllProviderSessions
223
+ disposeProviderSession
224
+ executionModeIncompatibilityReason
225
+ findProviderForModel
226
+ generatePiNativeResponse
227
+ invalidateProviderSession
228
+ isModelCompatibleWithExecutionMode
229
+ listProviders
230
+ listRuntimeBridges
231
+ normalizeClaudeSdkCatalog
232
+ normalizeClaudeSdkModelId
233
+ normalizeRuntimeModelReference
234
+ parseRuntimeModelReference
235
+ piNativeRuntimeBridge
236
+ refreshProviderSession
237
+ resolveRuntimeBridge
238
+ runtimeCapabilities
239
+ sdkFromModelReference
240
+ syncProviderSession
241
+ toolCompactionAppliedFromWarnings
242
+ ```
243
+
244
+ **`@mono-agent/agent-runtime/ai/backend.js`**
245
+
246
+ ```text
247
+ BACKEND_CAPABILITIES
248
+ backendCapabilities
249
+ backendSupportsSessionResume
250
+ backendUsesExecenvConfig
251
+ ```
252
+
253
+ **`@mono-agent/agent-runtime/ai/cost.js`**
254
+
255
+ ```text
256
+ NormalizedPricing
257
+ ParsedModelReference
258
+ PricingInputRow
259
+ estimateCost
260
+ isPrivateHost
261
+ normalizePricing
262
+ parseReference
263
+ pricingHasRates
264
+ resolvePricing
265
+ unknownPricing
266
+ zeroPricing
267
+ ```
268
+
269
+ **`@mono-agent/agent-runtime/ai/failure.js`**
270
+
271
+ ```text
272
+ FAILURE_KINDS
273
+ FailureKind
274
+ PROVIDER_ABORT_RE
275
+ RetryableProviderFailureInfo
276
+ classifyFailure
277
+ createStderrTail
278
+ isProviderAuthFailureText
279
+ retryableProviderFailureInfo
280
+ ```
281
+
282
+ **`@mono-agent/agent-runtime/ai/file-change-stats.js`**
283
+
284
+ ```text
285
+ createFileChangePayload
286
+ fileChangeSummary
287
+ readFileChangeSnapshot
288
+ statsForCompletedChange
289
+ ```
290
+
291
+ **`@mono-agent/agent-runtime/ai/live-input-prompt.js`**
292
+
293
+ ```text
294
+ formatLiveInputGuidance
295
+ ```
296
+
297
+ **`@mono-agent/agent-runtime/ai/providers/claude-cli.js`**
298
+
299
+ ```text
300
+ buildCliCommand
301
+ claudeCodeBackend
302
+ claudeCodeRuntimeBridge
303
+ codexCliBackend
304
+ createThinkingBuffer
305
+ generateCliResponse
306
+ normalizeCliEvent
307
+ ```
308
+
309
+ **`@mono-agent/agent-runtime/ai/providers/claude-sdk-discovery.js`**
310
+
311
+ ```text
312
+ CLAUDE_SDK_CATALOG_VERSION
313
+ ClaudeSdkCatalogModel
314
+ ClaudeSdkEffort
315
+ createClaudeSdkDiscoveryIsolation
316
+ curatedClaudeSdkModels
317
+ discoverClaudeSdkModels
318
+ normalizeClaudeSdkCatalog
319
+ normalizeClaudeSdkModelId
320
+ ```
321
+
322
+ **`@mono-agent/agent-runtime/ai/providers/claude-sdk.js`**
323
+
324
+ ```text
325
+ claudeEffortOptions
326
+ claudeRuntimeBridge
327
+ claudeSdkBackend
328
+ claudeSdkModelForQuery
329
+ generateClaudeResponse
330
+ toolPayloadLimit
331
+ ```
332
+
333
+ **`@mono-agent/agent-runtime/ai/providers/codex-app.js`**
334
+
335
+ ```text
336
+ codexAppBackend
337
+ codexAppRuntimeBridge
338
+ createCodexAppServerClient
339
+ generateCodexAppResponse
340
+ ```
341
+
342
+ **`@mono-agent/agent-runtime/ai/providers/opencode-discovery.js`**
343
+
344
+ ```text
345
+ discoverOpencodeProviders
346
+ ```
347
+
348
+ **`@mono-agent/agent-runtime/ai/runtime/context-windows.js`**
349
+
350
+ ```text
351
+ CLAUDE_ONE_MILLION_CONTEXT_MODELS
352
+ DEFAULT_CONTEXT_WINDOW
353
+ ONE_MILLION_CONTEXT_WINDOW
354
+ claudeModelSupportsContextWindow
355
+ claudeModelSupportsOneMillionContext
356
+ hasExplicitOneMillionContextWindow
357
+ modelWithContextWindow
358
+ normalizeContextWindow
359
+ stripContextWindowSuffix
360
+ ```
361
+
362
+ **`@mono-agent/agent-runtime/ai/runtime/fast-mode.js`**
363
+
364
+ ```text
365
+ codexModelSupportsFastMode
366
+ normalizeFastMode
367
+ ```
368
+
369
+ **`@mono-agent/agent-runtime/ai/runtime/model-refs.js`**
370
+
371
+ ```text
372
+ ACTIVE_RUNTIME_KINDS
373
+ RESERVED_RUNTIME_KINDS
374
+ RuntimeModelRef
375
+ canonicalizeLegacyModelReference
376
+ executionModeIncompatibilityReason
377
+ isModelCompatibleWithExecutionMode
378
+ normalizeRuntimeModelReference
379
+ parseRuntimeModelReference
380
+ sdkFromModelReference
381
+ ```
382
+
383
+ **`@mono-agent/agent-runtime/ai/runtime/registry.js`**
384
+
385
+ ```text
386
+ BridgeSpec
387
+ RUNTIME_CAPABILITIES
388
+ RuntimeBridge
389
+ RuntimeBridgeDescriptor
390
+ RuntimeBridgeId
391
+ listRuntimeBridges
392
+ resolveRuntimeBridge
393
+ runtimeCapabilities
394
+ ```
395
+
396
+ **`@mono-agent/agent-runtime/ai/streaming/codex-events.js`**
397
+
398
+ ```text
399
+ normalizeCodexItemEvent
400
+ normalizeCodexItemType
401
+ ```
402
+
403
+ <!-- public-api-inventory:end -->
21
404
 
22
405
  ## Dependency Boundary
23
406
 
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "@mono-agent/agent-runtime",
3
- "version": "0.11.2",
3
+ "version": "0.11.4",
4
4
  "description": "Agent runtime supporting Claude SDK/CLI, Codex, OpenCode, and Pi SDK bridges out of the box",
5
5
  "type": "module",
6
6
  "license": "GPL-3.0-only",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/robertsreberski/mono-agent.git",
10
+ "directory": "packages/agent-runtime"
11
+ },
7
12
  "keywords": [
8
13
  "ai",
9
14
  "agents",
@@ -132,8 +137,8 @@
132
137
  "dependencies": {
133
138
  "@anthropic-ai/claude-agent-sdk": "0.3.206",
134
139
  "@anthropic-ai/sdk": "^0.110.0",
135
- "@earendil-works/pi-agent-core": "^0.80.5",
136
- "@earendil-works/pi-ai": "^0.80.5",
140
+ "@earendil-works/pi-agent-core": "0.80.6",
141
+ "@earendil-works/pi-ai": "0.80.6",
137
142
  "@modelcontextprotocol/sdk": "^1.29.0",
138
143
  "@opencode-ai/sdk": "^1.15.13",
139
144
  "@vscode/ripgrep": "1.18.0",
@@ -1,8 +1,7 @@
1
- // Public surface of the agent kernel. The kernel is consumed by the
2
- // worker, the assistant, the Slack triage path, and the coordinator's
3
- // run-spawn path. Everything below is intentionally re-exported; anything
4
- // not listed here is private to the kernel and should not be imported
5
- // from edge layers.
1
+ // Public agent-kernel barrel for runtime hosts. Everything below is
2
+ // intentionally re-exported through `@mono-agent/agent-runtime/agent`;
3
+ // agent modules not exposed by the package's exports map remain private
4
+ // implementation details.
6
5
 
7
6
  export {
8
7
  isLikelyContextTermination,
package/src/ai/cost.js CHANGED
@@ -4,6 +4,7 @@
4
4
  // deprecated/compat-only). `getBuiltinModel(provider, id)` from `providers/all`
5
5
  // is the non-deprecated replacement with the same signature and the same
6
6
  // undefined-on-miss behavior the pricing lookup below relies on.
7
+ import { calculateCost as calculatePiCost } from "@earendil-works/pi-ai";
7
8
  import { getBuiltinModel as getPiModel } from "@earendil-works/pi-ai/providers/all";
8
9
 
9
10
  /**
@@ -192,9 +193,9 @@ function pricingHasRates(pricing = {}) {
192
193
  * - sdk "claude": looked up under pi's "anthropic" provider (its models carry
193
194
  * `cost`), so pi's live rates win over the static CLAUDE_PRICING fallback.
194
195
  * @param {ParsedModelReference|null|undefined} parsed
195
- * @returns {NormalizedPricing|null}
196
+ * @returns {import("@earendil-works/pi-ai").Model<any>|null}
196
197
  */
197
- function piCatalogPricing(parsed) {
198
+ function piCatalogModel(parsed) {
198
199
  if (!parsed?.model) return null;
199
200
  let provider;
200
201
  if (parsed.sdk === "pi" && parsed.provider) provider = parsed.provider;
@@ -204,13 +205,21 @@ function piCatalogPricing(parsed) {
204
205
  // `provider` may be a caller-supplied id (custom providers included), wider
205
206
  // than pi-ai's built-in KnownProvider catalog union; the catalog lookup
206
207
  // itself is the runtime check, guarded by the catch below.
207
- const model = getPiModel(/** @type {*} */ (provider), parsed.model);
208
- return model?.cost ? normalizePricing(model.cost, { source: "pi-catalog" }) : null;
208
+ return getPiModel(/** @type {*} */ (provider), parsed.model) || null;
209
209
  } catch {
210
210
  return null;
211
211
  }
212
212
  }
213
213
 
214
+ /**
215
+ * @param {ParsedModelReference|null|undefined} parsed
216
+ * @returns {NormalizedPricing|null}
217
+ */
218
+ function piCatalogPricing(parsed) {
219
+ const model = piCatalogModel(parsed);
220
+ return model?.cost ? normalizePricing(model.cost, { source: "pi-catalog" }) : null;
221
+ }
222
+
214
223
  /**
215
224
  * @param {ParsedModelReference|null|undefined} parsed
216
225
  * @returns {NormalizedPricing|null}
@@ -244,6 +253,19 @@ export function resolvePricing({ resolveCustomPricing, model } = {}) {
244
253
  || unknownPricing();
245
254
  }
246
255
 
256
+ /**
257
+ * @param {any} model
258
+ * @param {{input: number, output: number, cacheRead: number, cacheWrite: number}} usage
259
+ * @returns {number}
260
+ */
261
+ function estimatePiCatalogCost(model, usage) {
262
+ return calculatePiCost(model, {
263
+ ...usage,
264
+ totalTokens: usage.input + usage.output + usage.cacheRead + usage.cacheWrite,
265
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
266
+ }).total;
267
+ }
268
+
247
269
  export { normalizePricing, zeroPricing, unknownPricing, pricingHasRates, isPrivateHost, parseReference };
248
270
 
249
271
  /**
@@ -266,12 +288,22 @@ export function estimateCost({
266
288
  cacheWriteTokens = 0,
267
289
  cacheCreationTokens = 0,
268
290
  } = {}) {
269
- const pricing = resolvePricing({ resolveCustomPricing, model });
270
- if (!pricing?.priced) return null;
271
291
  const cacheRead = Math.max(0, Number(cachedTokens) || 0);
272
292
  const cacheWrite = Math.max(0, Number(cacheWriteTokens ?? cacheCreationTokens) || 0);
273
293
  const input = Math.max(0, Number(inputTokens) || 0);
274
294
  const output = Math.max(0, Number(outputTokens) || 0);
295
+ const parsed = parseReference(model);
296
+ const customPricing = parsed && typeof resolveCustomPricing === "function"
297
+ ? resolveCustomPricing(parsed)
298
+ : null;
299
+ const piModel = customPricing ? null : piCatalogModel(parsed);
300
+ if (piModel?.cost) {
301
+ return estimatePiCatalogCost(piModel, { input, output, cacheRead, cacheWrite });
302
+ }
303
+ const pricing = customPricing
304
+ || claudePricing(parsed)
305
+ || unknownPricing();
306
+ if (!pricing?.priced) return null;
275
307
  const parts = [
276
308
  [input, pricing.input],
277
309
  [cacheRead, pricing.cacheRead],
@@ -24,8 +24,11 @@ const MAX_CLAUDE_ERROR_CHARS = 2_000;
24
24
 
25
25
  /**
26
26
  * Preserve the provider default when effort is omitted. The current Agent SDK
27
- * accepts the five values below verbatim; mono-agent must not infer thinking
28
- * enablement/disablement from a requested effort level.
27
+ * public effort contract accepts the five values below. Its shipped JavaScript
28
+ * currently forwards out-of-contract values to Claude Code, so mono-agent keeps
29
+ * this route inside the pinned public contract rather than relying on that
30
+ * untyped pass-through. Mono-agent must not infer thinking enablement/disablement
31
+ * from a requested effort level.
29
32
  * @param {unknown} effort
30
33
  * @returns {{effort?: "low" | "medium" | "high" | "xhigh" | "max"}}
31
34
  */
@@ -34,12 +37,12 @@ export function claudeEffortOptions(effort) {
34
37
  const normalized = String(effort).trim();
35
38
  if (normalized === "none") {
36
39
  throw new Error(
37
- 'Claude Agent SDK does not support effort "none". Omit effort to use the provider default, or choose low, medium, high, xhigh, or max.',
40
+ 'Mono-agent\'s Claude SDK route does not support effort "none": the pinned Claude Agent SDK public effort contract starts at "low". Omit effort to use the provider default, or choose low, medium, high, xhigh, or max.',
38
41
  );
39
42
  }
40
43
  if (!CLAUDE_EFFORT_LEVELS.has(normalized)) {
41
44
  throw new Error(
42
- `Claude Agent SDK does not support effort "${boundedText(normalized, 64)}". Choose low, medium, high, xhigh, or max, or omit effort.`,
45
+ `Mono-agent's Claude SDK route does not support effort "${boundedText(normalized, 64)}": the pinned Claude Agent SDK public effort contract ends at "max". Choose low, medium, high, xhigh, or max, or omit effort.`,
43
46
  );
44
47
  }
45
48
  return { effort: /** @type {"low" | "medium" | "high" | "xhigh" | "max"} */ (normalized) };
@@ -2,6 +2,7 @@
2
2
  // deprecated/compat-only. `getBuiltinModel(provider, id)` from `providers/all`
3
3
  // is the non-deprecated replacement — same 2-arg signature, and it returns
4
4
  // `undefined` on an unknown provider/model exactly like the old `getModel`.
5
+ import { getSupportedThinkingLevels } from "@earendil-works/pi-ai";
5
6
  import { getBuiltinModel as getPiModel } from "@earendil-works/pi-ai/providers/all";
6
7
  import { readRuntimeBrand } from "../../agent/tools/shared/runtime-context.js";
7
8
 
@@ -42,6 +43,18 @@ function customCompat(capabilities, isPrivate) {
42
43
  };
43
44
  }
44
45
 
46
+ /**
47
+ * Translate Pi's model-native thinking levels to mono-agent's public effort
48
+ * spelling. Pi calls the disabled level `off`; mono-agent calls it `none`.
49
+ * Keeping this derived from the model lets new native levels (such as `max`)
50
+ * flow through without maintaining a second hard-coded catalog.
51
+ * @param {any} model
52
+ * @returns {string[]}
53
+ */
54
+ export function reasoningLevelsForPiModel(model) {
55
+ return getSupportedThinkingLevels(model).map((level) => level === "off" ? "none" : level);
56
+ }
57
+
45
58
  // Build the pi-runtime view of a custom provider/model from
46
59
  // pre-resolved primitives. The caller (core/ai.js#generateResponse) reads
47
60
  // the provider/model rows and computes the capabilities + isPrivate flag
@@ -118,7 +131,7 @@ export function resolvePiRuntimeModel(resolved, options) {
118
131
  tool_use: true,
119
132
  reasoning: !!model.reasoning,
120
133
  reasoning_mode: model.reasoning ? "effort" : "none",
121
- reasoning_levels: model.reasoning ? ["none", "low", "medium", "high", "xhigh"] : undefined,
134
+ reasoning_levels: model.reasoning ? reasoningLevelsForPiModel(model) : undefined,
122
135
  reasoning_disable_supported: true,
123
136
  vision: Array.isArray(model.input) ? model.input.includes("image") : false,
124
137
  json_mode: true,
@@ -94,9 +94,9 @@ export function emitCapabilitiesResolved(onEvent, { sdk, model, capabilitiesUsed
94
94
 
95
95
  /**
96
96
  * The aborted-run result (entry pre-check / pre-request abort). Pure factory.
97
- * @param {{resolved: any, options: any, events: any[], runtimeWarnings: any[], start: number, providerSessionId: string}} params
97
+ * @param {{resolved: any, options: any, events: any[], runtimeWarnings: any[], start: number, providerSessionId: string, piTransport: string}} params
98
98
  */
99
- export function abortedResult({ resolved, options, events, runtimeWarnings, start, providerSessionId }) {
99
+ export function abortedResult({ resolved, options, events, runtimeWarnings, start, providerSessionId, piTransport }) {
100
100
  return {
101
101
  text: null,
102
102
  thinking: "",
@@ -116,6 +116,7 @@ export function abortedResult({ resolved, options, events, runtimeWarnings, star
116
116
  provider_session_id: providerSessionId,
117
117
  pi_stop_reason: "aborted",
118
118
  pi_engine: "native",
119
+ pi_transport_requested: piTransport,
119
120
  external_abort: true,
120
121
  },
121
122
  };
@@ -201,6 +202,7 @@ export function buildErrorResult(params) {
201
202
  providerSessionId,
202
203
  runtimeWarnings,
203
204
  isRetryable,
205
+ piTransport,
204
206
  } = params;
205
207
  return {
206
208
  text: assistantTexts.join("") || null,
@@ -221,6 +223,7 @@ export function buildErrorResult(params) {
221
223
  max_turns_hit: maxTurnsHit,
222
224
  provider_session_id: providerSessionId,
223
225
  pi_engine: "native",
226
+ pi_transport_requested: piTransport,
224
227
  pi_error_retryable: isRetryable,
225
228
  },
226
229
  failureKind: externalAbort ? null : failureKindForPiError(errorMessage, {}, { maxTurnsHit }),
@@ -230,6 +233,7 @@ export function buildErrorResult(params) {
230
233
  provider_session_id: providerSessionId,
231
234
  pi_stop_reason: externalAbort ? "aborted" : "error",
232
235
  pi_engine: "native",
236
+ pi_transport_requested: piTransport,
233
237
  max_turns_hit: maxTurnsHit,
234
238
  turn_count: turnCount,
235
239
  external_abort: externalAbort,
@@ -252,6 +256,7 @@ export function buildDiagnostics(params) {
252
256
  runAssistantCount,
253
257
  externalAbort,
254
258
  maxRetries,
259
+ piTransport,
255
260
  lastToolName,
256
261
  structuredRetry,
257
262
  contextCompactionDiagnostics,
@@ -265,6 +270,7 @@ export function buildDiagnostics(params) {
265
270
  turn_count: turnCount || runAssistantCount,
266
271
  external_abort: externalAbort,
267
272
  pi_max_retries: maxRetries,
273
+ pi_transport_requested: piTransport,
268
274
  ...(lastToolName ? { last_tool_name: lastToolName } : {}),
269
275
  ...structuredOutputRetryDiagnostics(
270
276
  structuredRetry.attempts,
@@ -177,6 +177,7 @@ function sessionUnavailableResult({
177
177
  errorMessage,
178
178
  failureKind,
179
179
  piErrorCode,
180
+ piTransport,
180
181
  }) {
181
182
  return {
182
183
  text: null,
@@ -196,6 +197,7 @@ function sessionUnavailableResult({
196
197
  provider_session_id: sessionId,
197
198
  pi_error_code: piErrorCode,
198
199
  pi_engine: "native",
200
+ pi_transport_requested: piTransport,
199
201
  },
200
202
  };
201
203
  }
@@ -221,6 +223,7 @@ export async function resolveSession(runState, {
221
223
  events,
222
224
  runtimeWarnings,
223
225
  start,
226
+ piTransport,
224
227
  }) {
225
228
  // Resume check first: a session miss must stay cheap (no tool/MCP/harness
226
229
  // init). This mirrors the legacy bridge's fail-fast contract.
@@ -307,6 +310,7 @@ export async function resolveSession(runState, {
307
310
  errorMessage: `Pi session ${requestedSessionId} is not live`,
308
311
  failureKind: "session_not_found",
309
312
  piErrorCode: "pi_session_not_found",
313
+ piTransport,
310
314
  }),
311
315
  };
312
316
  }
@@ -344,6 +348,7 @@ export async function resolveSession(runState, {
344
348
  : `Pi session ${requestedSessionId} is busy with another turn`,
345
349
  failureKind: missing ? "session_not_found" : "session_busy",
346
350
  piErrorCode: missing ? "pi_session_not_found" : "pi_session_busy",
351
+ piTransport,
347
352
  }),
348
353
  };
349
354
  }
@@ -0,0 +1,16 @@
1
+ // @ts-check
2
+
3
+ const PI_TRANSPORTS = new Set(["auto", "sse", "websocket", "websocket-cached"]);
4
+
5
+ /**
6
+ * Normalize the public runtime option at the untyped JS boundary. Typed/config
7
+ * callers already validate it; direct JavaScript callers fail safely to Pi's
8
+ * compatibility-preserving automatic transport selection.
9
+ * @param {unknown} value
10
+ * @returns {"auto" | "sse" | "websocket" | "websocket-cached"}
11
+ */
12
+ export function resolvePiTransport(value) {
13
+ return typeof value === "string" && PI_TRANSPORTS.has(value)
14
+ ? /** @type {"auto" | "sse" | "websocket" | "websocket-cached"} */ (value)
15
+ : "auto";
16
+ }
@@ -147,10 +147,19 @@ export async function buildTurnTools(runState, {
147
147
  export function thinkingLevelForEffort(effort, capabilities) {
148
148
  if (!capabilities?.reasoning || capabilities.reasoning_mode === "none") return "off";
149
149
  if (effort === "none") return "off";
150
- if (effort === "max") return "xhigh";
150
+ // Pi <0.80.6 and older/custom model metadata do not advertise native max.
151
+ // Preserve the historical xhigh ceiling for those models, but pass max
152
+ // through when the resolved model explicitly declares it.
153
+ if (effort === "max") {
154
+ return Array.isArray(capabilities.reasoning_levels)
155
+ && capabilities.reasoning_levels.includes("max")
156
+ ? "max"
157
+ : "xhigh";
158
+ }
151
159
  if (effort === "xhigh") return "xhigh";
152
160
  if (effort === "high") return "high";
153
161
  if (effort === "medium") return "medium";
162
+ if (effort === "minimal") return "minimal";
154
163
  return "low";
155
164
  }
156
165
 
@@ -172,6 +181,7 @@ export function buildTurnHarness(runState, {
172
181
  systemPrompt,
173
182
  outputSchema,
174
183
  tools,
184
+ transport,
175
185
  maxRetries,
176
186
  maxRetryDelayMs,
177
187
  steeringMode,
@@ -187,7 +197,7 @@ export function buildTurnHarness(runState, {
187
197
  thinkingLevel,
188
198
  systemPrompt: appendStructuredOutputInstruction(systemPrompt, outputSchema, options.prompts),
189
199
  tools,
190
- streamOptions: { maxRetries, maxRetryDelayMs },
200
+ streamOptions: { transport, maxRetries, maxRetryDelayMs },
191
201
  steeringMode,
192
202
  followUpMode: steeringMode,
193
203
  });
@@ -34,7 +34,7 @@ import {
34
34
  import { closePiMcpClients } from "../../agent/tools/pi-bridge.js";
35
35
  import { createApprovalManager } from "../../agent/approval.js";
36
36
  import { buildCapabilitiesUsed, toolCompactionAppliedFromWarnings } from "../runtime/capabilities-used.js";
37
- import { resolvePiRuntimeModel } from "./pi-models.js";
37
+ import { reasoningLevelsForPiModel, resolvePiRuntimeModel } from "./pi-models.js";
38
38
  import {
39
39
  textFromContent,
40
40
  thinkingFromContent,
@@ -76,6 +76,7 @@ import {
76
76
  startLiveInput,
77
77
  thinkingLevelForEffort,
78
78
  } from "./pi-native/turn-runner.js";
79
+ import { resolvePiTransport } from "./pi-native/transport.js";
79
80
 
80
81
  async function resolveApiKey(provider, { apiKeys, resolvePiApiKey, runtimeWarnings }) {
81
82
  if (apiKeys?.has(provider)) return apiKeys.get(provider);
@@ -302,6 +303,7 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
302
303
  let structuredOutputFinalizationRetryAttempts = 0;
303
304
  let structuredOutputFinalizationRetryReason = null;
304
305
  let structuredOutputFinalizationRetryFailed = false;
306
+ const piTransport = resolvePiTransport(options.piTransport);
305
307
 
306
308
  const onEvent = (event) => emitCaptured(events, options.onEvent, event);
307
309
  const approvalManager = options.onToolApprovalRequest
@@ -316,7 +318,7 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
316
318
  : null;
317
319
 
318
320
  if (options.abortSignal?.aborted) {
319
- return abortedResult({ resolved, options, events, runtimeWarnings, start, providerSessionId });
321
+ return abortedResult({ resolved, options, events, runtimeWarnings, start, providerSessionId, piTransport });
320
322
  }
321
323
 
322
324
  const durableRepo = resolveDurableNativeSessionRepo(options.piSessionsRoot);
@@ -341,6 +343,7 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
341
343
  events,
342
344
  runtimeWarnings,
343
345
  start,
346
+ piTransport,
344
347
  });
345
348
  if (resolvedSession.done) return resolvedSession.result;
346
349
 
@@ -355,6 +358,9 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
355
358
  tool_use: true,
356
359
  reasoning: !!options.piResolvedModel.reasoning,
357
360
  reasoning_mode: options.piResolvedModel.reasoning ? "effort" : "none",
361
+ reasoning_levels: options.piResolvedModel.reasoning
362
+ ? reasoningLevelsForPiModel(options.piResolvedModel)
363
+ : undefined,
358
364
  json_mode: true,
359
365
  },
360
366
  apiKeys: new Map(),
@@ -432,6 +438,7 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
432
438
  systemPrompt,
433
439
  outputSchema: options.outputSchema,
434
440
  tools,
441
+ transport: piTransport,
435
442
  maxRetries,
436
443
  maxRetryDelayMs,
437
444
  steeringMode: toolSteeringMode,
@@ -484,7 +491,7 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
484
491
  // and closes MCP clients. For a resume no transcript was appended yet
485
492
  // (prompt never ran), so the live session needs no rollback.
486
493
  await discardUncommittedSession(runState, { durableRepo });
487
- return abortedResult({ resolved, options, events, runtimeWarnings, start, providerSessionId });
494
+ return abortedResult({ resolved, options, events, runtimeWarnings, start, providerSessionId, piTransport });
488
495
  }
489
496
 
490
497
  // Compaction policy against the LIVE model's context window, then proactive
@@ -619,6 +626,7 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
619
626
  runAssistantCount,
620
627
  externalAbort: runState.externalAbort,
621
628
  maxRetries,
629
+ piTransport,
622
630
  lastToolName: runState.lastToolName,
623
631
  structuredRetry,
624
632
  contextCompactionDiagnostics: runState.compaction.diagnostics,
@@ -737,6 +745,7 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
737
745
  providerSessionId,
738
746
  runtimeWarnings,
739
747
  isRetryable,
748
+ piTransport,
740
749
  });
741
750
  } finally {
742
751
  if (runState.sessionEntry) runState.sessionEntry.busy = false;
@@ -1,7 +1,10 @@
1
1
  /**
2
2
  * Preserve the provider default when effort is omitted. The current Agent SDK
3
- * accepts the five values below verbatim; mono-agent must not infer thinking
4
- * enablement/disablement from a requested effort level.
3
+ * public effort contract accepts the five values below. Its shipped JavaScript
4
+ * currently forwards out-of-contract values to Claude Code, so mono-agent keeps
5
+ * this route inside the pinned public contract rather than relying on that
6
+ * untyped pass-through. Mono-agent must not infer thinking enablement/disablement
7
+ * from a requested effort level.
5
8
  * @param {unknown} effort
6
9
  * @returns {{effort?: "low" | "medium" | "high" | "xhigh" | "max"}}
7
10
  */
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Translate Pi's model-native thinking levels to mono-agent's public effort
3
+ * spelling. Pi calls the disabled level `off`; mono-agent calls it `none`.
4
+ * Keeping this derived from the model lets new native levels (such as `max`)
5
+ * flow through without maintaining a second hard-coded catalog.
6
+ * @param {any} model
7
+ * @returns {string[]}
8
+ */
9
+ export function reasoningLevelsForPiModel(model: any): string[];
1
10
  export function resolvePiRuntimeModel(resolved: any, options: any): {
2
11
  model: {
3
12
  id: any;
@@ -53,15 +53,16 @@ export function emitCapabilitiesResolved(onEvent: (event: any) => void, { sdk, m
53
53
  }): void;
54
54
  /**
55
55
  * The aborted-run result (entry pre-check / pre-request abort). Pure factory.
56
- * @param {{resolved: any, options: any, events: any[], runtimeWarnings: any[], start: number, providerSessionId: string}} params
56
+ * @param {{resolved: any, options: any, events: any[], runtimeWarnings: any[], start: number, providerSessionId: string, piTransport: string}} params
57
57
  */
58
- export function abortedResult({ resolved, options, events, runtimeWarnings, start, providerSessionId }: {
58
+ export function abortedResult({ resolved, options, events, runtimeWarnings, start, providerSessionId, piTransport }: {
59
59
  resolved: any;
60
60
  options: any;
61
61
  events: any[];
62
62
  runtimeWarnings: any[];
63
63
  start: number;
64
64
  providerSessionId: string;
65
+ piTransport: string;
65
66
  }): {
66
67
  text: any;
67
68
  thinking: string;
@@ -81,6 +82,7 @@ export function abortedResult({ resolved, options, events, runtimeWarnings, star
81
82
  provider_session_id: string;
82
83
  pi_stop_reason: string;
83
84
  pi_engine: string;
85
+ pi_transport_requested: string;
84
86
  external_abort: boolean;
85
87
  };
86
88
  };
@@ -140,6 +142,7 @@ export function buildErrorResult(params: object): {
140
142
  max_turns_hit: any;
141
143
  provider_session_id: any;
142
144
  pi_engine: string;
145
+ pi_transport_requested: any;
143
146
  pi_error_retryable: any;
144
147
  };
145
148
  failureKind: string;
@@ -149,6 +152,7 @@ export function buildErrorResult(params: object): {
149
152
  provider_session_id: any;
150
153
  pi_stop_reason: string;
151
154
  pi_engine: string;
155
+ pi_transport_requested: any;
152
156
  max_turns_hit: any;
153
157
  turn_count: any;
154
158
  external_abort: any;
@@ -17,7 +17,7 @@ export function retireDurableNativeSession(providerSessionId: any, piSessionsRoo
17
17
  * @param {any} params
18
18
  * @returns {Promise<{done: true, result: any} | {done: false}>}
19
19
  */
20
- export function resolveSession(runState: any, { requestedSessionId, providerSessionId, durableRepo, sessionTtlMs, cwd, resolved, options, events, runtimeWarnings, start, }: any): Promise<{
20
+ export function resolveSession(runState: any, { requestedSessionId, providerSessionId, durableRepo, sessionTtlMs, cwd, resolved, options, events, runtimeWarnings, start, piTransport, }: any): Promise<{
21
21
  done: true;
22
22
  result: any;
23
23
  } | {
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Normalize the public runtime option at the untyped JS boundary. Typed/config
3
+ * callers already validate it; direct JavaScript callers fail safely to Pi's
4
+ * compatibility-preserving automatic transport selection.
5
+ * @param {unknown} value
6
+ * @returns {"auto" | "sse" | "websocket" | "websocket-cached"}
7
+ */
8
+ export function resolvePiTransport(value: unknown): "auto" | "sse" | "websocket" | "websocket-cached";
@@ -30,7 +30,7 @@ export function thinkingLevelForEffort(effort: string, capabilities: any): strin
30
30
  * @param {any} params
31
31
  * @returns {any}
32
32
  */
33
- export function buildTurnHarness(runState: any, { cwd, session, piModels, model, thinkingLevel, systemPrompt, outputSchema, tools, maxRetries, maxRetryDelayMs, steeringMode, onEvent, options, toolLimits, }: any): any;
33
+ export function buildTurnHarness(runState: any, { cwd, session, piModels, model, thinkingLevel, systemPrompt, outputSchema, tools, transport, maxRetries, maxRetryDelayMs, steeringMode, onEvent, options, toolLimits, }: any): any;
34
34
  /**
35
35
  * Start the live-input steering consumer. Consumes follow-up messages and steers
36
36
  * the harness mid-run; the consumer is tied to run completion (an internal