@myagentroam/agent 0.9.135 → 0.9.137

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.
Files changed (72) hide show
  1. package/dist/cli/main.js +1 -1
  2. package/dist/host/local-agent-host.d.ts +9 -7
  3. package/dist/host/local-agent-host.js +77 -5
  4. package/dist/host/local-process-executor.d.ts +2 -0
  5. package/dist/index.d.ts +4 -2
  6. package/dist/index.js +1 -0
  7. package/dist/model/catalog-file.d.ts +2 -0
  8. package/dist/model/configuration.d.ts +5 -0
  9. package/dist/model/configuration.js +8 -0
  10. package/dist/model/contracts.d.ts +7 -0
  11. package/dist/model/openai-responses.d.ts +1 -1
  12. package/dist/model/openai-responses.js +85 -20
  13. package/dist/prompts/index.d.ts +2 -1
  14. package/dist/prompts/index.js +2 -2
  15. package/dist/prompts/workflow.d.ts +1 -1
  16. package/dist/prompts/workflow.js +9 -2
  17. package/dist/runtime/context-gc-runtime.d.ts +1 -0
  18. package/dist/runtime/context-gc-runtime.js +3 -0
  19. package/dist/runtime/context-gc-tokens.d.ts +1 -0
  20. package/dist/runtime/context-gc-tokens.js +1 -1
  21. package/dist/runtime/context-gc.d.ts +1 -0
  22. package/dist/runtime/context-gc.js +85 -8
  23. package/dist/runtime/context-projection.js +19 -2
  24. package/dist/sandbox/linux/bubblewrap-sandbox-executor.js +29 -2
  25. package/dist/sdk/agent.js +249 -26
  26. package/dist/sdk/mcp-catalog.d.ts +13 -0
  27. package/dist/sdk/mcp-catalog.js +219 -0
  28. package/dist/sdk/types.d.ts +53 -1
  29. package/dist/session/context-gc-checkpoint.d.ts +7 -1
  30. package/dist/session/context-gc-checkpoint.js +28 -2
  31. package/dist/session/context-gc-replacements.d.ts +7 -0
  32. package/dist/session/context-gc-replacements.js +26 -0
  33. package/dist/session/jsonl-store.d.ts +6 -0
  34. package/dist/session/jsonl-store.js +92 -54
  35. package/dist/subagent/scheduler.d.ts +3 -3
  36. package/dist/subagent/session-controller.d.ts +1 -1
  37. package/dist/tools/agent-cancel.js +1 -0
  38. package/dist/tools/agent-message.js +1 -0
  39. package/dist/tools/agent-start.js +1 -0
  40. package/dist/tools/agent-wait.js +1 -0
  41. package/dist/tools/apply-patch.js +2 -1
  42. package/dist/tools/callers.d.ts +6 -0
  43. package/dist/tools/callers.js +23 -0
  44. package/dist/tools/code-mode/engine.d.ts +43 -0
  45. package/dist/tools/code-mode/engine.js +1 -0
  46. package/dist/tools/code-mode/quickjs-engine.d.ts +2 -0
  47. package/dist/tools/code-mode/quickjs-engine.js +454 -0
  48. package/dist/tools/code-mode/state.d.ts +20 -0
  49. package/dist/tools/code-mode/state.js +82 -0
  50. package/dist/tools/code-mode/worker.d.ts +1 -0
  51. package/dist/tools/code-mode/worker.js +65 -0
  52. package/dist/tools/code-mode.d.ts +8 -4
  53. package/dist/tools/code-mode.js +154 -120
  54. package/dist/tools/exec.js +1 -0
  55. package/dist/tools/execution-limits.d.ts +8 -0
  56. package/dist/tools/execution-limits.js +8 -0
  57. package/dist/tools/local-registry.d.ts +2 -0
  58. package/dist/tools/local-registry.js +1 -1
  59. package/dist/tools/question.js +1 -0
  60. package/dist/tools/read.js +1 -0
  61. package/dist/tools/registry.js +3 -0
  62. package/dist/tools/runtime-context.d.ts +2 -0
  63. package/dist/tools/runtime.js +3 -1
  64. package/dist/tools/skill.js +1 -0
  65. package/dist/tools/todo-read.js +1 -0
  66. package/dist/tools/todo-write.js +1 -0
  67. package/dist/tools/tool-search.d.ts +43 -0
  68. package/dist/tools/tool-search.js +284 -0
  69. package/dist/tools/view-image.js +1 -0
  70. package/dist/tools/web-fetch.js +1 -0
  71. package/dist/tools/web-search.js +1 -0
  72. package/package.json +3 -1
