@mono-agent/agent-runtime 0.11.5 → 0.13.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.
@@ -7,6 +7,7 @@
7
7
  // takes its inputs explicitly and returns the verbatim runtime-result contract
8
8
  // (diagnostics key spellings, error fields, and shape unchanged — I9).
9
9
 
10
+ import { calculateContextTokens } from "@earendil-works/pi-agent-core";
10
11
  import { isContextLimitError } from "../pi-errors.js";
11
12
  import { isLikelyContextTermination } from "../../../agent/compaction.js";
12
13
  import { isProviderAuthFailureText } from "../../failure.js";
@@ -32,8 +33,31 @@ export function usageFromMessages(messages = []) {
32
33
  }
33
34
 
34
35
  /**
35
- * Classify a pi error message into a runtime failure kind. Context-limit /
36
- * max-turns terminations map to usage_limit; credential/config auth failures
36
+ * Normalize the final provider request's usage into an exact context snapshot.
37
+ * Unlike usageFromMessages(), this deliberately does not aggregate earlier
38
+ * requests in the run: the last assistant usage is the same provider-counted
39
+ * value Pi's compaction logic trusts, so it can decrease after compaction.
40
+ * @param {any} assistantMessage
41
+ * @returns {{input: number, output: number, cacheRead: number, cacheCreation: number, total: number}|null}
42
+ */
43
+ export function contextUsageFromAssistantMessage(assistantMessage) {
44
+ if (assistantMessage?.role !== "assistant" || !assistantMessage.usage) return null;
45
+ if (assistantMessage.stopReason === "error" || assistantMessage.stopReason === "aborted") return null;
46
+ const total = Number(calculateContextTokens(assistantMessage.usage)) || 0;
47
+ if (total <= 0) return null;
48
+ return {
49
+ input: Number(assistantMessage.usage.input) || 0,
50
+ output: Number(assistantMessage.usage.output) || 0,
51
+ cacheRead: Number(assistantMessage.usage.cacheRead) || 0,
52
+ cacheCreation: Number(assistantMessage.usage.cacheWrite) || 0,
53
+ total,
54
+ };
55
+ }
56
+
57
+ /**
58
+ * Classify a pi error message into a runtime failure kind. Context-window
59
+ * overflows map to context_limit so the router can try the configured fallback;
60
+ * max-turns terminations remain usage_limit. Credential/config auth failures
37
61
  * map to provider_auth; everything else to provider_unavailable. Null message → null.
38
62
  * @param {string|null} message
39
63
  * @param {Record<string, unknown>} diagnostics
@@ -42,18 +66,27 @@ export function usageFromMessages(messages = []) {
42
66
  */
43
67
  export function failureKindForPiError(message, diagnostics, { maxTurnsHit = false } = {}) {
44
68
  if (!message) return null;
45
- if (maxTurnsHit || isContextLimitError(message) || isLikelyContextTermination(message, diagnostics)) {
46
- return "usage_limit";
47
- }
69
+ if (maxTurnsHit) return "usage_limit";
70
+ if (isContextLimitError(message) || isLikelyContextTermination(message, diagnostics)) return "context_limit";
48
71
  if (isProviderAuthFailureText(message)) return "provider_auth";
49
72
  return "provider_unavailable";
50
73
  }
51
74
 
52
75
  /**
53
76
  * Emit the per-run cache / cost / provider-completed events.
54
- * @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
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
55
78
  */
