@myagentroam/agent 0.9.141 → 0.9.143
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/dist/agent-core/host/contracts.d.ts +64 -0
- package/dist/{host → agent-core/host}/local-agent-host.d.ts +6 -5
- package/dist/{host → agent-core/host}/local-agent-host.js +4 -4
- package/dist/{model → agent-core/model}/anthropic-messages.js +24 -13
- package/dist/{model → agent-core/model}/contracts.d.ts +6 -16
- package/dist/{model → agent-core/model}/openai-responses.js +16 -9
- package/dist/agent-core/model/recovery.d.ts +4 -0
- package/dist/agent-core/model/recovery.js +71 -0
- package/dist/{prompts → agent-core/prompts}/core.d.ts +3 -13
- package/dist/{prompts → agent-core/prompts}/index.d.ts +1 -1
- package/dist/{prompts → agent-core/prompts}/modes.d.ts +1 -1
- package/dist/{prompts → agent-core/prompts}/resources.d.ts +1 -1
- package/dist/{runtime/compact.d.ts → agent-core/runtime/compaction/history.d.ts} +2 -23
- package/dist/{runtime/compact.js → agent-core/runtime/compaction/history.js} +2 -92
- package/dist/agent-core/runtime/compaction/operation.d.ts +22 -0
- package/dist/agent-core/runtime/compaction/operation.js +91 -0
- package/dist/agent-core/runtime/context/contracts.d.ts +12 -0
- package/dist/{runtime/environment-context.d.ts → agent-core/runtime/context/environment.d.ts} +2 -2
- package/dist/{runtime/environment-context.js → agent-core/runtime/context/environment.js} +1 -1
- package/dist/{runtime/context-gc-runtime.d.ts → agent-core/runtime/context/gc-runtime.d.ts} +4 -4
- package/dist/{runtime/context-gc-runtime.js → agent-core/runtime/context/gc-runtime.js} +3 -3
- package/dist/{runtime/context-gc-tokens.d.ts → agent-core/runtime/context/gc-tokens.d.ts} +2 -2
- package/dist/{runtime/context-gc-tokens.js → agent-core/runtime/context/gc-tokens.js} +7 -5
- package/dist/{runtime/context-gc.d.ts → agent-core/runtime/context/gc.d.ts} +3 -3
- package/dist/{runtime/context-gc.js → agent-core/runtime/context/gc.js} +152 -19
- package/dist/{runtime → agent-core/runtime/context}/instructions.d.ts +1 -1
- package/dist/{runtime → agent-core/runtime/context}/instructions.js +1 -1
- package/dist/{runtime → agent-core/runtime/context}/normalize.d.ts +1 -1
- package/dist/{runtime/context-projection.d.ts → agent-core/runtime/context/projection.d.ts} +3 -3
- package/dist/{runtime/context-projection.js → agent-core/runtime/context/projection.js} +35 -4
- package/dist/agent-core/runtime/context/request-budget.d.ts +6 -0
- package/dist/agent-core/runtime/context/request-budget.js +22 -0
- package/dist/agent-core/runtime/context/restore.d.ts +15 -0
- package/dist/agent-core/runtime/context/restore.js +85 -0
- package/dist/agent-core/runtime/context/usage.d.ts +18 -0
- package/dist/agent-core/runtime/context/usage.js +138 -0
- package/dist/agent-core/runtime/context/world-state.d.ts +35 -0
- package/dist/agent-core/runtime/context/world-state.js +133 -0
- package/dist/agent-core/runtime/contracts.d.ts +37 -0
- package/dist/agent-core/runtime/event-projection.d.ts +5 -0
- package/dist/agent-core/runtime/event-projection.js +17 -0
- package/dist/agent-core/runtime/events.d.ts +143 -0
- package/dist/agent-core/runtime/execution.d.ts +50 -0
- package/dist/agent-core/runtime/execution.js +397 -0
- package/dist/{runtime → agent-core/runtime}/rollout-budget.d.ts +1 -1
- package/dist/agent-core/sdk/agent.js +209 -0
- package/dist/agent-core/sdk/model-runtime.d.ts +13 -0
- package/dist/agent-core/sdk/model-runtime.js +63 -0
- package/dist/agent-core/sdk/session-title.d.ts +3 -0
- package/dist/agent-core/sdk/session-title.js +42 -0
- package/dist/agent-core/sdk/session.d.ts +62 -0
- package/dist/agent-core/sdk/session.js +1147 -0
- package/dist/agent-core/sdk/subagent-backend.d.ts +3 -0
- package/dist/agent-core/sdk/subagent-backend.js +46 -0
- package/dist/agent-core/sdk/types.d.ts +56 -0
- package/dist/{session → agent-core/session}/catalog.d.ts +2 -1
- package/dist/{session → agent-core/session}/context-gc-checkpoint.d.ts +3 -0
- package/dist/{session → agent-core/session}/context-gc-checkpoint.js +122 -23
- package/dist/agent-core/session/context-gc-observations.d.ts +38 -0
- package/dist/agent-core/session/context-gc-observations.js +150 -0
- package/dist/{session → agent-core/session}/context-gc-replacements.d.ts +1 -1
- package/dist/{session → agent-core/session}/context-gc-replacements.js +6 -2
- package/dist/{session → agent-core/session}/jsonl-store.d.ts +2 -2
- package/dist/{session → agent-core/session}/jsonl-store.js +1 -1
- package/dist/agent-core/subagent/contracts.d.ts +91 -0
- package/dist/agent-core/subagent/contracts.js +1 -0
- package/dist/agent-core/subagent/scheduler.d.ts +117 -0
- package/dist/{subagent → agent-core/subagent}/session-controller.d.ts +3 -2
- package/dist/agent-core/tools/agent/agent-cancel.d.ts +7 -0
- package/dist/{tools → agent-core/tools/agent}/agent-cancel.js +1 -1
- package/dist/agent-core/tools/agent/agent-message.d.ts +7 -0
- package/dist/{tools → agent-core/tools/agent}/agent-message.js +2 -2
- package/dist/{tools → agent-core/tools/agent}/agent-start.d.ts +3 -3
- package/dist/{tools → agent-core/tools/agent}/agent-start.js +3 -3
- package/dist/agent-core/tools/agent/agent-wait.d.ts +7 -0
- package/dist/{tools → agent-core/tools/agent}/agent-wait.js +2 -2
- package/dist/{tools → agent-core/tools/agent}/question.d.ts +2 -2
- package/dist/{tools → agent-core/tools/agent}/question.js +2 -2
- package/dist/{tools → agent-core/tools/agent}/skill.d.ts +2 -2
- package/dist/{tools → agent-core/tools/agent}/skill.js +2 -2
- package/dist/{tools → agent-core/tools/agent}/todo-read.d.ts +2 -2
- package/dist/{tools → agent-core/tools/agent}/todo-write.d.ts +2 -2
- package/dist/{tools → agent-core/tools/agent}/todo-write.js +2 -2
- package/dist/{tools → agent-core/tools/agent}/todo.d.ts +2 -9
- package/dist/{tools → agent-core/tools/agent}/todo.js +1 -1
- package/dist/{tools → agent-core/tools}/code-mode/cells.d.ts +4 -1
- package/dist/{tools → agent-core/tools}/code-mode/cells.js +60 -6
- package/dist/{tools → agent-core/tools}/code-mode/dispatch.d.ts +2 -4
- package/dist/{tools → agent-core/tools}/code-mode/dispatch.js +10 -6
- package/dist/{tools → agent-core/tools}/code-mode/engine.d.ts +13 -1
- package/dist/agent-core/tools/code-mode/engine.js +1 -0
- package/dist/{tools/code-mode.d.ts → agent-core/tools/code-mode/index.d.ts} +7 -7
- package/dist/{tools/code-mode.js → agent-core/tools/code-mode/index.js} +190 -28
- package/dist/agent-core/tools/code-mode/observations.d.ts +103 -0
- package/dist/agent-core/tools/code-mode/observations.js +195 -0
- package/dist/{tools → agent-core/tools}/code-mode/quickjs-engine.js +91 -17
- package/dist/{tools → agent-core/tools}/code-mode/state.d.ts +2 -13
- package/dist/agent-core/tools/code-mode/worker.d.ts +1 -0
- package/dist/{tools → agent-core/tools}/code-mode/worker.js +8 -1
- package/dist/agent-core/tools/contracts.d.ts +172 -0
- package/dist/agent-core/tools/contracts.js +1 -0
- package/dist/agent-core/tools/execution.d.ts +36 -0
- package/dist/agent-core/tools/execution.js +111 -0
- package/dist/agent-core/tools/local/apply-patch.d.ts +19 -0
- package/dist/{tools → agent-core/tools/local}/apply-patch.js +8 -2
- package/dist/{tools → agent-core/tools/local}/exec.d.ts +5 -17
- package/dist/{tools → agent-core/tools/local}/exec.js +4 -4
- package/dist/{tools → agent-core/tools/local}/read.d.ts +7 -15
- package/dist/{tools → agent-core/tools/local}/read.js +185 -2
- package/dist/{tools/local-registry.d.ts → agent-core/tools/local/registry.d.ts} +5 -5
- package/dist/agent-core/tools/local/registry.js +101 -0
- package/dist/{tools → agent-core/tools/local}/view-image.d.ts +4 -9
- package/dist/{tools → agent-core/tools/local}/view-image.js +2 -2
- package/dist/agent-core/tools/local/web-fetch.d.ts +4 -0
- package/dist/agent-core/tools/local/web-fetch.js +85 -0
- package/dist/agent-core/tools/local/web-search.d.ts +7 -0
- package/dist/agent-core/tools/local/web-search.js +34 -0
- package/dist/{tools/local-workspace-tools.js → agent-core/tools/local/workspace-tools.js} +1 -1
- package/dist/{sdk/mcp-catalog.d.ts → agent-core/tools/mcp/catalog.d.ts} +1 -2
- package/dist/{sdk/mcp-catalog.js → agent-core/tools/mcp/catalog.js} +1 -1
- package/dist/agent-core/tools/mcp/history.d.ts +4 -0
- package/dist/agent-core/tools/mcp/history.js +33 -0
- package/dist/{tools → agent-core/tools/mcp}/tool-search.d.ts +3 -3
- package/dist/{tools → agent-core/tools/mcp}/tool-search.js +4 -4
- package/dist/agent-core/tools/output-projection.d.ts +14 -0
- package/dist/agent-core/tools/output-projection.js +223 -0
- package/dist/{tools → agent-core/tools}/registry.d.ts +1 -1
- package/dist/agent-core/tools/registry.js +47 -0
- package/dist/{tools → agent-core/tools}/runtime-context.d.ts +8 -7
- package/dist/agent-core/tools/runtime-context.js +1 -0
- package/dist/{tools → agent-core/tools}/runtime.d.ts +1 -1
- package/dist/cli/codex-auth-file.d.ts +1 -1
- package/dist/cli/codex-auth-file.js +2 -2
- package/dist/cli/main.js +9 -9
- package/dist/index.d.ts +17 -15
- package/dist/index.js +8 -8
- package/dist/sandbox/linux/bubblewrap-sandbox-executor.d.ts +1 -1
- package/dist/sandbox/linux/bubblewrap-sandbox-executor.js +1 -1
- package/package.json +3 -3
- package/dist/host/contracts.d.ts +0 -21
- package/dist/sdk/agent.js +0 -2548
- package/dist/sdk/types.d.ts +0 -349
- package/dist/subagent/scheduler.d.ts +0 -206
- package/dist/tools/agent-cancel.d.ts +0 -7
- package/dist/tools/agent-message.d.ts +0 -7
- package/dist/tools/agent-wait.d.ts +0 -7
- package/dist/tools/apply-patch.d.ts +0 -32
- package/dist/tools/local-registry.js +0 -373
- package/dist/tools/registry.js +0 -47
- package/dist/tools/web-fetch.d.ts +0 -2
- package/dist/tools/web-fetch.js +0 -12
- package/dist/tools/web-search.d.ts +0 -2
- package/dist/tools/web-search.js +0 -15
- /package/dist/{error.d.ts → agent-core/error.d.ts} +0 -0
- /package/dist/{error.js → agent-core/error.js} +0 -0
- /package/dist/{host → agent-core/host}/contracts.js +0 -0
- /package/dist/{host → agent-core/host}/local-process-executor.d.ts +0 -0
- /package/dist/{host → agent-core/host}/local-process-executor.js +0 -0
- /package/dist/{host → agent-core/host}/network.d.ts +0 -0
- /package/dist/{host → agent-core/host}/network.js +0 -0
- /package/dist/{model → agent-core/model}/anthropic-messages.d.ts +0 -0
- /package/dist/{model → agent-core/model}/anthropic-thinking.d.ts +0 -0
- /package/dist/{model → agent-core/model}/anthropic-thinking.js +0 -0
- /package/dist/{model → agent-core/model}/catalog-file.d.ts +0 -0
- /package/dist/{model → agent-core/model}/catalog-file.js +0 -0
- /package/dist/{model → agent-core/model}/configuration.d.ts +0 -0
- /package/dist/{model → agent-core/model}/configuration.js +0 -0
- /package/dist/{model → agent-core/model}/contracts.js +0 -0
- /package/dist/{model → agent-core/model}/http.d.ts +0 -0
- /package/dist/{model → agent-core/model}/http.js +0 -0
- /package/dist/{model → agent-core/model}/openai-responses.d.ts +0 -0
- /package/dist/{model → agent-core/model}/runtime-credential.d.ts +0 -0
- /package/dist/{model → agent-core/model}/runtime-credential.js +0 -0
- /package/dist/{model → agent-core/model}/sse.d.ts +0 -0
- /package/dist/{model → agent-core/model}/sse.js +0 -0
- /package/dist/{model → agent-core/model}/transport-test.d.ts +0 -0
- /package/dist/{model → agent-core/model}/transport-test.js +0 -0
- /package/dist/{prompts → agent-core/prompts}/compact.d.ts +0 -0
- /package/dist/{prompts → agent-core/prompts}/compact.js +0 -0
- /package/dist/{prompts → agent-core/prompts}/core.js +0 -0
- /package/dist/{prompts → agent-core/prompts}/execution-budget.d.ts +0 -0
- /package/dist/{prompts → agent-core/prompts}/execution-budget.js +0 -0
- /package/dist/{prompts → agent-core/prompts}/index.js +0 -0
- /package/dist/{prompts → agent-core/prompts}/modes.js +0 -0
- /package/dist/{prompts → agent-core/prompts}/output.d.ts +0 -0
- /package/dist/{prompts → agent-core/prompts}/output.js +0 -0
- /package/dist/{prompts → agent-core/prompts}/resources.js +0 -0
- /package/dist/{prompts → agent-core/prompts}/subagent.d.ts +0 -0
- /package/dist/{prompts → agent-core/prompts}/subagent.js +0 -0
- /package/dist/{prompts → agent-core/prompts}/title.d.ts +0 -0
- /package/dist/{prompts → agent-core/prompts}/title.js +0 -0
- /package/dist/{prompts → agent-core/prompts}/workflow.d.ts +0 -0
- /package/dist/{prompts → agent-core/prompts}/workflow.js +0 -0
- /package/dist/{runtime → agent-core/runtime}/async-queue.d.ts +0 -0
- /package/dist/{runtime → agent-core/runtime}/async-queue.js +0 -0
- /package/dist/{sdk/types.js → agent-core/runtime/context/contracts.js} +0 -0
- /package/dist/{runtime → agent-core/runtime/context}/normalize.js +0 -0
- /package/dist/{session/types.js → agent-core/runtime/contracts.js} +0 -0
- /package/dist/{tools/code-mode/engine.js → agent-core/runtime/events.js} +0 -0
- /package/dist/{runtime → agent-core/runtime}/execution-policy.d.ts +0 -0
- /package/dist/{runtime → agent-core/runtime}/execution-policy.js +0 -0
- /package/dist/{runtime → agent-core/runtime}/plan-output.d.ts +0 -0
- /package/dist/{runtime → agent-core/runtime}/plan-output.js +0 -0
- /package/dist/{runtime → agent-core/runtime}/rollout-budget.js +0 -0
- /package/dist/{runtime → agent-core/runtime}/token-budget.d.ts +0 -0
- /package/dist/{runtime → agent-core/runtime}/token-budget.js +0 -0
- /package/dist/{sdk → agent-core/sdk}/agent.d.ts +0 -0
- /package/dist/{tools/code-mode/worker.d.ts → agent-core/sdk/types.js} +0 -0
- /package/dist/{session → agent-core/session}/catalog.js +0 -0
- /package/dist/{session → agent-core/session}/context-gc-subagent.d.ts +0 -0
- /package/dist/{session → agent-core/session}/context-gc-subagent.js +0 -0
- /package/dist/{session → agent-core/session}/transaction-recovery.d.ts +0 -0
- /package/dist/{session → agent-core/session}/transaction-recovery.js +0 -0
- /package/dist/{session → agent-core/session}/types.d.ts +0 -0
- /package/dist/{tools/runtime-context.js → agent-core/session/types.js} +0 -0
- /package/dist/{subagent → agent-core/subagent}/scheduler.js +0 -0
- /package/dist/{subagent → agent-core/subagent}/session-controller.js +0 -0
- /package/dist/{tools → agent-core/tools/agent}/todo-read.js +0 -0
- /package/dist/{tools → agent-core/tools}/callers.d.ts +0 -0
- /package/dist/{tools → agent-core/tools}/callers.js +0 -0
- /package/dist/{tools → agent-core/tools}/code-mode/quickjs-engine.d.ts +0 -0
- /package/dist/{tools → agent-core/tools}/code-mode/state.js +0 -0
- /package/dist/{tools → agent-core/tools}/code-mode/text-output.d.ts +0 -0
- /package/dist/{tools → agent-core/tools}/code-mode/text-output.js +0 -0
- /package/dist/{tools → agent-core/tools}/execution-limits.d.ts +0 -0
- /package/dist/{tools → agent-core/tools}/execution-limits.js +0 -0
- /package/dist/{tools → agent-core/tools/local}/read-context.d.ts +0 -0
- /package/dist/{tools → agent-core/tools/local}/read-context.js +0 -0
- /package/dist/{tools/local-workspace-tools.d.ts → agent-core/tools/local/workspace-tools.d.ts} +0 -0
- /package/dist/{tools → agent-core/tools}/runtime.js +0 -0
- /package/dist/{tools → agent-core/tools}/scheduler.d.ts +0 -0
- /package/dist/{tools → agent-core/tools}/scheduler.js +0 -0
- /package/dist/{tools → agent-core/tools}/shared/path-resolver.d.ts +0 -0
- /package/dist/{tools → agent-core/tools}/shared/path-resolver.js +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { type LocalProcessExecutor } from '
|
|
2
|
-
import type { ClientToolDefinition, ModelMessage } from '
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import type {
|
|
6
|
-
import {
|
|
1
|
+
import { type LocalProcessExecutor } from '../../host/local-process-executor.js';
|
|
2
|
+
import type { ClientToolDefinition, ModelMessage } from '../../model/contracts.js';
|
|
3
|
+
import { type CellOutput } from './cells.js';
|
|
4
|
+
import type { CodeModeEngineFactory } from './engine.js';
|
|
5
|
+
import type { ToolExecutionContext, ToolExecutionResult } from '../contracts.js';
|
|
6
|
+
import { WorkspacePathResolver } from '../shared/path-resolver.js';
|
|
7
7
|
export declare const codeModeToolDefinition: ClientToolDefinition;
|
|
8
8
|
export declare const codeExecWaitToolDefinition: ClientToolDefinition;
|
|
9
9
|
/** Deferred definitions travel in search results, not in the stable Code Mode description. */
|
|
@@ -20,7 +20,7 @@ export declare class CodeModeTool {
|
|
|
20
20
|
wait(value: unknown, context: ToolExecutionContext): Promise<ToolExecutionResult>;
|
|
21
21
|
listSessionResources(sessionId: string): {
|
|
22
22
|
cellId: string;
|
|
23
|
-
status: "completed" | "
|
|
23
|
+
status: "completed" | "failed" | "cancelled" | "running";
|
|
24
24
|
executionId: string;
|
|
25
25
|
}[];
|
|
26
26
|
constructor(paths: WorkspacePathResolver, environment?: NodeJS.ProcessEnv, executor?: LocalProcessExecutor, engineFactory?: CodeModeEngineFactory);
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { createRequire } from 'node:module';
|
|
3
|
-
import { pathToFileURL } from 'node:url';
|
|
4
2
|
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
5
4
|
import { dirname, sep } from 'node:path';
|
|
6
|
-
import { fileURLToPath } from 'node:url';
|
|
7
5
|
import { StringDecoder } from 'node:string_decoder';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { BoundedTextOutput, renderCapturedText } from './
|
|
16
|
-
import {
|
|
6
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
7
|
+
import { MarAgentError, describeMarAgentError } from '../../error.js';
|
|
8
|
+
import { directLocalProcessExecutor, signalProcessTree } from '../../host/local-process-executor.js';
|
|
9
|
+
import { allowsDirectTool, allowsToolCaller } from '../callers.js';
|
|
10
|
+
import { CodeCells } from './cells.js';
|
|
11
|
+
import { newObservationId, renderObservations } from './observations.js';
|
|
12
|
+
import { parseCodeModeStateMutations } from './state.js';
|
|
13
|
+
import { BoundedTextOutput, renderCapturedText } from './text-output.js';
|
|
14
|
+
import { TOOL_EXECUTION_LIMITS as limits } from '../execution-limits.js';
|
|
15
|
+
import { createToolCallScheduler } from '../scheduler.js';
|
|
16
|
+
import { detectImageMime } from '../local/view-image.js';
|
|
17
17
|
export const codeModeToolDefinition = {
|
|
18
18
|
name: 'code_exec',
|
|
19
19
|
description: `Run JavaScript to orchestrate or compose tool calls.
|
|
@@ -21,7 +21,7 @@ export const codeModeToolDefinition = {
|
|
|
21
21
|
- Use bounded combinations, parallel independent calls, and filtering of large intermediate results to reduce model round trips.
|
|
22
22
|
- Evaluates source in a fresh restricted ECMAScript runtime with top-level await and Promise.all. It is not Node.js or a browser. JavaScript globals do not survive between cells; bounded JSON state is available through state.
|
|
23
23
|
- Accepts raw JavaScript source text, not JSON, quoted strings, or markdown code fences. Responses uses the source directly; Anthropic uses the code field of its tool input object. In either case, do not quote or fence the source again.
|
|
24
|
-
- Use only standard ECMAScript built-ins and the explicitly documented tools,
|
|
24
|
+
- Use only standard ECMAScript built-ins and the explicitly documented tools, observe, state, catalog and cell namespaces. Do not use Node.js, browser or Web APIs. Module imports, filesystem and network APIs are unavailable. Obtain external capabilities only through available tools. Use tools.exec to start managed processes when permitted; use tools.exec_wait afterward to wait, write stdin or cancel.
|
|
25
25
|
|
|
26
26
|
Tool calls:
|
|
27
27
|
- tools.NAME(input) returns a Promise. Use the existing tool input schema; freeform tools such as apply_patch accept a raw string, not a JSON wrapper.
|
|
@@ -30,25 +30,26 @@ Tool calls:
|
|
|
30
30
|
- skill, tool_search, question, code_exec, code_exec_wait and direct-only tools cannot be called here. Load Skills directly and read their instructions before the next tool call. Use direct tool_search before a later code cell for deferred tools; the current cell's tools do not change.
|
|
31
31
|
|
|
32
32
|
Built-in namespaces:
|
|
33
|
-
-
|
|
34
|
-
-
|
|
33
|
+
- observe.result(result): void registers an unmodified complete tools.NAME result or caught tool error as a trusted tool_result, using the original text and all images without repeating program data. Non-original, copied or modified values are rejected. This selects evidence for the next model response, not a log and not a new model call.
|
|
34
|
+
- observe.text(value): void registers bounded text/JSON values. observe.image(value): void registers one image value using the existing capability, MIME, byte and count limits. Both accept original tool results for compatibility and use the same complete tool_result observation path; they do not select part of an original result. Extracted single images, copies and computed summaries are value observations, never trusted tool results. Observations are returned in registration order. Only explicitly observed evidence reaches the model; registration does not prove inspection. Sources and types are runtime-assigned. No out or callable observe(value) alias exists.
|
|
35
35
|
- state.get(key), state.has(key), state.set(key, value), state.delete(key) access bounded session JSON state. Mutations commit atomically only when the cell succeeds; failed or cancelled cells discard them.
|
|
36
36
|
- catalog.tools() returns a read-only snapshot of the tools callable in this cell, including name, description, inputSchema and inputMode. It does not discover or authorize additional tools.
|
|
37
37
|
- await cell.sleep(ms) performs a cancellable Host-side delay up to 30000 ms and remains subject to the cell deadline.
|
|
38
38
|
- await cell.yield_control() returns accumulated output to the model immediately while this cell continues running.
|
|
39
39
|
- Optionally start source with // @options: {"yieldMs": ${limits.codeDefaultYieldMs}, "maxOutputTokens": 10000}. yieldMs defaults to ${limits.codeDefaultYieldMs} ms and is a wait window (0..${limits.codeMaxYieldMs}), not a cell timeout. Explicit values are preserved and do not change nested tools' wait windows. A running result includes cellId; use direct code_exec_wait for new output, completion or termination.
|
|
40
40
|
- Registered cells are Session warm resources: ending or cancelling the model Execution cancels its wait, not the cell. Reuse retained cellId; do not start duplicate work. Host cleanup or explicit termination stops the cell.
|
|
41
|
-
- tools,
|
|
41
|
+
- tools, observe, state, catalog and cell are frozen bindings. Do not shadow their names.
|
|
42
42
|
- Input max 1 MiB; cumulative text capture max 1 MiB with truncation; 128 calls, 120 seconds. Tool-specific limits apply before explicit text capture. Protocol, image, memory and time limits remain hard failures. Failures do not roll back completed tool work; do not replay successful operations blindly.
|
|
43
43
|
|
|
44
44
|
Examples (copy the JavaScript source, not the fences; use only tools available in the current directory):
|
|
45
|
-
Independent reads,
|
|
45
|
+
Independent reads, observing the original tool results:
|
|
46
46
|
\`\`\`js
|
|
47
47
|
const [a, b] = await Promise.all([
|
|
48
48
|
tools.read({ reads: [{ path: "a.txt" }] }),
|
|
49
49
|
tools.read({ reads: [{ path: "b.txt" }] })
|
|
50
50
|
]);
|
|
51
|
-
|
|
51
|
+
observe.result(a);
|
|
52
|
+
observe.result(b);
|
|
52
53
|
\`\`\`
|
|
53
54
|
Inspect before a dependent edit; successful await needs no invented success flag:
|
|
54
55
|
\`\`\`js
|
|
@@ -56,7 +57,7 @@ const inspected = await tools.read({ reads: [{ path: "source.txt" }] });
|
|
|
56
57
|
const sourceText = inspected.data.results[0].text;
|
|
57
58
|
if (!sourceText?.includes("original=1")) throw new Error("Unexpected source");
|
|
58
59
|
const patched = await tools.apply_patch("*** Begin Patch\\n*** Update File: source.txt\\n@@\\n original=1\\n+updated=2\\n*** End Patch");
|
|
59
|
-
|
|
60
|
+
observe.result(patched);
|
|
60
61
|
\`\`\``,
|
|
61
62
|
inputMode: 'freeform',
|
|
62
63
|
inputSchema: {
|
|
@@ -154,10 +155,10 @@ function defaultEngineFactory() {
|
|
|
154
155
|
return root.includes(`${sep}.pnpm${sep}`) ? dirname(dirname(root)) : root;
|
|
155
156
|
};
|
|
156
157
|
return {
|
|
157
|
-
moduleUrl: new URL('./
|
|
158
|
+
moduleUrl: new URL('./quickjs-engine.js', import.meta.url).href,
|
|
158
159
|
runtimeDirectories: [
|
|
159
160
|
...new Set([
|
|
160
|
-
fileURLToPath(new URL('
|
|
161
|
+
fileURLToPath(new URL('.', import.meta.url)),
|
|
161
162
|
dependencyRoot(core),
|
|
162
163
|
dependencyRoot(variant),
|
|
163
164
|
dependencyRoot(ffi)
|
|
@@ -255,7 +256,7 @@ export class CodeModeTool {
|
|
|
255
256
|
`--max-old-space-size=${limits.codeHeapMegabytes}`,
|
|
256
257
|
'--input-type=module',
|
|
257
258
|
'--eval',
|
|
258
|
-
await readFile(new URL('./
|
|
259
|
+
await readFile(new URL('./worker.js', import.meta.url), 'utf8')
|
|
259
260
|
],
|
|
260
261
|
cwd,
|
|
261
262
|
shell: false,
|
|
@@ -268,6 +269,34 @@ export class CodeModeTool {
|
|
|
268
269
|
});
|
|
269
270
|
const text = new BoundedTextOutput(limits.codeMaxOutputBytes);
|
|
270
271
|
const images = [];
|
|
272
|
+
const observations = [];
|
|
273
|
+
let observationBytes = 0;
|
|
274
|
+
const appendObservation = (value, originalBytes) => {
|
|
275
|
+
const capture = new BoundedTextOutput(Math.max(0, limits.codeMaxOutputBytes - observationBytes), '');
|
|
276
|
+
const body = value.type === 'tool_result' ? value.result.content : value.value;
|
|
277
|
+
capture.append(body);
|
|
278
|
+
const bounded = capture.snapshot();
|
|
279
|
+
observationBytes += bounded.retainedBytes;
|
|
280
|
+
text.append(body, originalBytes ?? Buffer.byteLength(body));
|
|
281
|
+
output?.text(body, originalBytes ?? Buffer.byteLength(body));
|
|
282
|
+
const observation = value.type === 'tool_result'
|
|
283
|
+
? {
|
|
284
|
+
...value,
|
|
285
|
+
result: {
|
|
286
|
+
...value.result,
|
|
287
|
+
content: bounded.text,
|
|
288
|
+
truncated: value.result.truncated === true || bounded.droppedBytes > 0
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
: {
|
|
292
|
+
...value,
|
|
293
|
+
value: bounded.text,
|
|
294
|
+
truncated: value.truncated === true || bounded.droppedBytes > 0
|
|
295
|
+
};
|
|
296
|
+
observations.push(observation);
|
|
297
|
+
output?.observe(observation);
|
|
298
|
+
};
|
|
299
|
+
const toolResults = new Map();
|
|
271
300
|
let transportBytes = 0;
|
|
272
301
|
let calls = 0;
|
|
273
302
|
let complete = false;
|
|
@@ -317,13 +346,94 @@ export class CodeModeTool {
|
|
|
317
346
|
const receive = (frame) => {
|
|
318
347
|
if (complete)
|
|
319
348
|
throw new MarAgentError('MAR_AGENT_CODE_PROTOCOL_ERROR', 'Code Mode sent data after completion.');
|
|
320
|
-
if (frame.kind === '
|
|
349
|
+
if (frame.kind === 'observe' && frame.observation && typeof frame.observation === 'object') {
|
|
350
|
+
const value = frame.observation;
|
|
351
|
+
if (observations.length >= 4096)
|
|
352
|
+
throw new MarAgentError('MAR_AGENT_TOOL_OUTPUT_LIMIT', 'Too many Code Mode observations.');
|
|
353
|
+
const addImage = (raw) => {
|
|
354
|
+
if (!context.codeMode?.supportsImages)
|
|
355
|
+
throw new MarAgentError('MAR_AGENT_INPUT_CAPABILITY_UNSUPPORTED', 'The current model cannot receive image observations.');
|
|
356
|
+
if (images.length >= 5)
|
|
357
|
+
throw new MarAgentError('MAR_AGENT_TOOL_OUTPUT_LIMIT', 'Code Mode emitted too many images.');
|
|
358
|
+
const image = parseImage(raw);
|
|
359
|
+
const index = images.length;
|
|
360
|
+
images.push(image);
|
|
361
|
+
output?.image(image);
|
|
362
|
+
return index;
|
|
363
|
+
};
|
|
364
|
+
let observation;
|
|
365
|
+
if (value.type === 'tool_result' && typeof value.operationId === 'string') {
|
|
366
|
+
const original = toolResults.get(value.operationId);
|
|
367
|
+
if (!original)
|
|
368
|
+
throw new MarAgentError('MAR_AGENT_CODE_PROTOCOL_ERROR', 'Unknown observation source.');
|
|
369
|
+
const bounded = {
|
|
370
|
+
content: original.result.content,
|
|
371
|
+
truncated: original.result.truncated === true
|
|
372
|
+
};
|
|
373
|
+
const indices = original.result.images?.map(addImage);
|
|
374
|
+
const data = [
|
|
375
|
+
'apply_patch',
|
|
376
|
+
'todo_read',
|
|
377
|
+
'todo_write',
|
|
378
|
+
'agent_start',
|
|
379
|
+
'agent_wait',
|
|
380
|
+
'agent_message',
|
|
381
|
+
'agent_cancel'
|
|
382
|
+
].includes(original.source.toolName)
|
|
383
|
+
? original.result.data
|
|
384
|
+
: undefined;
|
|
385
|
+
observation = {
|
|
386
|
+
type: 'tool_result',
|
|
387
|
+
id: newObservationId(),
|
|
388
|
+
source: original.source,
|
|
389
|
+
outcome: original.outcome,
|
|
390
|
+
result: {
|
|
391
|
+
content: bounded.content,
|
|
392
|
+
truncated: original.result.truncated === true || bounded.truncated,
|
|
393
|
+
...(data === undefined ? {} : { data }),
|
|
394
|
+
...(indices?.length ? { imageIndices: indices } : {})
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
else if (value.type === 'image') {
|
|
399
|
+
observation = {
|
|
400
|
+
type: 'value',
|
|
401
|
+
id: newObservationId(),
|
|
402
|
+
format: 'image',
|
|
403
|
+
value: '',
|
|
404
|
+
imageIndices: [addImage(value.value)]
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
else if (value.type === 'value' &&
|
|
408
|
+
typeof value.value === 'string' &&
|
|
409
|
+
['text', 'json'].includes(String(value.format))) {
|
|
410
|
+
observation = {
|
|
411
|
+
type: 'value',
|
|
412
|
+
id: newObservationId(),
|
|
413
|
+
format: value.format,
|
|
414
|
+
value: value.value,
|
|
415
|
+
truncated: typeof value.originalBytes === 'number' &&
|
|
416
|
+
value.originalBytes > Buffer.byteLength(value.value)
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
else
|
|
420
|
+
throw new MarAgentError('MAR_AGENT_CODE_PROTOCOL_ERROR', 'Invalid observation frame.');
|
|
421
|
+
appendObservation(observation, value.type === 'value' && typeof value.originalBytes === 'number'
|
|
422
|
+
? value.originalBytes
|
|
423
|
+
: undefined);
|
|
424
|
+
}
|
|
425
|
+
else if (frame.kind === 'text' && typeof frame.value === 'string') {
|
|
321
426
|
const originalBytes = frame.originalBytes ?? Buffer.byteLength(frame.value);
|
|
322
427
|
if (!Number.isSafeInteger(originalBytes) ||
|
|
323
428
|
originalBytes < Buffer.byteLength(frame.value))
|
|
324
429
|
throw new MarAgentError('MAR_AGENT_CODE_PROTOCOL_ERROR', 'Code Mode sent invalid text byte counts.');
|
|
325
|
-
|
|
326
|
-
|
|
430
|
+
appendObservation({
|
|
431
|
+
type: 'value',
|
|
432
|
+
id: newObservationId(),
|
|
433
|
+
format: 'text',
|
|
434
|
+
value: frame.value,
|
|
435
|
+
truncated: originalBytes > Buffer.byteLength(frame.value)
|
|
436
|
+
}, originalBytes);
|
|
327
437
|
}
|
|
328
438
|
else if (frame.kind === 'image') {
|
|
329
439
|
if (!context.codeMode?.supportsImages)
|
|
@@ -333,6 +443,13 @@ export class CodeModeTool {
|
|
|
333
443
|
throw new MarAgentError('MAR_AGENT_TOOL_OUTPUT_LIMIT', 'Code Mode emitted too many images.');
|
|
334
444
|
images.push(image);
|
|
335
445
|
output?.image(image);
|
|
446
|
+
appendObservation({
|
|
447
|
+
type: 'value',
|
|
448
|
+
id: newObservationId(),
|
|
449
|
+
format: 'image',
|
|
450
|
+
value: '',
|
|
451
|
+
imageIndices: [images.length - 1]
|
|
452
|
+
});
|
|
336
453
|
}
|
|
337
454
|
else if (frame.kind === 'yield') {
|
|
338
455
|
output?.yield();
|
|
@@ -344,6 +461,14 @@ export class CodeModeTool {
|
|
|
344
461
|
if (seen.has(id) || ++calls > limits.codeMaxCalls)
|
|
345
462
|
throw new MarAgentError('MAR_AGENT_CODE_PROTOCOL_ERROR', 'Code Mode call ID or call count is invalid.');
|
|
346
463
|
seen.add(id);
|
|
464
|
+
const source = {
|
|
465
|
+
callId: randomUUID(),
|
|
466
|
+
toolName: frame.name,
|
|
467
|
+
input: frame.arguments
|
|
468
|
+
};
|
|
469
|
+
const operationId = typeof frame.operationId === 'string' ? frame.operationId : String(id);
|
|
470
|
+
const recordCall = (value) => output?.call(value);
|
|
471
|
+
recordCall({ ...source, status: 'running' });
|
|
347
472
|
const job = (async () => {
|
|
348
473
|
try {
|
|
349
474
|
if (frame.name === 'code_exec' || !available.has(frame.name))
|
|
@@ -351,7 +476,27 @@ export class CodeModeTool {
|
|
|
351
476
|
const output = await invoke({
|
|
352
477
|
name: frame.name,
|
|
353
478
|
arguments: frame.arguments,
|
|
354
|
-
callId:
|
|
479
|
+
callId: source.callId
|
|
480
|
+
});
|
|
481
|
+
toolResults.set(operationId, { source, outcome: 'completed', result: output });
|
|
482
|
+
recordCall({
|
|
483
|
+
...source,
|
|
484
|
+
status: 'completed',
|
|
485
|
+
result: {
|
|
486
|
+
content: '',
|
|
487
|
+
truncated: output.truncated === true,
|
|
488
|
+
data: [
|
|
489
|
+
'apply_patch',
|
|
490
|
+
'todo_read',
|
|
491
|
+
'todo_write',
|
|
492
|
+
'agent_start',
|
|
493
|
+
'agent_wait',
|
|
494
|
+
'agent_message',
|
|
495
|
+
'agent_cancel'
|
|
496
|
+
].includes(source.toolName)
|
|
497
|
+
? output.data
|
|
498
|
+
: undefined
|
|
499
|
+
}
|
|
355
500
|
});
|
|
356
501
|
const { content, ...structured } = output;
|
|
357
502
|
const projected = output.data !== undefined && content === JSON.stringify(output.data)
|
|
@@ -360,9 +505,24 @@ export class CodeModeTool {
|
|
|
360
505
|
await write({ id, ok: true, output: projected });
|
|
361
506
|
}
|
|
362
507
|
catch (error) {
|
|
508
|
+
// Serialization/transport failures cannot undo an already completed tool call.
|
|
509
|
+
if (toolResults.get(operationId)?.outcome === 'completed')
|
|
510
|
+
throw error;
|
|
363
511
|
if (context.signal.aborted)
|
|
364
512
|
return;
|
|
365
513
|
const diagnostic = describeMarAgentError(error, 'MAR_AGENT_HOST_OPERATION_FAILED');
|
|
514
|
+
recordCall({
|
|
515
|
+
...source,
|
|
516
|
+
status: 'failed',
|
|
517
|
+
error: { code: diagnostic.code, message: diagnostic.message }
|
|
518
|
+
});
|
|
519
|
+
toolResults.set(operationId, {
|
|
520
|
+
source,
|
|
521
|
+
outcome: 'failed',
|
|
522
|
+
result: {
|
|
523
|
+
content: JSON.stringify({ error: diagnostic.code, message: diagnostic.message })
|
|
524
|
+
}
|
|
525
|
+
});
|
|
366
526
|
await write({
|
|
367
527
|
id,
|
|
368
528
|
ok: false,
|
|
@@ -471,8 +631,10 @@ export class CodeModeTool {
|
|
|
471
631
|
await context.codeMode.commitState?.(stateMutations);
|
|
472
632
|
const captured = text.snapshot();
|
|
473
633
|
return {
|
|
474
|
-
content:
|
|
475
|
-
|
|
634
|
+
content: observations.length
|
|
635
|
+
? renderObservations(observations)
|
|
636
|
+
: renderCapturedText(captured, images.length) || '[]',
|
|
637
|
+
observations,
|
|
476
638
|
data: {
|
|
477
639
|
toolCalls: calls,
|
|
478
640
|
outputBytes: captured.originalBytes,
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/** Execution metadata is independent of explicit model observations. */
|
|
2
|
+
export interface CodeToolCallRecord {
|
|
3
|
+
callId: string;
|
|
4
|
+
toolName: string;
|
|
5
|
+
input: unknown;
|
|
6
|
+
status: 'running' | 'completed' | 'failed';
|
|
7
|
+
result?: {
|
|
8
|
+
content: string;
|
|
9
|
+
data?: unknown;
|
|
10
|
+
truncated?: boolean;
|
|
11
|
+
};
|
|
12
|
+
error?: {
|
|
13
|
+
code: string;
|
|
14
|
+
message: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export declare function parseCodeCalls(value: unknown): CodeToolCallRecord[] | undefined;
|
|
18
|
+
export type CodeObservation = {
|
|
19
|
+
type: 'tool_result';
|
|
20
|
+
id: string;
|
|
21
|
+
source: {
|
|
22
|
+
callId: string;
|
|
23
|
+
toolName: string;
|
|
24
|
+
input: unknown;
|
|
25
|
+
};
|
|
26
|
+
outcome: 'completed' | 'failed';
|
|
27
|
+
result: {
|
|
28
|
+
content: string;
|
|
29
|
+
data?: unknown;
|
|
30
|
+
truncated?: boolean;
|
|
31
|
+
imageIndices?: number[];
|
|
32
|
+
};
|
|
33
|
+
} | {
|
|
34
|
+
type: 'value';
|
|
35
|
+
id: string;
|
|
36
|
+
format: 'text' | 'json' | 'image';
|
|
37
|
+
value: string;
|
|
38
|
+
truncated?: boolean;
|
|
39
|
+
imageIndices?: number[];
|
|
40
|
+
};
|
|
41
|
+
export declare function observationContent(value: CodeObservation): string;
|
|
42
|
+
export declare function observationImages(value: CodeObservation): readonly number[];
|
|
43
|
+
export declare function selectObservationImages(values: readonly CodeObservation[], images: readonly {
|
|
44
|
+
mimeType: string;
|
|
45
|
+
dataBase64: string;
|
|
46
|
+
}[], offset?: number): {
|
|
47
|
+
observations: ({
|
|
48
|
+
result: {
|
|
49
|
+
imageIndices: number[];
|
|
50
|
+
content: string;
|
|
51
|
+
data?: unknown;
|
|
52
|
+
truncated?: boolean;
|
|
53
|
+
};
|
|
54
|
+
type: "tool_result";
|
|
55
|
+
id: string;
|
|
56
|
+
source: {
|
|
57
|
+
callId: string;
|
|
58
|
+
toolName: string;
|
|
59
|
+
input: unknown;
|
|
60
|
+
};
|
|
61
|
+
outcome: "completed" | "failed";
|
|
62
|
+
} | {
|
|
63
|
+
imageIndices: number[];
|
|
64
|
+
type: "value";
|
|
65
|
+
id: string;
|
|
66
|
+
format: "text" | "json" | "image";
|
|
67
|
+
value: string;
|
|
68
|
+
truncated?: boolean;
|
|
69
|
+
})[];
|
|
70
|
+
images: {
|
|
71
|
+
mimeType: string;
|
|
72
|
+
dataBase64: string;
|
|
73
|
+
}[];
|
|
74
|
+
};
|
|
75
|
+
/** Only the visible projection crosses into model text; program data and inputs stay private. */
|
|
76
|
+
export declare function visibleObservation(value: CodeObservation): Record<string, unknown>;
|
|
77
|
+
export declare function renderObservations(values: readonly CodeObservation[]): string;
|
|
78
|
+
export declare function renderObservationResult(values: readonly CodeObservation[], original: string): string;
|
|
79
|
+
/** Truncate each body before encoding, never a JSON array or its trusted identity. */
|
|
80
|
+
export declare function boundObservations(values: readonly CodeObservation[], maximumTokens: number): {
|
|
81
|
+
observations: CodeObservation[];
|
|
82
|
+
content: string;
|
|
83
|
+
truncated: boolean;
|
|
84
|
+
};
|
|
85
|
+
export declare function newObservationId(): string;
|
|
86
|
+
export declare function observationModelParts(message: {
|
|
87
|
+
content?: string;
|
|
88
|
+
observations?: readonly CodeObservation[];
|
|
89
|
+
images?: readonly {
|
|
90
|
+
mimeType: string;
|
|
91
|
+
dataBase64: string;
|
|
92
|
+
}[];
|
|
93
|
+
}): Array<{
|
|
94
|
+
type: 'text';
|
|
95
|
+
text: string;
|
|
96
|
+
} | {
|
|
97
|
+
type: 'image';
|
|
98
|
+
image: {
|
|
99
|
+
mimeType: string;
|
|
100
|
+
dataBase64: string;
|
|
101
|
+
};
|
|
102
|
+
}> | undefined;
|
|
103
|
+
export declare function parseObservations(value: unknown): CodeObservation[] | undefined;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { truncateModelText, countModelTokens } from '../../runtime/token-budget.js';
|
|
3
|
+
export function parseCodeCalls(value) {
|
|
4
|
+
if (!Array.isArray(value) || value.length > 128)
|
|
5
|
+
return undefined;
|
|
6
|
+
const ids = new Set();
|
|
7
|
+
for (const item of value) {
|
|
8
|
+
if (!item ||
|
|
9
|
+
typeof item !== 'object' ||
|
|
10
|
+
typeof item.callId !== 'string' ||
|
|
11
|
+
!item.callId ||
|
|
12
|
+
ids.has(item.callId) ||
|
|
13
|
+
typeof item.toolName !== 'string' ||
|
|
14
|
+
!['running', 'completed', 'failed'].includes(item.status))
|
|
15
|
+
return undefined;
|
|
16
|
+
if (item.result !== undefined && (!item.result || typeof item.result.content !== 'string'))
|
|
17
|
+
return undefined;
|
|
18
|
+
ids.add(item.callId);
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
export function observationContent(value) {
|
|
23
|
+
return value.type === 'tool_result' ? value.result.content : value.value;
|
|
24
|
+
}
|
|
25
|
+
export function observationImages(value) {
|
|
26
|
+
return value.type === 'tool_result'
|
|
27
|
+
? (value.result.imageIndices ?? [])
|
|
28
|
+
: (value.imageIndices ?? []);
|
|
29
|
+
}
|
|
30
|
+
export function selectObservationImages(values, images, offset = 0) {
|
|
31
|
+
const selected = [];
|
|
32
|
+
const indices = new Map();
|
|
33
|
+
const observations = values.map((value) => {
|
|
34
|
+
const remap = observationImages(value).flatMap((index) => {
|
|
35
|
+
const image = images[index - offset];
|
|
36
|
+
if (!image)
|
|
37
|
+
return [];
|
|
38
|
+
let next = indices.get(index);
|
|
39
|
+
if (next === undefined) {
|
|
40
|
+
next = selected.length;
|
|
41
|
+
indices.set(index, next);
|
|
42
|
+
selected.push(image);
|
|
43
|
+
}
|
|
44
|
+
return [next];
|
|
45
|
+
});
|
|
46
|
+
return value.type === 'tool_result'
|
|
47
|
+
? { ...value, result: { ...value.result, imageIndices: remap } }
|
|
48
|
+
: { ...value, imageIndices: remap };
|
|
49
|
+
});
|
|
50
|
+
return { observations, images: selected };
|
|
51
|
+
}
|
|
52
|
+
/** Only the visible projection crosses into model text; program data and inputs stay private. */
|
|
53
|
+
export function visibleObservation(value) {
|
|
54
|
+
return value.type === 'tool_result'
|
|
55
|
+
? {
|
|
56
|
+
type: value.type,
|
|
57
|
+
toolName: value.source.toolName,
|
|
58
|
+
outcome: value.outcome,
|
|
59
|
+
content: value.result.content,
|
|
60
|
+
...(value.result.truncated ? { truncated: true } : {})
|
|
61
|
+
}
|
|
62
|
+
: {
|
|
63
|
+
type: value.type,
|
|
64
|
+
format: value.format,
|
|
65
|
+
value: value.value,
|
|
66
|
+
...(value.truncated ? { truncated: true } : {})
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export function renderObservations(values) {
|
|
70
|
+
return JSON.stringify(values.map(visibleObservation));
|
|
71
|
+
}
|
|
72
|
+
export function renderObservationResult(values, original) {
|
|
73
|
+
try {
|
|
74
|
+
const envelope = JSON.parse(original);
|
|
75
|
+
if (envelope && !Array.isArray(envelope) && typeof envelope === 'object')
|
|
76
|
+
return JSON.stringify({ ...envelope, observations: values.map(visibleObservation) });
|
|
77
|
+
}
|
|
78
|
+
catch { }
|
|
79
|
+
return renderObservations(values);
|
|
80
|
+
}
|
|
81
|
+
/** Truncate each body before encoding, never a JSON array or its trusted identity. */
|
|
82
|
+
export function boundObservations(values, maximumTokens) {
|
|
83
|
+
let remaining = Math.max(0, maximumTokens - 2);
|
|
84
|
+
let truncated = false;
|
|
85
|
+
const observations = [];
|
|
86
|
+
const selected = [];
|
|
87
|
+
let overheadBudget = 0;
|
|
88
|
+
for (const original of values) {
|
|
89
|
+
const empty = original.type === 'tool_result'
|
|
90
|
+
? { ...original, result: { ...original.result, content: '', truncated: true } }
|
|
91
|
+
: { ...original, value: '', truncated: true };
|
|
92
|
+
const overhead = countModelTokens(JSON.stringify(visibleObservation(empty))) + 8;
|
|
93
|
+
if (overheadBudget + overhead > remaining) {
|
|
94
|
+
truncated = true;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
selected.push({ original, overhead });
|
|
98
|
+
overheadBudget += overhead;
|
|
99
|
+
}
|
|
100
|
+
for (const { original, overhead } of selected) {
|
|
101
|
+
let bodyBudget = Math.max(0, remaining - overheadBudget - 12);
|
|
102
|
+
let value;
|
|
103
|
+
let bodyTruncated = false;
|
|
104
|
+
for (;;) {
|
|
105
|
+
const bounded = truncateModelText(observationContent(original), bodyBudget);
|
|
106
|
+
bodyTruncated ||= bounded.truncated;
|
|
107
|
+
value =
|
|
108
|
+
original.type === 'tool_result'
|
|
109
|
+
? {
|
|
110
|
+
...original,
|
|
111
|
+
result: {
|
|
112
|
+
...original.result,
|
|
113
|
+
content: bounded.content,
|
|
114
|
+
truncated: original.result.truncated === true || bodyTruncated
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
: {
|
|
118
|
+
...original,
|
|
119
|
+
value: bounded.content,
|
|
120
|
+
truncated: original.truncated === true || bodyTruncated
|
|
121
|
+
};
|
|
122
|
+
if (countModelTokens(JSON.stringify(visibleObservation(value))) + 1 <=
|
|
123
|
+
remaining - (overheadBudget - overhead) ||
|
|
124
|
+
bodyBudget === 0)
|
|
125
|
+
break;
|
|
126
|
+
bodyBudget = Math.floor(bodyBudget / 2);
|
|
127
|
+
}
|
|
128
|
+
overheadBudget -= overhead;
|
|
129
|
+
observations.push(value);
|
|
130
|
+
remaining -= countModelTokens(JSON.stringify(visibleObservation(value))) + 1;
|
|
131
|
+
truncated ||=
|
|
132
|
+
bodyTruncated ||
|
|
133
|
+
(original.type === 'tool_result'
|
|
134
|
+
? original.result.truncated === true
|
|
135
|
+
: original.truncated === true);
|
|
136
|
+
}
|
|
137
|
+
return { observations, content: renderObservations(observations), truncated };
|
|
138
|
+
}
|
|
139
|
+
export function newObservationId() {
|
|
140
|
+
return randomUUID();
|
|
141
|
+
}
|
|
142
|
+
export function observationModelParts(message) {
|
|
143
|
+
if (!message.observations || !message.images?.length)
|
|
144
|
+
return undefined;
|
|
145
|
+
const prefix = [];
|
|
146
|
+
try {
|
|
147
|
+
const parsed = JSON.parse(message.content ?? '');
|
|
148
|
+
if (parsed && !Array.isArray(parsed) && typeof parsed === 'object') {
|
|
149
|
+
const { observations: _observations, ...metadata } = parsed;
|
|
150
|
+
prefix.push({ type: 'text', text: JSON.stringify(metadata) });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch { }
|
|
154
|
+
return [
|
|
155
|
+
...prefix,
|
|
156
|
+
...message.observations.flatMap((value) => {
|
|
157
|
+
const parts = [{ type: 'text', text: JSON.stringify(visibleObservation(value)) }];
|
|
158
|
+
for (const index of observationImages(value)) {
|
|
159
|
+
const image = message.images?.[index];
|
|
160
|
+
if (image)
|
|
161
|
+
parts.push({ type: 'image', image });
|
|
162
|
+
}
|
|
163
|
+
return parts;
|
|
164
|
+
})
|
|
165
|
+
];
|
|
166
|
+
}
|
|
167
|
+
export function parseObservations(value) {
|
|
168
|
+
if (!Array.isArray(value) || value.length > 4096)
|
|
169
|
+
return undefined;
|
|
170
|
+
const ids = new Set();
|
|
171
|
+
for (const item of value) {
|
|
172
|
+
if (!item || typeof item !== 'object' || typeof item.id !== 'string' || ids.has(item.id))
|
|
173
|
+
return undefined;
|
|
174
|
+
ids.add(item.id);
|
|
175
|
+
if (item.type === 'tool_result') {
|
|
176
|
+
if (!item.source ||
|
|
177
|
+
typeof item.source.callId !== 'string' ||
|
|
178
|
+
typeof item.source.toolName !== 'string' ||
|
|
179
|
+
!['completed', 'failed'].includes(item.outcome) ||
|
|
180
|
+
!item.result ||
|
|
181
|
+
typeof item.result.content !== 'string')
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
else if (item.type !== 'value' ||
|
|
185
|
+
!['text', 'json', 'image'].includes(item.format) ||
|
|
186
|
+
typeof item.value !== 'string')
|
|
187
|
+
return undefined;
|
|
188
|
+
const indices = item.type === 'tool_result' ? item.result.imageIndices : item.imageIndices;
|
|
189
|
+
if (indices !== undefined &&
|
|
190
|
+
(!Array.isArray(indices) ||
|
|
191
|
+
indices.some((i) => !Number.isSafeInteger(i) || Number(i) < 0 || Number(i) >= 5)))
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
return value;
|
|
195
|
+
}
|