@@ -0,0 +1,219 @@
1
+ import { MarAgentError } from '../error.js';
2
+ export const MCP_DEFINITION_LIMITS = Object.freeze({
3
+ depth: 64,
4
+ nodes: 32768,
5
+ definitionBytes: 256 * 1024,
6
+ catalogBytes: 16 * 1024 * 1024,
7
+ tools: 10000,
8
+ servers: 256
9
+ });
10
+ function invalid() {
11
+ throw new MarAgentError('MAR_AGENT_MCP_CATALOG_INVALID', 'MCP catalog contains invalid or oversized definitions.');
12
+ }
13
+ const record = (value) => value !== null &&
14
+ typeof value === 'object' &&
15
+ !Array.isArray(value) &&
16
+ [Object.prototype, null].includes(Object.getPrototypeOf(value));
17
+ const text = (value, maximum) => typeof value === 'string' && value.length > 0 && value.length <= maximum;
18
+ const onlyKeys = (value, keys) => Object.keys(value).every((key) => keys.includes(key));
19
+ /** Bound all JSON, including unknown extension keywords, before recursive lowering. */
20
+ function assertJson(value) {
21
+ const stack = [{ value, depth: 0 }];
22
+ const seen = new Set();
23
+ let nodes = 0;
24
+ while (stack.length) {
25
+ const current = stack.pop();
26
+ if (current.exit) {
27
+ seen.delete(current.value);
28
+ continue;
29
+ }
30
+ if (++nodes > MCP_DEFINITION_LIMITS.nodes || current.depth > MCP_DEFINITION_LIMITS.depth)
31
+ invalid();
32
+ const item = current.value;
33
+ if (item === null ||
34
+ typeof item === 'string' ||
35
+ typeof item === 'boolean' ||
36
+ (typeof item === 'number' && Number.isFinite(item)))
37
+ continue;
38
+ if (!Array.isArray(item) && !record(item))
39
+ invalid();
40
+ if (seen.has(item))
41
+ invalid();
42
+ seen.add(item);
43
+ stack.push({ value: item, depth: current.depth, exit: true });
44
+ for (const child of Object.values(item))
45
+ stack.push({ value: child, depth: current.depth + 1 });
46
+ }
47
+ }
48
+ function assertSchema(schema) {
49
+ if (!record(schema) || schema.type !== 'object')
50
+ invalid();
51
+ assertJson(schema);
52
+ const stack = [schema];
53
+ const types = new Set(['null', 'boolean', 'object', 'array', 'number', 'integer', 'string']);
54
+ while (stack.length) {
55
+ const value = stack.pop();
56
+ if (typeof value === 'boolean')
57
+ continue;
58
+ if (!record(value))
59
+ invalid();
60
+ if (value.type !== undefined) {
61
+ const entries = Array.isArray(value.type) ? value.type : [value.type];
62
+ if (!entries.length ||
63
+ new Set(entries).size !== entries.length ||
64
+ entries.some((type) => typeof type !== 'string' || !types.has(type)))
65
+ invalid();
66
+ }
67
+ if (value.required !== undefined &&
68
+ (!Array.isArray(value.required) ||
69
+ value.required.some((name) => typeof name !== 'string') ||
70
+ new Set(value.required).size !== value.required.length))
71
+ invalid();
72
+ for (const key of [
73
+ 'properties',
74
+ 'patternProperties',
75
+ '$defs',
76
+ 'definitions',
77
+ 'dependentSchemas'
78
+ ]) {
79
+ const children = value[key];
80
+ if (children === undefined)
81
+ continue;
82
+ if (!record(children))
83
+ invalid();
84
+ stack.push(...Object.values(children));
85
+ }
86
+ for (const key of ['allOf', 'anyOf', 'oneOf', 'prefixItems']) {
87
+ const children = value[key];
88
+ if (children === undefined)
89
+ continue;
90
+ if (!Array.isArray(children) || !children.length)
91
+ invalid();
92
+ stack.push(...children);
93
+ }
94
+ for (const key of [
95
+ 'additionalProperties',
96
+ 'unevaluatedProperties',
97
+ 'additionalItems',
98
+ 'unevaluatedItems',
99
+ 'contains',
100
+ 'propertyNames',
101
+ 'not',
102
+ 'if',
103
+ 'then',
104
+ 'else',
105
+ 'items'
106
+ ]) {
107
+ const child = value[key];
108
+ if (child !== undefined) {
109
+ if (key === 'items' && Array.isArray(child))
110
+ stack.push(...child);
111
+ else
112
+ stack.push(child);
113
+ }
114
+ }
115
+ for (const key of ['$ref', '$id', '$schema', 'title', 'description', 'format', 'pattern'])
116
+ if (value[key] !== undefined && typeof value[key] !== 'string')
117
+ invalid();
118
+ for (const key of ['minimum', 'maximum', 'exclusiveMinimum', 'exclusiveMaximum', 'multipleOf'])
119
+ if (value[key] !== undefined &&
120
+ (typeof value[key] !== 'number' ||
121
+ !Number.isFinite(value[key]) ||
122
+ (key === 'multipleOf' && Number(value[key]) <= 0)))
123
+ invalid();
124
+ for (const key of [
125
+ 'minLength',
126
+ 'maxLength',
127
+ 'minItems',
128
+ 'maxItems',
129
+ 'minProperties',
130
+ 'maxProperties'
131
+ ])
132
+ if (value[key] !== undefined && (!Number.isSafeInteger(value[key]) || Number(value[key]) < 0))
133
+ invalid();
134
+ if (value.enum !== undefined && (!Array.isArray(value.enum) || !value.enum.length))
135
+ invalid();
136
+ }
137
+ }
138
+ /** Shared Host and Node publication boundary, not a provider-specific conversion. */
139
+ export function assertMcpToolDefinition(value) {
140
+ if (!record(value) ||
141
+ !text(value.name, 256) ||
142
+ !/^mcp__[A-Za-z0-9_-]+__[A-Za-z0-9_-]+$/u.test(value.name) ||
143
+ typeof value.description !== 'string' ||
144
+ value.description.length > 65536 ||
145
+ (value.parallelSafety !== undefined &&
146
+ !['safe', 'serial'].includes(String(value.parallelSafety))) ||
147
+ (value.agentScope !== undefined &&
148
+ !['ROOT_AND_SUBAGENTS', 'ROOT_ONLY'].includes(String(value.agentScope))) ||
149
+ (value.allowedCallers !== undefined &&
150
+ (!Array.isArray(value.allowedCallers) ||
151
+ !value.allowedCallers.length ||
152
+ value.allowedCallers.some((caller) => caller !== 'direct' && caller !== 'programmatic'))) ||
153
+ (value.inputMode !== undefined && value.inputMode !== 'json'))
154
+ invalid();
155
+ assertJson(value);
156
+ assertSchema(value.inputSchema);
157
+ if (value.outputSchema !== undefined)
158
+ assertSchema(value.outputSchema);
159
+ if (Buffer.byteLength(JSON.stringify(value)) > MCP_DEFINITION_LIMITS.definitionBytes)
160
+ invalid();
161
+ }
162
+ export function assertMcpToolCatalog(value) {
163
+ if (!record(value) ||
164
+ typeof value.revision !== 'string' ||
165
+ value.revision.length > 512 ||
166
+ !onlyKeys(value, ['revision', 'servers', 'tools']) ||
167
+ !Array.isArray(value.servers) ||
168
+ value.servers.length > MCP_DEFINITION_LIMITS.servers ||
169
+ !Array.isArray(value.tools) ||
170
+ value.tools.length > MCP_DEFINITION_LIMITS.tools)
171
+ invalid();
172
+ const servers = new Set();
173
+ for (const server of value.servers) {
174
+ if (!record(server) ||
175
+ !text(server.id, 512) ||
176
+ !text(server.name, 256) ||
177
+ servers.has(server.id) ||
178
+ !onlyKeys(server, ['id', 'name', 'description', 'instructions']) ||
179
+ (server.description !== undefined &&
180
+ (typeof server.description !== 'string' || server.description.length > 65536)) ||
181
+ (server.instructions !== undefined &&
182
+ (typeof server.instructions !== 'string' || server.instructions.length > 65536)))
183
+ invalid();
184
+ servers.add(server.id);
185
+ }
186
+ const names = new Set();
187
+ for (const tool of value.tools) {
188
+ if (!record(tool) ||
189
+ !text(tool.serverId, 512) ||
190
+ !servers.has(tool.serverId) ||
191
+ !onlyKeys(tool, [
192
+ 'definition',
193
+ 'serverId',
194
+ 'rawName',
195
+ 'sourceIdentity',
196
+ 'definitionRevision',
197
+ 'lifetime',
198
+ 'exposure',
199
+ 'annotations'
200
+ ]) ||
201
+ !text(tool.rawName, 256) ||
202
+ !text(tool.sourceIdentity, 512) ||
203
+ !text(tool.definitionRevision, 512) ||
204
+ !['session', 'execution'].includes(String(tool.lifetime)) ||
205
+ !['direct', 'deferred'].includes(String(tool.exposure)))
206
+ invalid();
207
+ assertMcpToolDefinition(tool.definition);
208
+ if (tool.annotations !== undefined) {
209
+ if (!record(tool.annotations))
210
+ invalid();
211
+ assertJson(tool.annotations);
212
+ }
213
+ if (names.has(tool.definition.name))
214
+ invalid();
215
+ names.add(tool.definition.name);
216
+ }
217
+ if (Buffer.byteLength(JSON.stringify(value)) > MCP_DEFINITION_LIMITS.catalogBytes)
218
+ invalid();
219
+ }
@@ -1,7 +1,9 @@
1
1
  import type { HostDescription } from '../host/contracts.js';