56
- export function emitUsageCostEvents({ onEvent, resolved, reference, usage, estimatedCost, start, externalAbort }) {
79
+ export function emitUsageCostEvents({
80
+ onEvent,
81
+ resolved,
82
+ reference,
83
+ usage,
84
+ contextUsage,
85
+ contextWindow,
86
+ estimatedCost,
87
+ start,
88
+ externalAbort,
89
+ }) {
57
90
  if (usage.cacheRead > 0) {
58
91
  onEvent({ type: "cache_hit", sdk: resolved.sdk, model: reference, tokens: usage.cacheRead, source: "prompt_cache" });
59
92
  }
@@ -72,6 +105,16 @@ export function emitUsageCostEvents({ onEvent, resolved, reference, usage, estim
72
105
  cacheCreationTokens: Number(usage.cacheWrite) || 0,
73
106
  },
74
107
  });
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
+ }
75
118
  onEvent({
76
119
  type: "provider_request_completed",
77
120
  sdk: resolved.sdk,
@@ -14,6 +14,7 @@ import {
14
14
  getPiBuiltinTools,
15
15
  initPiMcpTools,
16
16
  } from "../../../agent/tools/pi-bridge.js";
17
+ import { createNodeReplController } from "../../../agent/tools/node-repl.js";
17
18
  import { readToolRuntime } from "../../../agent/tools/shared/runtime-context.js";
18
19
  import { formatLiveInputGuidance } from "../../live-input-prompt.js";
19
20
  import { appendStructuredOutputInstruction } from "./structured-output.js";
@@ -24,10 +25,11 @@ import { createStreamSubscriber } from "./stream-subscriber.js";
24
25
  * tools, the MCP tool bridge, and the StructuredOutput tool (whose callback
25
26
  * writes runState.structuredResult). Surfaces MCP init/list failures to both the
26
27
  * event stream and runtimeWarnings. Returns the assembled tools plus the MCP
27
- * clients (closed by the caller's finally) and the structured tool.
28
+ * clients (closed by the caller's finally), run-owned tool cleanup, and the
29
+ * structured tool.
28
30
  * @param {any} runState
29
31
  * @param {any} params
30
- * @returns {Promise<{tools: any[], structuredTool: any, mcpClients: any[]}>}
32
+ * @returns {Promise<{tools: any[], structuredTool: any, mcpClients: any[], closeRunTools: () => Promise<void>}>}
31
33
  */
32
34
  export async function buildTurnTools(runState, {
33
35
  options,
@@ -62,6 +64,15 @@ export async function buildTurnTools(runState, {
62
64
  ? { ...(options.toolContext ?? readToolRuntime()), sandbox: options.sandbox }
63
65
  : options.toolContext;
64
66
  const sandboxEngine = options.sandboxEngine ?? runCtx?.sandboxEngine;
67
+ const nodeReplController = capabilities.tool_use === false
68
+ ? null
69
+ : createNodeReplController({
70
+ cwd: options.cwd,
71
+ maxOutputChars: toolLimits.bashOutputLimitChars || toolLimits.toolTextLimitChars,
72
+ sandboxPolicy: options.sandboxPolicy,
73
+ sandboxEngine,
74
+ ctx: runCtx,
75
+ });
65
76
 
66
77
  // REUSED custom pieces: built-in tool sandboxing + allowlist/bloat filter +
67
78
  // approval gates. These are identical to the legacy bridge.
@@ -97,6 +108,7 @@ export async function buildTurnTools(runState, {
97
108
  sandboxEngine,
98
109
  approvalManager,
99
110
  approvalModel: runtime.model?.id || runtime.model?.name || resolved.model,
111
+ nodeReplController,
100
112
  ctx: runCtx,
101
113
  }));
102
114
 
@@ -134,7 +146,12 @@ export async function buildTurnTools(runState, {
134
146
  ...mcpInit.tools,
135
147
  ...(structuredTool ? [structuredTool] : []),
136
148
  ];
137
- return { tools, structuredTool, mcpClients: mcpInit.clients };
149
+ return {
150
+ tools,
151
+ structuredTool,
152
+ mcpClients: mcpInit.clients,
153
+ closeRunTools: async () => { await nodeReplController?.close(); },
154
+ };
138
155
  }
139
156
 
140
157
  /**
@@ -52,6 +52,7 @@ import {
52
52
  buildErrorDetails,
53
53
  buildErrorResult,
54
54
  buildSuccessResult,
55
+ contextUsageFromAssistantMessage,
55
56
  emitCapabilitiesResolved,
56
57
  emitUsageCostEvents,
57
58
  usageFromMessages,
@@ -223,6 +224,7 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
223
224
  const events = [];
224
225
  const runtimeWarnings = [];
225
226
  let mcpClients = [];
227
+ let closeRunTools = async () => {};
226
228
  let harness = null;
227
229
  // The ONE explicit runState the extracted modules (stream subscriber, session
228
230
  // lifecycle, compaction driver, turn runner, result builder) read/write.
@@ -399,7 +401,12 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
399
401
  // Build the turn's tools (builtins + MCP bridge + StructuredOutput). The
400
402
  // StructuredOutput callback writes runState.structuredResult; the MCP clients
401
403
  // are closed in the finally.
402
- const { tools, structuredTool, mcpClients: builtMcpClients } = await buildTurnTools(runState, {
404
+ const {
405
+ tools,
406
+ structuredTool,
407
+ mcpClients: builtMcpClients,
408
+ closeRunTools: builtCloseRunTools,
409
+ } = await buildTurnTools(runState, {
403
410
  options,
404
411
  capabilities,
405
412
  toolLimits,
@@ -410,6 +417,7 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
410
417
  runtimeWarnings,
411
418
  });
412
419
  mcpClients = builtMcpClients;
420
+ closeRunTools = builtCloseRunTools;
413
421
 
414
422
  // Provider retry/backoff is delegated to pi-ai via streamOptions, replacing
415
423
  // the legacy hand-rolled stream-retry loop.
@@ -601,7 +609,19 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
601
609
  cachedTokens: usage.cacheRead,
602
610
  cacheWriteTokens: usage.cacheWrite,
603
611
  });
604
- emitUsageCostEvents({ onEvent, resolved, reference, usage, estimatedCost, start, externalAbort: runState.externalAbort });
612
+ emitUsageCostEvents({
613
+ onEvent,
614
+ resolved,
615
+ reference,
616
+ usage,
617
+ contextUsage: runState.externalAbort || runState.maxTurnsHit || runError
618
+ ? null
619
+ : contextUsageFromAssistantMessage(lastAssistant),
620
+ contextWindow: runState.compaction.policy?.contextWindow,
621
+ estimatedCost,
622
+ start,
623
+ externalAbort: runState.externalAbort,
624
+ });
605
625
 
606
626
  const rawErrorMessage = runState.externalAbort
607
627
  ? null
@@ -654,7 +674,7 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
654
674
  toolCompactionApplied: toolCompactionAppliedFromWarnings(runtimeWarnings),
655
675
  // Tristate: true = a compaction fired this run (proactive or reactive),
656
676
  // false = the path is enabled but did not need to fire, null = disabled via
657
- // agent_compaction_enabled. See docs/reference/feature-registry.md runtime.context-compaction.
677
+ // runtime.compaction.enabled. See docs/reference/feature-registry.md runtime.context-compaction.
658
678
  contextCompactionApplied: runState.compaction.policy?.enabled ? runState.compaction.applied : null,
659
679
  });
660
680
  emitCapabilitiesResolved(onEvent, { sdk: resolved.sdk, model: reference, capabilitiesUsed });
@@ -750,7 +770,11 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
750
770
  } finally {
751
771
  if (runState.sessionEntry) runState.sessionEntry.busy = false;
752
772
  runState.removeAbortHandler?.();
753
- await closePiMcpClients(mcpClients);
773
+ try {
774
+ await closeRunTools();
775
+ } finally {
776
+ await closePiMcpClients(mcpClients);
777
+ }
754
778
  }
755
779
  }
756
780
 
package/src/ai/types.js CHANGED
@@ -98,14 +98,15 @@
98
98
  * @typedef {Object} RuntimeCompactionPolicy
99
99
  * Typed per-run context-compaction policy (the supported replacement for the
100
100
  * `agent_compaction_*` keys of the deprecated `settings` bag). Every field is
101
- * optional; an omitted field falls back to the kernel default.
101
+ * optional; omitted scalar budgets resolve adaptively against the effective
102
+ * model context window.
102
103
  * @property {boolean} [enabled] Whether auto-compaction runs at all.
103
104
  * @property {number} [triggerRatio] Fraction of the context window that arms the proactive trigger.
104
105
  * @property {number} [keepRecentTokens] Recent-token budget preserved across a compaction.
105
- * @property {number} [summaryMaxTokens] Max tokens of the generated summary.
106
- * @property {number} [minSavingsTokens] Minimum token savings required to keep a compaction.
106
+ * @property {number} [summaryMaxTokens] Combined output-token budget for generated compaction summaries.
107
+ * @property {number} [minSavingsTokens] Minimum token savings required for proactive compaction; reactive recovery accepts any positive reduction.
107
108
  * @property {boolean} [fixedOverheadEnabled] Whether the system-prompt + tool-schema overhead correction is folded into the trigger.
108
- * @property {number} [contextWindowOverride] Forces the compaction window instead of the live-model-recognized one (applied at resolveLiveCompactionPolicy; has no legacy settings equivalent).
109
+ * @property {number} [contextWindowOverride] Persistent correction for provider context-window metadata; learned overflow evidence may lower it process-locally (applied at resolveLiveCompactionPolicy; has no legacy settings equivalent).
109
110
  */
110
111
 
111
112
  /**
@@ -0,0 +1,19 @@
1
+ /**
2
+ * One lazy Node REPL process owned by a single Pi run.
3
+ * @param {{cwd?: string, maxOutputChars?: number, sandboxPolicy?: any, sandboxEngine?: any, ctx?: any}} [options]
4
+ */
5
+ export function createNodeReplController({ cwd, maxOutputChars, sandboxPolicy, sandboxEngine, ctx, }?: {
6
+ cwd?: string;
7
+ maxOutputChars?: number;
8
+ sandboxPolicy?: any;
9
+ sandboxEngine?: any;
10
+ ctx?: any;
11
+ }): {
12
+ /** @param {{code: string}} params @param {{signal?: AbortSignal}} [execution] */
13
+ execute({ code }: {
14
+ code: string;
15
+ }, { signal }?: {
16
+ signal?: AbortSignal;
17
+ }): Promise<any>;
18
+ close(): Promise<void>;
19
+ };
@@ -35,9 +35,9 @@ export function createStructuredOutputTool(outputSchema: any, onStructuredOutput
35
35
  };
36
36
  /**
37
37
  * @param {any} allowedTools
38
- * @param {{disallowedTools?: any[], skillNames?: any[], skills?: any[], skillsRoot?: any, dataDir?: any, cwd?: any, onEvent?: (event: any) => void, toolLimits?: any, persistArtifact?: any, onTruncate?: any, toolPayloadMaxBytes?: number, imageInlineMaxBytes?: any, toolPolicy?: any, sandboxPolicy?: any, sandboxEngine?: any, approvalManager?: any, approvalModel?: any, ctx?: any}} [options]
38
+ * @param {{disallowedTools?: any[], skillNames?: any[], skills?: any[], skillsRoot?: any, dataDir?: any, cwd?: any, onEvent?: (event: any) => void, toolLimits?: any, persistArtifact?: any, onTruncate?: any, toolPayloadMaxBytes?: number, imageInlineMaxBytes?: any, toolPolicy?: any, sandboxPolicy?: any, sandboxEngine?: any, approvalManager?: any, approvalModel?: any, nodeReplController?: any, ctx?: any}} [options]
39
39
  */
40
- export function getPiBuiltinTools(allowedTools: any, { disallowedTools, skillNames, skills, skillsRoot, dataDir, cwd, onEvent, toolLimits, persistArtifact, onTruncate, toolPayloadMaxBytes, imageInlineMaxBytes, toolPolicy, sandboxPolicy, sandboxEngine, approvalManager, approvalModel, ctx, }?: {
40
+ export function getPiBuiltinTools(allowedTools: any, { disallowedTools, skillNames, skills, skillsRoot, dataDir, cwd, onEvent, toolLimits, persistArtifact, onTruncate, toolPayloadMaxBytes, imageInlineMaxBytes, toolPolicy, sandboxPolicy, sandboxEngine, approvalManager, approvalModel, nodeReplController, ctx, }?: {
41
41
  disallowedTools?: any[];
42
42
  skillNames?: any[];
43
43
  skills?: any[];
@@ -55,6 +55,7 @@ export function getPiBuiltinTools(allowedTools: any, { disallowedTools, skillNam
55
55
  sandboxEngine?: any;
56
56
  approvalManager?: any;
57
57
  approvalModel?: any;
58
+ nodeReplController?: any;
58
59
  ctx?: any;
59
60
  }): any[];
60
61
  export function resolveMcpStdioCwd(cfg?: {}, cwd?: any): any;
@@ -3,6 +3,15 @@
3
3
  * @returns {boolean}
4
4
  */
5
5
  export function isProviderAuthFailureText(text?: string): boolean;
6
+ /**
7
+ * Identify request-input/context-window overflows without conflating provider
8
+ * throttling or output-token ceilings. Context overflows are route-local: a
9
+ * fallback model may have a larger usable window, while rate/quota/max-turn
10
+ * failures retain the terminal `usage_limit` classification.
11
+ * @param {string} text
12
+ * @returns {boolean}
13
+ */
14
+ export function isContextLimitFailureText(text?: string): boolean;
6
15
  /**
7
16
  * @param {Object} [options]
8
17
  * @param {string} [options.errorText]
@@ -64,7 +73,7 @@ export function createStderrTail({ limit }?: {
64
73
  * @property {string|null} requestId
65
74
  */
66
75
  /**
67
- * @typedef {"spawn" | "timeout" | "stall" | "usage_limit" | "invalid_result"
76
+ * @typedef {"spawn" | "timeout" | "stall" | "context_limit" | "usage_limit" | "invalid_result"
68
77
  * | "invalid_delegation" | "tool_failure" | "provider_unavailable"
69
78
  * | "provider_unavailable_exhausted" | "provider_auth"
70
79
  * | "skipped_capability_mismatch" | "cancelled" | "cancelled_user"
@@ -114,4 +123,4 @@ export type RetryableProviderFailureInfo = {
114
123
  * Hosts (e.g. worklab's coordinator) validate against `FAILURE_KINDS` and may
115
124
  * define additional kinds — accepting them at the type level is deliberate.
116
125
  */
117
- export type FailureKind = "spawn" | "timeout" | "stall" | "usage_limit" | "invalid_result" | "invalid_delegation" | "tool_failure" | "provider_unavailable" | "provider_unavailable_exhausted" | "provider_auth" | "skipped_capability_mismatch" | "cancelled" | "cancelled_user" | "cancelled_shutdown" | "cancelled_signal" | "abandoned" | "session_not_found" | "session_busy" | (string & {});
126
+ export type FailureKind = "spawn" | "timeout" | "stall" | "context_limit" | "usage_limit" | "invalid_result" | "invalid_delegation" | "tool_failure" | "provider_unavailable" | "provider_unavailable_exhausted" | "provider_auth" | "skipped_capability_mismatch" | "cancelled" | "cancelled_user" | "cancelled_shutdown" | "cancelled_signal" | "abandoned" | "session_not_found" | "session_busy" | (string & {});
@@ -4,7 +4,7 @@
4
4
  * can contain provider credentials or echoed request secrets.
5
5
  */
6
6
  export function safeOpenCodeErrorMessage(error: any, fallback?: string): any;
7
- export function mapErrorFailureKind(error: any): "usage_limit" | "provider_unavailable" | "provider_auth" | "cancelled";
7
+ export function mapErrorFailureKind(error: any): "context_limit" | "usage_limit" | "provider_unavailable" | "provider_auth" | "cancelled";
8
8
  export function mapSpawnFailureKind(err: any): "spawn" | "provider_unavailable";
9
9
  export namespace opencodeAppRuntimeBridge {
10
10
  export let id: string;
@@ -1,17 +1,31 @@
1
- export function estimateCurrentContextTokens(session: any, fixedOverheadTokens?: number): Promise<{
1
+ export function estimateCurrentContextTokens(session: any, fixedOverheadTokens?: number, usageIncrementTokens?: number): Promise<{
2
2
  tokens: number;
3
3
  source: string;
4
4
  }>;
5
- export function tryCompact(harness: any, { trigger, onEvent, runtimeWarnings, onCompactionRecorded, runId, model }: {
5
+ /**
6
+ * Pi derives its summary output limit from reserveTokens. A normal compaction
7
+ * uses floor(0.8 * reserve); a split-turn compaction may generate both that
8
+ * history summary and floor(0.5 * reserve) for the turn prefix. Return the
9
+ * largest reserve whose derived generation budget does not exceed the public
10
+ * summaryMaxTokens setting.
11
+ * @param {number} summaryMaxTokens
12
+ * @param {boolean} isSplitTurn
13
+ */
14
+ export function piSummaryReserveTokens(summaryMaxTokens: number, isSplitTurn: boolean): number;
15
+ export function tryCompact(harness: any, { trigger, onEvent, runtimeWarnings, onCompactionRecorded, runId, model, session, policy, }: {
6
16
  trigger: any;
7
17
  onEvent: any;
8
18
  runtimeWarnings: any;
9
19
  onCompactionRecorded: any;
10
20
  runId: any;
11
21
  model: any;
22
+ session: any;
23
+ policy: any;
12
24
  }): Promise<{
13
25
  applied: boolean;
14
26
  tokensBefore: number;
27
+ tokensAfter: any;
28
+ reduced: boolean;
15
29
  nothingToCompact: boolean;
16
30
  }>;
17
31
  /**
@@ -49,10 +63,10 @@ export function piCompactionSettings(policy: {
49
63
  * Resolve the compaction policy against the LIVE model's context window
50
64
  * (auto-recognized from the model actually serving the request, lowered by any
51
65
  * ceiling learned from a prior overflow). A positive `contextWindowOverride`
52
- * (from the typed `compaction` policy object) replaces the auto-recognized
53
- * window it is not a legacy `settings` key, so it is applied here directly
54
- * rather than through the settings shim. Drives the proactive trigger +
55
- * reactive recovery.
66
+ * (from the typed `compaction` policy object) replaces provider metadata, but
67
+ * process-local overflow evidence can still lower it. It is not a legacy
68
+ * `settings` key, so it is applied here directly rather than through the
69
+ * settings shim. Drives the proactive trigger + reactive recovery.
56
70
  * @param {{harness: any, runtime: any, resolved: any, settings: any, contextWindowOverride?: number}} params
57
71
  */
58
72
  export function resolveLiveCompactionPolicy({ harness, runtime, resolved, settings, contextWindowOverride }: {
@@ -11,8 +11,24 @@ export function usageFromMessages(messages?: Array<any>): {
11
11
  cost: number;
12
12
  };
13
13
  /**
14
- * Classify a pi error message into a runtime failure kind. Context-limit /
15
- * max-turns terminations map to usage_limit; credential/config auth failures
14
+ * Normalize the final provider request's usage into an exact context snapshot.
15
+ * Unlike usageFromMessages(), this deliberately does not aggregate earlier
16
+ * requests in the run: the last assistant usage is the same provider-counted
17
+ * value Pi's compaction logic trusts, so it can decrease after compaction.
18
+ * @param {any} assistantMessage
19
+ * @returns {{input: number, output: number, cacheRead: number, cacheCreation: number, total: number}|null}
20
+ */
21
+ export function contextUsageFromAssistantMessage(assistantMessage: any): {
22
+ input: number;
23
+ output: number;
24
+ cacheRead: number;
25
+ cacheCreation: number;
26
+ total: number;
27
+ } | null;
28
+ /**
29
+ * Classify a pi error message into a runtime failure kind. Context-window
30
+ * overflows map to context_limit so the router can try the configured fallback;
31
+ * max-turns terminations remain usage_limit. Credential/config auth failures
16
32
  * map to provider_auth; everything else to provider_unavailable. Null message → null.
17
33
  * @param {string|null} message
18
34
  * @param {Record<string, unknown>} diagnostics
@@ -24,9 +40,9 @@ export function failureKindForPiError(message: string | null, diagnostics: Recor
24
40
  }): string | null;
25
41
  /**
26
42
  * Emit the per-run cache / cost / provider-completed events.
27
- * @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
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
28
44
  */
29
- export function emitUsageCostEvents({ onEvent, resolved, reference, usage, estimatedCost, start, externalAbort }: {
45
+ export function emitUsageCostEvents({ onEvent, resolved, reference, usage, contextUsage, contextWindow, estimatedCost, start, externalAbort, }: {
30
46
  onEvent: (event: any) => void;
31
47
  resolved: any;
32
48
  reference: string;
@@ -37,6 +53,14 @@ export function emitUsageCostEvents({ onEvent, resolved, reference, usage, estim
37
53
  cacheWrite: number;
38
54
  cost: number;
39
55
  };
56
+ contextUsage?: {
57
+ input: number;
58
+ output: number;
59
+ cacheRead: number;
60
+ cacheCreation: number;
61
+ total: number;
62
+ } | null;
63
+ contextWindow?: number;
40
64
  estimatedCost: number;
41
65
  start: number;
42
66
  externalAbort: boolean;
@@ -3,15 +3,17 @@
3
3
  * tools, the MCP tool bridge, and the StructuredOutput tool (whose callback
4
4
  * writes runState.structuredResult). Surfaces MCP init/list failures to both the
5
5
  * event stream and runtimeWarnings. Returns the assembled tools plus the MCP
6
- * clients (closed by the caller's finally) and the structured tool.
6
+ * clients (closed by the caller's finally), run-owned tool cleanup, and the
7
+ * structured tool.
7
8
  * @param {any} runState
8
9
  * @param {any} params
9
- * @returns {Promise<{tools: any[], structuredTool: any, mcpClients: any[]}>}
10
+ * @returns {Promise<{tools: any[], structuredTool: any, mcpClients: any[], closeRunTools: () => Promise<void>}>}
10
11
  */
11
12
  export function buildTurnTools(runState: any, { options, capabilities, toolLimits, approvalManager, runtime, resolved, onEvent, runtimeWarnings, }: any): Promise<{
12
13
  tools: any[];
13
14
  structuredTool: any;
14
15
  mcpClients: any[];
16
+ closeRunTools: () => Promise<void>;
15
17
  }>;
16
18
  /**
17
19
  * Map an effort level to the harness thinkingLevel, respecting model reasoning
@@ -71,14 +71,15 @@
71
71
  * @typedef {Object} RuntimeCompactionPolicy
72
72
  * Typed per-run context-compaction policy (the supported replacement for the
73
73
  * `agent_compaction_*` keys of the deprecated `settings` bag). Every field is
74
- * optional; an omitted field falls back to the kernel default.
74
+ * optional; omitted scalar budgets resolve adaptively against the effective
75
+ * model context window.
75
76
  * @property {boolean} [enabled] Whether auto-compaction runs at all.
76
77
  * @property {number} [triggerRatio] Fraction of the context window that arms the proactive trigger.
77
78
  * @property {number} [keepRecentTokens] Recent-token budget preserved across a compaction.
78
- * @property {number} [summaryMaxTokens] Max tokens of the generated summary.
79
- * @property {number} [minSavingsTokens] Minimum token savings required to keep a compaction.
79
+ * @property {number} [summaryMaxTokens] Combined output-token budget for generated compaction summaries.
80
+ * @property {number} [minSavingsTokens] Minimum token savings required for proactive compaction; reactive recovery accepts any positive reduction.
80
81
  * @property {boolean} [fixedOverheadEnabled] Whether the system-prompt + tool-schema overhead correction is folded into the trigger.
81
- * @property {number} [contextWindowOverride] Forces the compaction window instead of the live-model-recognized one (applied at resolveLiveCompactionPolicy; has no legacy settings equivalent).
82
+ * @property {number} [contextWindowOverride] Persistent correction for provider context-window metadata; learned overflow evidence may lower it process-locally (applied at resolveLiveCompactionPolicy; has no legacy settings equivalent).
82
83
  */
83
84
  /**
84
85
  * @typedef {Object} RuntimePromptOverrides
@@ -406,7 +407,8 @@ export type RuntimeToolLimits = {
406
407
  /**
407
408
  * Typed per-run context-compaction policy (the supported replacement for the
408
409
  * `agent_compaction_*` keys of the deprecated `settings` bag). Every field is
409
- * optional; an omitted field falls back to the kernel default.
410
+ * optional; omitted scalar budgets resolve adaptively against the effective
411
+ * model context window.
410
412
  */
411
413
  export type RuntimeCompactionPolicy = {
412
414
  /**
@@ -422,11 +424,11 @@ export type RuntimeCompactionPolicy = {
422
424
  */
423
425
  keepRecentTokens?: number;
424
426
  /**
425
- * Max tokens of the generated summary.
427
+ * Combined output-token budget for generated compaction summaries.
426
428
  */
427
429
  summaryMaxTokens?: number;
428
430
  /**
429
- * Minimum token savings required to keep a compaction.
431
+ * Minimum token savings required for proactive compaction; reactive recovery accepts any positive reduction.
430
432
  */
431
433
  minSavingsTokens?: number;
432
434
  /**
@@ -434,7 +436,7 @@ export type RuntimeCompactionPolicy = {
434
436
  */
435
437
  fixedOverheadEnabled?: boolean;
436
438
  /**
437
- * Forces the compaction window instead of the live-model-recognized one (applied at resolveLiveCompactionPolicy; has no legacy settings equivalent).
439
+ * Persistent correction for provider context-window metadata; learned overflow evidence may lower it process-locally (applied at resolveLiveCompactionPolicy; has no legacy settings equivalent).
438
440
  */
439
441
  contextWindowOverride?: number;
440
442
  };