@mono-agent/agent-runtime 0.13.0 → 0.15.0

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.
@@ -33,6 +33,7 @@ import {
33
33
  prepareCompaction,
34
34
  shouldCompact,
35
35
  } from "@earendil-works/pi-agent-core";
36
+ import { randomUUID } from "node:crypto";
36
37
  import {
37
38
  estimateFixedOverheadTokens,
38
39
  isLikelyContextTermination,
@@ -204,6 +205,52 @@ function previewCompactedContext(branchEntries, result) {
204
205
  return estimateBuiltContextTokens([...branchEntries, previewEntry]);
205
206
  }
206
207
 
208
+ function canonicalCompactionTrigger(trigger) {
209
+ return trigger === "reactive_overflow" ? "overflow" : trigger;
210
+ }
211
+
212
+ function finiteTokenCount(value) {
213
+ if (value === null || value === undefined) return undefined;
214
+ const count = Number(value);
215
+ return Number.isFinite(count) && count >= 0 ? count : undefined;
216
+ }
217
+
218
+ /**
219
+ * @param {((event: any) => void)|undefined} onEvent
220
+ * @param {{operationId: string, status: string, trigger: string, model?: string, tokensBefore?: number|null, tokensAfter?: number|null, reason?: string, message?: string}} event
221
+ */
222
+ function emitCompactionEvent(onEvent, {
223
+ operationId,
224
+ status,
225
+ trigger,
226
+ model,
227
+ tokensBefore,
228
+ tokensAfter,
229
+ reason,
230
+ message,
231
+ }) {
232
+ const before = finiteTokenCount(tokensBefore);
233
+ const after = finiteTokenCount(tokensAfter);
234
+ try {
235
+ onEvent?.({
236
+ type: "context_compaction",
237
+ operationId,
238
+ status,
239
+ sdk: "pi",
240
+ trigger: canonicalCompactionTrigger(trigger),
241
+ timestamp: Date.now(),
242
+ ...(model ? { model } : {}),
243
+ ...(before === undefined ? {} : { tokensBefore: before }),
244
+ ...(after === undefined ? {} : { tokensAfter: after }),
245
+ ...(before === undefined && after === undefined ? {} : { tokenCountsExact: false }),
246
+ ...(reason ? { reason } : {}),
247
+ ...(message ? { message } : {}),
248
+ });
249
+ } catch {
250
+ // Observability must never change whether compaction itself succeeds.
251
+ }
252
+ }
253
+
207
254
  // Run a single guarded compaction. Requires the harness idle (callers
208
255
  // waitForIdle first). Never throws — classifies AgentHarnessError into a warning
209
256
  // and reports back whether anything was compacted. Fires onCompactionRecorded on
@@ -218,14 +265,22 @@ export async function tryCompact(harness, {
218
265
  session,
219
266
  policy,
220
267
  }) {
221
- const adaptivePolicy = resolveAgentCompactionPolicy({}, {
222
- contextWindow: typeof harness?.getModel === "function" ? harness.getModel()?.contextWindow : undefined,
268
+ const operationId = randomUUID();
269
+ emitCompactionEvent(onEvent, {
270
+ operationId,
271
+ status: "running",
272
+ trigger,
273
+ model,
223
274
  });
224
- const effectivePolicy = { ...adaptivePolicy, ...(policy || {}) };
275
+ let effectivePolicy = policy || {};
225
276
  /** @type {null | {kind: string, tokensBefore?: number|null, tokensAfter?: number|null, savings?: number|null, error?: any}} */
226
277
  let hookDecision = null;
227
278
  let removeHook = null;
228
279
  try {
280
+ const adaptivePolicy = resolveAgentCompactionPolicy({}, {
281
+ contextWindow: typeof harness?.getModel === "function" ? harness.getModel()?.contextWindow : undefined,
282
+ });
283
+ effectivePolicy = { ...adaptivePolicy, ...(policy || {}) };
229
284
  if (typeof harness?.on !== "function") {
230
285
  throw new Error("Pi AgentHarness does not expose session_before_compact hooks");
231
286
  }
@@ -298,14 +353,13 @@ export async function tryCompact(harness, {
298
353
  const reduced = measuredTokensBefore === null || tokensAfter === null
299
354
  ? null
300
355
  : tokensAfter < measuredTokensBefore;
301
- onEvent?.({
302
- type: "runtime_warning",
303
- warning_kind: "context_compaction_applied",
304
- source: "pi",
356
+ emitCompactionEvent(onEvent, {
357
+ operationId,
358
+ status: "succeeded",
305
359
  trigger,
306
- tokens_before: tokensBefore,
307
- tokens_after: tokensAfter,
308
- reduced,
360
+ model,
361
+ tokensBefore,
362
+ tokensAfter,
309
363
  });
310
364
  if (reduced === false) {
311
365
  runtimeWarnings?.push({
@@ -354,6 +408,15 @@ export async function tryCompact(harness, {
354
408
  ? { minimum_savings_tokens: effectivePolicy.compactionMinSavingsTokens }
355
409
  : {}),
356
410
  });
411
+ emitCompactionEvent(onEvent, {
412
+ operationId,
413
+ status: "skipped",
414
+ trigger,
415
+ model,
416
+ tokensBefore: hookDecision.tokensBefore,
417
+ tokensAfter: hookDecision.tokensAfter,
418
+ reason: hookDecision.kind,
419
+ });
357
420
  return {
358
421
  applied: false,
359
422
  tokensBefore: hookDecision.tokensBefore ?? null,
@@ -369,6 +432,13 @@ export async function tryCompact(harness, {
369
432
  trigger,
370
433
  message: "Nothing to compact",
371
434
  });
435
+ emitCompactionEvent(onEvent, {
436
+ operationId,
437
+ status: "skipped",
438
+ trigger,
439
+ model,
440
+ reason: "nothing_to_compact",
441
+ });
372
442
  return { applied: false, tokensBefore: null, tokensAfter: null, reduced: null, nothingToCompact: true };
373
443
  }
374
444
  const effectiveError = hookDecision?.kind === "failed" && hookDecision.error
@@ -385,6 +455,32 @@ export async function tryCompact(harness, {
385
455
  ? "context_compaction_busy"
386
456
  : "context_compaction_failed";
387
457
  runtimeWarnings?.push({ warning_kind: warningKind, source: "pi", trigger, message });
458
+ emitCompactionEvent(onEvent, {
459
+ operationId,
460
+ status: nothingToCompact ? "skipped" : "failed",
461
+ trigger,
462
+ model,
463
+ reason: nothingToCompact
464
+ ? "nothing_to_compact"
465
+ : code === "auth"
466
+ ? "authentication"
467
+ : code === "busy"
468
+ ? "busy"
469
+ : code === "aborted"
470
+ ? "cancelled"
471
+ : "provider_error",
472
+ ...(nothingToCompact
473
+ ? {}
474
+ : {
475
+ message: code === "auth"
476
+ ? "Compaction authentication failed."
477
+ : code === "busy"
478
+ ? "Context was busy and could not be compacted."
479
+ : code === "aborted"
480
+ ? "Compaction was cancelled."
481
+ : "Compaction failed.",
482
+ }),
483
+ });
388
484
  return { applied: false, tokensBefore: null, tokensAfter: null, reduced: null, nothingToCompact };
389
485
  } finally {
390
486
  removeHook?.();
@@ -33,7 +33,7 @@ export function usageFromMessages(messages = []) {
33
33
  }
34
34
 
35
35
  /**
36
- * Normalize the final provider request's usage into an exact context snapshot.
36
+ * Normalize one provider request's usage into an exact context snapshot.
37
37
  * Unlike usageFromMessages(), this deliberately does not aggregate earlier
38
38
  * requests in the run: the last assistant usage is the same provider-counted
39
39
  * value Pi's compaction logic trusts, so it can decrease after compaction.
@@ -74,15 +74,13 @@ export function failureKindForPiError(message, diagnostics, { maxTurnsHit = fals
74
74
 
75
75
  /**
76
76
  * Emit the per-run cache / cost / provider-completed events.
77
- * @param {{onEvent: (event: any) => void, resolved: any, reference: string, usage: {input: number, output: number, cacheRead: number, cacheWrite: number, cost: number}, contextUsage?: {input: number, output: number, cacheRead: number, cacheCreation: number, total: number}|null, contextWindow?: number, estimatedCost: number, start: number, externalAbort: boolean}} params
77
+ * @param {{onEvent: (event: any) => void, resolved: any, reference: string, usage: {input: number, output: number, cacheRead: number, cacheWrite: number, cost: number}, estimatedCost: number, start: number, externalAbort: boolean}} params
78
78
  */
79
79
  export function emitUsageCostEvents({
80
80
  onEvent,
81
81
  resolved,
82
82
  reference,
83
83
  usage,
84
- contextUsage,
85
- contextWindow,
86
84
  estimatedCost,
87
85
  start,
88
86
  externalAbort,
@@ -105,16 +103,6 @@ export function emitUsageCostEvents({
105
103
  cacheCreationTokens: Number(usage.cacheWrite) || 0,
106
104
  },
107
105
  });
108
- if (contextUsage) {
109
- const effectiveContextWindow = Number(contextWindow) || 0;
110
- onEvent({
111
- type: "context_usage",
112
- sdk: resolved.sdk,
113
- model: reference,
114
- ...(effectiveContextWindow > 0 ? { contextWindow: effectiveContextWindow } : {}),
115
- tokens: contextUsage,
116
- });
117
- }
118
106
  onEvent({
119
107
  type: "provider_request_completed",
120
108
  sdk: resolved.sdk,
@@ -13,6 +13,7 @@ import {
13
13
  jsonSerializable,
14
14
  streamContentKey,
15
15
  } from "../pi-events.js";
16
+ import { contextUsageFromAssistantMessage } from "./result-builder.js";
16
17
 
17
18
  function toolResultFileChange(result) {
18
19
  const fileChange = result?.details?.file_change;
@@ -41,10 +42,10 @@ function toolResultFileChange(result) {
41
42
  * abort; it is already constructed when this is wired (subscribe follows the
42
43
  * AgentHarness constructor).
43
44
  * @param {StreamSubscriberState} runState
44
- * @param {{onEvent: (event: any) => void, options: any, toolLimits: any, harness: any}} deps
45
+ * @param {{onEvent: (event: any) => void, options: any, toolLimits: any, harness: any, sdk: string, model: string}} deps
45
46
  * @returns {(event: any) => void}
46
47
  */
47
- export function createStreamSubscriber(runState, { onEvent, options, toolLimits, harness }) {
48
+ export function createStreamSubscriber(runState, { onEvent, options, toolLimits, harness, sdk, model }) {
48
49
  return (event) => {
49
50
  if (event.type === "message_update") {
50
51
  const streamEvent = event.assistantMessageEvent;
@@ -69,6 +70,23 @@ export function createStreamSubscriber(runState, { onEvent, options, toolLimits,
69
70
  onEvent({ type: "assistant", message: { content: [{ type: "thinking", text: streamEvent.content }] } });
70
71
  }
71
72
  }
73
+ } else if (event.type === "message_end") {
74
+ const contextUsage = contextUsageFromAssistantMessage(event.message);
75
+ if (contextUsage) {
76
+ const contextWindow = Number(harness?.getModel?.()?.contextWindow) || 0;
77
+ const measurementId = typeof event.message?.id === "string" && event.message.id.trim().length > 0
78
+ ? event.message.id
79
+ : undefined;
80
+ onEvent({
81
+ type: "context_usage",
82
+ sdk,
83
+ model,
84
+ timestamp: Date.now(),
85
+ ...(measurementId === undefined ? {} : { measurementId }),
86
+ ...(contextWindow > 0 ? { contextWindow } : {}),
87
+ tokens: contextUsage,
88
+ });
89
+ }
72
90
  } else if (event.type === "tool_execution_start") {
73
91
  if (event.toolName) runState.lastToolName = event.toolName;
74
92
  if (event.toolCallId) runState.toolStartTimes.set(event.toolCallId, Date.now());
@@ -205,6 +205,8 @@ export function buildTurnHarness(runState, {
205
205
  onEvent,
206
206
  options,
207
207
  toolLimits,
208
+ sdk,
209
+ reference,
208
210
  }) {
209
211
  const harness = new AgentHarness({
210
212
  env: new NodeExecutionEnv({ cwd: cwd || process.cwd() }),
@@ -228,7 +230,14 @@ export function buildTurnHarness(runState, {
228
230
  : undefined);
229
231
  runState.harness = harness;
230
232
 
231
- harness.subscribe(createStreamSubscriber(runState, { onEvent, options, toolLimits, harness }));
233
+ harness.subscribe(createStreamSubscriber(runState, {
234
+ onEvent,
235
+ options,
236
+ toolLimits,
237
+ harness,
238
+ sdk,
239
+ model: reference,
240
+ }));
232
241
 
233
242
  const abortHandler = () => {
234
243
  runState.externalAbort = true;
@@ -255,12 +264,24 @@ export function startLiveInput({ harness, options, onEvent }) {
255
264
  ? options.liveInput[Symbol.asyncIterator]()
256
265
  : options.liveInput;
257
266
  let runComplete = false;
267
+ /** @type {() => void} */
268
+ let signalStop = () => {};
269
+ const stopped = new Promise((resolve) => { signalStop = () => resolve(); });
258
270
  const task = (async () => {
259
271
  try {
260
272
  while (!runComplete && !options.abortSignal?.aborted) {
261
- const next = await iterator.next();
273
+ const next = await Promise.race([
274
+ iterator.next(),
275
+ stopped.then(() => ({ done: true, value: undefined })),
276
+ ]);
262
277
  if (next.done || runComplete || options.abortSignal?.aborted) break;
263
- await harness.steer(formatLiveInputGuidance(next.value.body, options.prompts));
278
+ try {
279
+ await harness.steer(formatLiveInputGuidance(next.value.body, options.prompts));
280
+ next.value.acknowledge?.();
281
+ } catch (err) {
282
+ next.value.reject?.(err);
283
+ throw err;
284
+ }
264
285
  }
265
286
  } catch (err) {
266
287
  onEvent({
@@ -273,15 +294,17 @@ export function startLiveInput({ harness, options, onEvent }) {
273
294
  return {
274
295
  // The run is done: stop the live-steering consumer so it cannot steer a
275
296
  // finished harness or swallow a follow-up meant for the next turn. We signal
276
- // completion, then best-effort return() the iterator to unblock a pending
277
- // next(). We do NOT await the task (it could block on next() if the source
278
- // has no return()), but the runComplete guard prevents any further steering.
297
+ // completion, then best-effort return() the iterator. The explicit stop
298
+ // race releases the task even when a third-party iterator's return() does
299
+ // not unblock its pending next(); awaiting the task still closes any steer
300
+ // acknowledgement already in progress.
279
301
  stop: async () => {
280
302
  runComplete = true;
303
+ signalStop();
281
304
  if (iterator && typeof iterator.return === "function") {
282
- try { await iterator.return(); } catch { /* best-effort */ }
305
+ try { void Promise.resolve(iterator.return()).catch(() => {}); } catch { /* best-effort */ }
283
306
  }
284
- void task;
307
+ await task;
285
308
  },
286
309
  };
287
310
  }
@@ -52,7 +52,6 @@ import {
52
52
  buildErrorDetails,
53
53
  buildErrorResult,
54
54
  buildSuccessResult,
55
- contextUsageFromAssistantMessage,
56
55
  emitCapabilitiesResolved,
57
56
  emitUsageCostEvents,
58
57
  usageFromMessages,
@@ -453,6 +452,8 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
453
452
  onEvent,
454
453
  options,
455
454
  toolLimits,
455
+ sdk: resolved.sdk,
456
+ reference,
456
457
  });
457
458
 
458
459
  // Seed prior transcript (everything before the trailing user turn) into the
@@ -614,10 +615,6 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
614
615
  resolved,
615
616
  reference,
616
617
  usage,
617
- contextUsage: runState.externalAbort || runState.maxTurnsHit || runError
618
- ? null
619
- : contextUsageFromAssistantMessage(lastAssistant),
620
- contextWindow: runState.compaction.policy?.contextWindow,
621
618
  estimatedCost,
622
619
  start,
623
620
  externalAbort: runState.externalAbort,
@@ -123,7 +123,7 @@ export const RESERVED_RUNTIME_KINDS = [...RESERVED_RUNTIME_IDS];
123
123
  // sdk='claude' → CLI (claude binary) or SDK (Anthropic)
124
124
  // sdk='codex' → CLI only (codex app-server)
125
125
  // sdk='opencode' → CLI only (opencode server via @opencode-ai/sdk)
126
- // sdk='pi' → SDK only (pi-sdk handles openai-codex and other providers)
126
+ // sdk='pi' → SDK only (the pi-native bridge handles openai-codex and other providers)
127
127
 
128
128
  // Returns null when the combo is fine; otherwise a short reason string the
129
129
  // UI / API can show.
@@ -29,7 +29,14 @@ const builtinBridgeSpecs = {
29
29
  id: "claude-code",
30
30
  supports: (ref, options) => ref?.sdk === "claude" && options?.executionMode === "cli",
31
31
  // The claude CLI resumes prior sessions via `--resume <sessionId>`.
32
- capabilities: () => ({ kind: "claude-code", runtime: "cli", ...COMMON_CAPABILITIES, supports_session_resume: true }),
32
+ capabilities: () => ({
33
+ kind: "claude-code",
34
+ runtime: "cli",
35
+ ...COMMON_CAPABILITIES,
36
+ supports_session_resume: true,
37
+ // The one-shot CLI bridge has no bidirectional stdin steering channel.
38
+ supports_live_input: false,
39
+ }),
33
40
  load: async () => (await import("../providers/claude-cli.js")).claudeCodeRuntimeBridge,
34
41
  },
35
42
  "codex-app": {
package/src/ai/types.js CHANGED
@@ -133,7 +133,7 @@
133
133
  * @property {string} [providerSessionId] Provider-owned resume id for resumable bridges.
134
134
  * @property {boolean} [sessionKeepAlive] Keep resumable provider state alive after the turn.
135
135
  * @property {number} [sessionIdleTimeoutMs] Idle TTL for resumable provider state.
136
- * @property {boolean} [liveInput] Whether this run expects a live/streaming input channel.
136
+ * @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.
137
137
  * @property {ReadonlyArray<*>} [observers] Per-call observers (see RuntimeObserver) merged with host-level (createRuntime) observers.
138
138
  * @property {(event: RuntimeEvent) => void} [onEvent]
139
139
  * @property {ReadonlyArray<Object>} [messages]
package/src/runtime.js CHANGED
@@ -8,10 +8,10 @@
8
8
  // method that resolves the right provider bridge based on `options.model` +
9
9
  // `options.executionMode`.
10
10
  //
11
- // The built-in bridges (claude-sdk, claude-cli, pi-native, codex-app,
12
- // opencode-app) register themselves on import via the runtime registry. Hosts
13
- // that need
14
- // finer control can keep using the named exports (resolveRuntimeBridge,
11
+ // The runtime registry contains a static table for the five built-in bridges
12
+ // (claude-sdk, claude-cli, pi-native, codex-app, opencode-app) and lazily imports
13
+ // the matching implementation only when a run selects it. Hosts that need finer
14
+ // control can keep using the named exports (resolveRuntimeBridge,
15
15
  // generateClaudeResponse, etc.) directly.
16
16
  //
17
17
  // Return shape from `.run()`:
@@ -1,4 +1,3 @@
1
- export * from "./registry.js";
2
1
  export * from "./runtime/model-refs.js";
3
2
  export * from "./runtime/registry.js";
4
3
  export { createSessionRegistry, disposeAllProviderSessions, disposeProviderSession, invalidateProviderSession, refreshProviderSession, syncProviderSession } from "./runtime/sessions.js";
@@ -14,8 +14,9 @@ export function createObserverHub({ observers, onEvent }?: {
14
14
  flush: () => Promise<void>;
15
15
  observers: () => any[];
16
16
  };
17
- export function createMetricsObserver({ name }?: {
17
+ export function createMetricsObserver({ name, maxLatencySamples }?: {
18
18
  name?: string;
19
+ maxLatencySamples?: number;
19
20
  }): {
20
21
  name: string;
21
22
  recordEvent: (event: any) => void;
@@ -49,7 +50,8 @@ export function createMetricsObserver({ name }?: {
49
50
  byKind: any;
50
51
  };
51
52
  turns: {
52
- count: number;
53
+ count: any;
54
+ sampleCount: number;
53
55
  latencyMsP50: any;
54
56
  latencyMsP95: any;
55
57
  };
@@ -155,9 +155,10 @@ export function generateCliResponse(systemPrompt: any, options?: {}): Promise<{
155
155
  context_compaction_applied: any;
156
156
  };
157
157
  }>;
158
- export namespace claudeCodeBackend {
159
- export let kind: string;
160
- export namespace capabilities {
158
+ export namespace claudeCodeRuntimeBridge {
159
+ let id: string;
160
+ let kind: string;
161
+ namespace capabilities {
161
162
  export let streaming: boolean;
162
163
  export let structured_output: boolean;
163
164
  export let supports_session_resume: boolean;
@@ -171,33 +172,8 @@ export namespace claudeCodeBackend {
171
172
  export { kind_1 as kind };
172
173
  export let runtime: string;
173
174
  }
174
- export { generateCliResponse as execute };
175
- }
176
- export namespace codexCliBackend {
177
- let kind_2: string;
178
- export { kind_2 as kind };
179
- export namespace capabilities_1 {
180
- let kind_3: string;
181
- export { kind_3 as kind };
182
- let runtime_1: string;
183
- export { runtime_1 as runtime };
184
- }
185
- export { capabilities_1 as capabilities };
186
- export { generateCliResponse as execute };
187
- }
188
- export namespace claudeCodeRuntimeBridge {
189
- export let id: string;
190
- let kind_4: string;
191
- export { kind_4 as kind };
192
- export namespace capabilities_2 {
193
- let kind_5: string;
194
- export { kind_5 as kind };
195
- let runtime_2: string;
196
- export { runtime_2 as runtime };
197
- }
198
- export { capabilities_2 as capabilities };
199
- export function supports(ref: any, options: any): boolean;
200
- export function execute(systemPrompt: any, options: any): Promise<{
175
+ function supports(ref: any, options: any): boolean;
176
+ function execute(systemPrompt: any, options: any): Promise<{
201
177
  text: any;
202
178
  structuredResult: any;
203
179
  structuredResultSource: any;
@@ -129,17 +129,10 @@ export function generateClaudeResponse(systemPrompt: any, options: any): Promise
129
129
  context_compaction_applied: any;
130
130
  };
131
131
  }>;
132
- export namespace claudeSdkBackend {
133
- export let kind: string;
134
- export let capabilities: any;
135
- export { generateClaudeResponse as execute };
136
- }
137
132
  export namespace claudeRuntimeBridge {
138
133
  export let id: string;
139
- let kind_1: string;
140
- export { kind_1 as kind };
141
- let capabilities_1: any;
142
- export { capabilities_1 as capabilities };
134
+ export let kind: string;
135
+ export let capabilities: any;
143
136
  export function supports(ref: any): boolean;
144
137
  export { generateClaudeResponse as execute };
145
138
  }
@@ -62,7 +62,7 @@ export function generateCodexAppResponse(systemPrompt: any, options?: {}): Promi
62
62
  };
63
63
  durationMs: number;
64
64
  numTurns: number;
65
- model: string;
65
+ model: any;
66
66
  effort: any;
67
67
  sdk: string;
68
68
  providerSessionId: any;
@@ -124,22 +124,16 @@ export function generateCodexAppResponse(systemPrompt: any, options?: {}): Promi
124
124
  context_compaction_applied: any;
125
125
  };
126
126
  }>;
127
- export namespace codexAppBackend {
128
- export let kind: string;
129
- export { CODEX_APP_CAPABILITIES as capabilities };
130
- export { generateCodexAppResponse as execute };
131
- }
132
127
  export namespace codexAppRuntimeBridge {
133
128
  export let id: string;
134
- let kind_1: string;
135
- export { kind_1 as kind };
129
+ export let kind: string;
136
130
  export { CODEX_APP_CAPABILITIES as capabilities };
137
131
  export function supports(ref: any, options: any): boolean;
138
132
  export { generateCodexAppResponse as execute };
139
133
  }
140
134
  declare namespace CODEX_APP_CAPABILITIES {
141
- let kind_2: string;
142
- export { kind_2 as kind };
135
+ let kind_1: string;
136
+ export { kind_1 as kind };
143
137
  export let runtime: string;
144
138
  export let streaming: boolean;
145
139
  export let structured_output: boolean;
@@ -1,4 +1,3 @@
1
- export function promptTextFromMessages(messages: any): string;
2
1
  export function toAgentMessages(messages: any, model: any): any[];
3
2
  export function textFromContent(content: any): string;
4
3
  export function thinkingFromContent(content: any): string;
@@ -11,7 +11,7 @@ export function usageFromMessages(messages?: Array<any>): {
11
11
  cost: number;
12
12
  };
13
13
  /**
14
- * Normalize the final provider request's usage into an exact context snapshot.
14
+ * Normalize one provider request's usage into an exact context snapshot.
15
15
  * Unlike usageFromMessages(), this deliberately does not aggregate earlier
16
16
  * requests in the run: the last assistant usage is the same provider-counted
17
17
  * value Pi's compaction logic trusts, so it can decrease after compaction.
@@ -40,9 +40,9 @@ export function failureKindForPiError(message: string | null, diagnostics: Recor
40
40
  }): string | null;
41
41
  /**
42
42
  * Emit the per-run cache / cost / provider-completed events.
43
- * @param {{onEvent: (event: any) => void, resolved: any, reference: string, usage: {input: number, output: number, cacheRead: number, cacheWrite: number, cost: number}, contextUsage?: {input: number, output: number, cacheRead: number, cacheCreation: number, total: number}|null, contextWindow?: number, estimatedCost: number, start: number, externalAbort: boolean}} params
43
+ * @param {{onEvent: (event: any) => void, resolved: any, reference: string, usage: {input: number, output: number, cacheRead: number, cacheWrite: number, cost: number}, estimatedCost: number, start: number, externalAbort: boolean}} params
44
44
  */
45
- export function emitUsageCostEvents({ onEvent, resolved, reference, usage, contextUsage, contextWindow, estimatedCost, start, externalAbort, }: {
45
+ export function emitUsageCostEvents({ onEvent, resolved, reference, usage, estimatedCost, start, externalAbort, }: {
46
46
  onEvent: (event: any) => void;
47
47
  resolved: any;
48
48
  reference: string;
@@ -53,14 +53,6 @@ export function emitUsageCostEvents({ onEvent, resolved, reference, usage, conte
53
53
  cacheWrite: number;
54
54
  cost: number;
55
55
  };
56
- contextUsage?: {
57
- input: number;
58
- output: number;
59
- cacheRead: number;
60
- cacheCreation: number;
61
- total: number;
62
- } | null;
63
- contextWindow?: number;
64
56
  estimatedCost: number;
65
57
  start: number;
66
58
  externalAbort: boolean;
@@ -17,14 +17,16 @@
17
17
  * abort; it is already constructed when this is wired (subscribe follows the
18
18
  * AgentHarness constructor).
19
19
  * @param {StreamSubscriberState} runState
20
- * @param {{onEvent: (event: any) => void, options: any, toolLimits: any, harness: any}} deps
20
+ * @param {{onEvent: (event: any) => void, options: any, toolLimits: any, harness: any, sdk: string, model: string}} deps
21
21
  * @returns {(event: any) => void}
22
22
  */
23
- export function createStreamSubscriber(runState: StreamSubscriberState, { onEvent, options, toolLimits, harness }: {
23
+ export function createStreamSubscriber(runState: StreamSubscriberState, { onEvent, options, toolLimits, harness, sdk, model }: {
24
24
  onEvent: (event: any) => void;
25
25
  options: any;
26
26
  toolLimits: any;
27
27
  harness: any;
28
+ sdk: string;
29
+ model: string;
28
30
  }): (event: any) => void;
29
31
  /**
30
32
  * The slice of run state the stream subscriber reads and mutates. A structural
@@ -32,7 +32,7 @@ export function thinkingLevelForEffort(effort: string, capabilities: any): strin
32
32
  * @param {any} params
33
33
  * @returns {any}
34
34
  */
35
- export function buildTurnHarness(runState: any, { cwd, session, piModels, model, thinkingLevel, systemPrompt, outputSchema, tools, transport, maxRetries, maxRetryDelayMs, steeringMode, onEvent, options, toolLimits, }: any): any;
35
+ export function buildTurnHarness(runState: any, { cwd, session, piModels, model, thinkingLevel, systemPrompt, outputSchema, tools, transport, maxRetries, maxRetryDelayMs, steeringMode, onEvent, options, toolLimits, sdk, reference, }: any): any;
36
36
  /**
37
37
  * Start the live-input steering consumer. Consumes follow-up messages and steers
38
38
  * the harness mid-run; the consumer is tied to run completion (an internal
@@ -104,7 +104,7 @@
104
104
  * @property {string} [providerSessionId] Provider-owned resume id for resumable bridges.
105
105
  * @property {boolean} [sessionKeepAlive] Keep resumable provider state alive after the turn.
106
106
  * @property {number} [sessionIdleTimeoutMs] Idle TTL for resumable provider state.
107
- * @property {boolean} [liveInput] Whether this run expects a live/streaming input channel.
107
+ * @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.
108
108
  * @property {ReadonlyArray<*>} [observers] Per-call observers (see RuntimeObserver) merged with host-level (createRuntime) observers.
109
109
  * @property {(event: RuntimeEvent) => void} [onEvent]
110
110
  * @property {ReadonlyArray<Object>} [messages]
@@ -490,9 +490,15 @@ export type RuntimeRunOptions = {
490
490
  */
491
491
  sessionIdleTimeoutMs?: number;
492
492
  /**
493
- * Whether this run expects a live/streaming input channel.
493
+ * Stream of in-flight user messages for steering an active run. Providers acknowledge only after accepting a message into the active turn.
494
494
  */
495
- liveInput?: boolean;
495
+ liveInput?: AsyncIterable<{
496
+ body: string;
497
+ id?: string;
498
+ receivedAt?: string;
499
+ acknowledge?: () => void;
500
+ reject?: (error?: unknown) => void;
501
+ }>;
496
502
  /**
497
503
  * Per-call observers (see RuntimeObserver) merged with host-level (createRuntime) observers.
498
504
  */