2
2
  import type { MarAgentModelConfiguration, MarAgentReasoningEffort } from '../model/configuration.js';
3
+ import type { ClientToolDefinition } from '../model/contracts.js';
3
4
  import type { MarAgentSessionPage, MarAgentSessionSummary } from '../session/catalog.js';
4
5
  import type { SessionListInput, SessionSource } from '../session/types.js';
6
+ import type { CodeModeStateEntry, CodeModeStateMutation } from '../tools/code-mode/state.js';
5
7
  /** @deprecated MAR Agent always executes tools directly through the Host. */
6
8
  export type AccessMode = 'full-access';
7
9
  export type ExecutionMode = 'run' | 'plan' | 'compact';
@@ -22,6 +24,8 @@ export interface ToolExecutionContext {
22
24
  codeMode?: {
23
25
  supportsImages?: boolean;
24
26
  tools: readonly import('../model/contracts.js').ClientToolDefinition[];
27
+ state?: readonly CodeModeStateEntry[];
28
+ commitState?(mutations: readonly CodeModeStateMutation[]): Promise<readonly CodeModeStateEntry[]>;
25
29
  invoke(call: ToolCall, signal: AbortSignal): Promise<ToolExecutionResult>;
26
30
  };
27
31
  }
@@ -29,6 +33,34 @@ export interface McpToolCatalogContext extends Pick<ToolExecutionContext, 'sessi
29
33
  executionScopeId?: string;
30
34
  claimExecutionScope?: boolean;
31
35
  }
36
+ export interface McpToolCatalog {
37
+ readonly revision: string;
38
+ readonly servers: readonly {
39
+ readonly id: string;
40
+ readonly name: string;
41
+ readonly description?: string;
42
+ readonly instructions?: string;
43
+ }[];
44
+ readonly tools: readonly McpCatalogTool[];
45
+ }
46
+ export interface McpCatalogTool {
47
+ readonly definition: import('../model/contracts.js').ClientToolDefinition;
48
+ readonly serverId: string;
49
+ readonly rawName: string;
50
+ readonly sourceIdentity: string;
51
+ readonly definitionRevision: string;
52
+ readonly lifetime: 'session' | 'execution';
53
+ readonly exposure: 'direct' | 'deferred';
54
+ /** Untrusted MCP hints; never an authorization or parallel-safety decision. */
55
+ readonly annotations?: Readonly<Record<string, unknown>>;
56
+ }
57
+ export interface McpToolCallContext extends Pick<ToolExecutionContext, 'sessionId' | 'executionId'> {
58
+ readonly mode?: ExecutionMode;
59
+ readonly expectedTool?: {
60
+ readonly sourceIdentity: string;
61
+ readonly definitionRevision: string;
62
+ };
63
+ }
32
64
  export interface HostSkill {
33
65
  readonly name: string;
34
66
  readonly description: string;
@@ -51,6 +83,8 @@ export type MarAgentToolArtifact = MarAgentToolImageArtifact;
51
83
  export interface ToolExecutionResult {
52
84
  content: string;
53
85
  data?: unknown;
86
+ /** Runtime-only definitions used to encode a Tool Search output. */
87
+ toolSearchTools?: readonly ClientToolDefinition[];
54
88
  truncated?: boolean;
55
89
  images?: readonly {
56
90
  mimeType: string;
@@ -78,7 +112,8 @@ export interface MarAgentHost {
78
112
  questions: unknown[];
79
113
  }, signal: AbortSignal): Promise<Record<string, unknown>>;
80
114
  listMcpTools?(context?: McpToolCatalogContext): Promise<readonly import('../model/contracts.js').ClientToolDefinition[]>;
81
- callMcpTool?(call: ToolCall, signal: AbortSignal, context?: Pick<ToolExecutionContext, 'sessionId' | 'executionId'>): Promise<ToolExecutionResult>;
115
+ listMcpToolCatalog?(context: McpToolCatalogContext): Promise<McpToolCatalog>;
116
+ callMcpTool?(call: ToolCall, signal: AbortSignal, context?: McpToolCallContext): Promise<ToolExecutionResult>;
82
117
  listSessionResources?(sessionId: string): Promise<HostSessionResourceSnapshot>;
83
118
  disposeSessionResources?(sessionId: string): Promise<void>;
84
119
  dispose(): Promise<void>;
@@ -106,6 +141,20 @@ export type MarAgentEvent = MarAgentEventBase & ({
106
141
  text: string;
107
142
  modelId: string;
108
143
  modelName: string;
144
+ } | {
145
+ type: 'model.performance';
146
+ latencyMs: number;
147
+ outputTokens?: number | undefined;
148
+ outputDurationMs?: number | undefined;
149
+ tokensPerSecond?: number | undefined;
150
+ } | {
151
+ /** Legacy history event; new executions publish model.performance instead. */
152
+ type: 'message.performance';
153
+ itemId: string;
154
+ ttftMs: number;
155
+ outputTokens?: number | undefined;
156
+ outputDurationMs?: number | undefined;
157
+ tokensPerSecond?: number | undefined;
109
158
  } | {
110
159
  type: 'plan.completed';
111
160
  itemId: string;
@@ -137,11 +186,13 @@ export type MarAgentEvent = MarAgentEventBase & ({
137
186
  type: 'tool.started';
138
187
  toolName: string;
139
188
  callId: string;
189
+ parentCallId?: string;
140
190
  input?: unknown;
141
191
  } | {
142
192
  type: 'tool.completed';
143
193
  toolName: string;
144
194
  callId: string;
195
+ parentCallId?: string;
145
196
  summary: string;
146
197
  truncated?: boolean;
147
198
  artifacts?: readonly MarAgentToolArtifact[];
@@ -150,6 +201,7 @@ export type MarAgentEvent = MarAgentEventBase & ({
150
201
  type: 'tool.failed';
151
202
  toolName: string;
152
203
  callId: string;
204
+ parentCallId?: string;
153
205
  code: string;
154
206
  message?: string;
155
207
  } | {
@@ -50,7 +50,7 @@ export type ContextGcReplacement = {
50
50
  readonly evidenceSequences: readonly number[];
51
51
  } | {
52
52
  readonly kind: 'TOOL_CALL_INPUT';
53
- readonly toolName: 'apply_patch' | 'exec';
53
+ readonly toolName: 'apply_patch' | 'exec' | 'code_mode';
54
54
  readonly callId: string;
55
55
  readonly target: ContextGcTarget;
56
56
  readonly replacementArguments: unknown;
@@ -62,6 +62,12 @@ export type ContextGcReplacement = {
62
62
  readonly target: ContextGcTarget;
63
63
  readonly replacementContent: string;
64
64
  readonly evidenceSequence: number;
65
+ } | {
66
+ readonly kind: 'CODE_MODE_OUTPUT';
67
+ readonly callId: string;
68
+ readonly target: ContextGcTarget;
69
+ readonly replacementContent: string;
70
+ readonly evidenceSequence: number;
65
71
  } | {
66
72
  readonly kind: 'SUBAGENT_OUTPUT';
67
73
  readonly toolName: 'agent_wait' | 'agent_message' | 'agent_cancel';
@@ -2,7 +2,7 @@ import { createHash } from 'node:crypto';
2
2
  import { posix, win32 } from 'node:path';
3
3
  import { isDeepStrictEqual } from 'node:util';
4
4
  import { parseReadContextOutput } from '../tools/read-context.js';
5
- import { contextGcApplyPatchInputReplacement, contextGcWebOutputReplacement, contextGcExecInputReplacement, contextGcExecOutputReplacement, contextGcPatchResultFromCompletedPayload, contextGcStaleReadReplacement, normalizeContextGcExecResult } from './context-gc-replacements.js';
5
+ import { contextGcApplyPatchInputReplacement, contextGcCodeModeInputReplacement, contextGcCodeModeOutputReplacement, contextGcExecInputReplacement, contextGcExecOutputReplacement, contextGcPatchResultFromCompletedPayload, contextGcStaleReadReplacement, contextGcWebOutputReplacement, normalizeContextGcCodeModeInput, normalizeContextGcExecResult } from './context-gc-replacements.js';
6
6
  import { contextGcSubagentNeedsRetainedPriorFinal, contextGcSubagentOutputReplacement, contextGcSubagentSnapshotIsPreciselyCovered, contextGcSubagentSnapshotIsSuperseded, normalizeContextGcSubagentSnapshot } from './context-gc-subagent.js';
7
7
  export const CONTEXT_GC_CHECKPOINT_VERSION = 1;
8
8
  export const CONTEXT_GC_MAX_TARGETS = 4_096;
@@ -266,6 +266,25 @@ function replacementMatchesRecords(replacement, records, recordsBySequence, work
266
266
  result !== undefined &&
267
267
  isDeepStrictEqual(replacement.replacementArguments, contextGcApplyPatchInputReplacement(source.payload.arguments, result, replacement.evidenceSequence, applyPatchReplacementFormatVersion(replacement.replacementArguments))));
268
268
  }
269
+ if (replacement.kind === 'TOOL_CALL_INPUT' && replacement.toolName === 'code_mode') {
270
+ const evidence = successfulToolEvidence(records, recordsBySequence, replacement.evidenceSequence, 'code_mode');
271
+ const input = normalizeContextGcCodeModeInput(source.payload.arguments);
272
+ return (evidence?.callId === replacement.callId &&
273
+ evidence.call.sequence === replacement.target.sequence &&
274
+ input !== undefined &&
275
+ isDeepStrictEqual(replacement.replacementArguments, contextGcCodeModeInputReplacement(input)));
276
+ }
277
+ if (replacement.kind === 'CODE_MODE_OUTPUT') {
278
+ const evidence = successfulToolEvidence(records, recordsBySequence, replacement.evidenceSequence, 'code_mode');
279
+ return (evidence?.callId === replacement.callId &&
280
+ evidence.result.sequence === replacement.target.sequence &&
281
+ isRecord(evidence.result.payload) &&
282
+ typeof evidence.result.payload.content === 'string' &&
283
+ isRecord(evidence.completed.payload) &&
284
+ typeof evidence.completed.payload.truncated === 'boolean' &&
285
+ replacement.replacementContent ===
286
+ contextGcCodeModeOutputReplacement(evidence.result.payload.content, evidence.completed.payload.truncated));
287
+ }
269
288
  if (replacement.kind === 'SUBAGENT_OUTPUT') {
270
289
  const retainedPriorFinal = replacement.retainedPriorFinal;
271
290
  const sourceEvidence = successfulToolEvidence(records, recordsBySequence, source.sequence, replacement.toolName);
@@ -605,7 +624,9 @@ function isContextGcReplacement(value) {
605
624
  'evidenceSequence'
606
625
  ]) &&
607
626
  value.target.role === 'tool_call' &&
608
- (value.toolName === 'apply_patch' || value.toolName === 'exec') &&
627
+ (value.toolName === 'apply_patch' ||
628
+ value.toolName === 'exec' ||
629
+ value.toolName === 'code_mode') &&
609
630
  value.target.toolName === value.toolName &&
610
631
  Array.isArray(value.providerAliasTargets) &&
611
632
  value.providerAliasTargets.every((target) => isContextGcTarget(target) &&
@@ -661,6 +682,11 @@ function isContextGcReplacement(value) {
661
682
  (value.target.toolName === undefined || value.target.toolName === value.toolName) &&
662
683
  isNonemptyString(value.replacementContent) &&
663
684
  isPositiveInteger(value.evidenceSequence));
685
+ if (value.kind === 'CODE_MODE_OUTPUT')
686
+ return (hasOnlyKeys(value, ['kind', 'callId', 'target', 'replacementContent', 'evidenceSequence']) &&
687
+ value.target.role === 'tool' &&
688
+ isNonemptyString(value.replacementContent) &&
689
+ isPositiveInteger(value.evidenceSequence));
664
690
  return (value.kind === 'EXEC_OUTPUT' &&
665
691
  hasOnlyKeys(value, ['kind', 'callId', 'target', 'replacementContent', 'evidenceSequence']) &&
666
692
  value.target.role === 'tool' &&
@@ -1,4 +1,11 @@
1
1
  export type ContextGcWebToolName = 'web_search' | 'web_fetch';
2
+ export interface ContextGcCodeModeInput {
3
+ readonly code: string;
4
+ readonly inputMode: 'freeform' | 'json';
5
+ }
6
+ export declare function normalizeContextGcCodeModeInput(arguments_: unknown): ContextGcCodeModeInput | undefined;
7
+ export declare function contextGcCodeModeInputReplacement(input: ContextGcCodeModeInput): unknown;
8
+ export declare function contextGcCodeModeOutputReplacement(originalContent: string, truncated: boolean): string;
2
9
  export interface ContextGcPatchFile {
3
10
  readonly path: string;
4
11
  readonly targetPath?: string;
@@ -3,6 +3,32 @@ const RAW_MODEL_CONTEXT_PREVIEW_CHARACTERS = 256;
3
3
  const EXEC_INPUT_COMPLETE_CHARACTERS = 512;
4
4
  const EXEC_INPUT_PREVIEW_CHARACTERS = 256;
5
5
  const EXEC_OUTPUT_PREVIEW_CHARACTERS = 512;
6
+ const CODE_MODE_OUTPUT_PREVIEW_CHARACTERS = 512;
7
+ export function normalizeContextGcCodeModeInput(arguments_) {
8
+ if (typeof arguments_ === 'string' && arguments_.length > 0)
9
+ return { code: arguments_, inputMode: 'freeform' };
10
+ if (isRecord(arguments_) &&
11
+ Object.keys(arguments_).length === 1 &&
12
+ typeof arguments_.code === 'string' &&
13
+ arguments_.code.length > 0)
14
+ return { code: arguments_.code, inputMode: 'json' };
15
+ return undefined;
16
+ }
17
+ export function contextGcCodeModeInputReplacement(input) {
18
+ const replacement = `<context_gc kind="completed_code_mode_input" originalBytes="${Buffer.byteLength(input.code)}" lines="${lineCount(input.code)}" inputMode="${input.inputMode}">Completed Code Mode source was reclaimed after six successful rollouts. The paired output, images, completion evidence, and nested tool side effects remain in history.</context_gc>`;
19
+ return input.inputMode === 'freeform' ? replacement : { code: replacement };
20
+ }
21
+ export function contextGcCodeModeOutputReplacement(originalContent, truncated) {
22
+ const preview = unicodeHeadTail(originalContent, CODE_MODE_OUTPUT_PREVIEW_CHARACTERS);
23
+ return JSON.stringify({
24
+ originalBytes: Buffer.byteLength(originalContent),
25
+ lines: lineCount(originalContent),
26
+ truncated,
27
+ preview,
28
+ previewComplete: !truncated && preview === originalContent,
29
+ contextGc: 'Detailed Code Mode output was reclaimed after six successful rollouts. An incomplete preview is not the complete cell output. The source was not replayed and nested tool side effects were not changed.'
30
+ });
31
+ }
6
32
  export function contextGcPatchResultFromCompletedPayload(payload) {
7
33
  if (!isRecord(payload) || payload.type !== 'tool.completed')
8
34
  return undefined;
@@ -1,5 +1,6 @@
1
1
  import type { ModelUsage } from '../model/contracts.js';
2
2
  import type { EnvironmentContextState } from '../prompts/core.js';
3
+ import { type CodeModeStateEntry } from '../tools/code-mode/state.js';
3
4
  import { type TodoSnapshot } from '../tools/todo.js';
4
5
  import { type ContextGcCheckpointDraft } from './context-gc-checkpoint.js';
5
6
  import type { SessionListInput, SessionSource } from './types.js';
@@ -146,6 +147,11 @@ export declare class JsonlSessionStore {
146
147
  timestamp?: string;
147
148
  }): Promise<SessionRecord>;
148
149
  read(sessionId: string): Promise<SessionRecord[]>;
150
+ readCodeModeState(sessionId: string): Promise<CodeModeStateEntry[]>;
151
+ commitCodeModeState(sessionId: string, mutations: unknown, input: {
152
+ readonly executionId: string;
153
+ readonly turnId: string;
154
+ }): Promise<CodeModeStateEntry[]>;
149
155
  readExecutionState(sessionId: string): Promise<SessionExecutionState>;
150
156
  readContext(sessionId: string): Promise<SessionRecord[]>;
151
157
  contextGcProjectionHash(sessionId: string, boundarySequence: number): Promise<string>;