@yolk-sdk/codemode 0.1.0-canary.124 → 0.1.0-canary.126
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/README.md +14 -8
- package/dist/catalog.d.mts.map +1 -1
- package/dist/catalog.mjs +55 -8
- package/dist/catalog.mjs.map +1 -1
- package/dist/executor.d.mts +3 -2
- package/dist/executor.d.mts.map +1 -1
- package/dist/node.d.mts.map +1 -1
- package/dist/node.mjs +48 -6
- package/dist/node.mjs.map +1 -1
- package/dist/tool.d.mts.map +1 -1
- package/dist/tool.mjs +38 -34
- package/dist/tool.mjs.map +1 -1
- package/package.json +2 -2
- package/src/catalog.ts +102 -8
- package/src/executor.ts +3 -2
- package/src/node.ts +66 -8
- package/src/tool.ts +46 -26
package/dist/tool.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.d.mts","names":[],"sources":["../src/tool.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"tool.d.mts","names":[],"sources":["../src/tool.ts"],"mappings":";;;;;;qBAkFa;;YAGD;;WAED;;WAEA;;;;;WAKA;;WAEA;;WAEA;;;;WAIA;;qBAGE;WACA;;WAEK;WACA;;;;;qBAML;;qBAGA;YAED,wBAAwB;WACzB,UAAU;;WAEV;;WAEA;WACA,SAAS;;;;;WAKT,YAAY,SAAS;;;;;WAKrB,aAAa,SAAS,YAAY,OAAO,OAAO,eAAe;;;;;;;;WAQ/D,oBAAoB;aAClB,MAAM;aACN,SAAS;QACd,OAAO;;;;;;;;;;WAUJ,mBAAmB,OAAO,6BAA6B,aAAa,OAAO;;;;;;;WAO3E,UAAU;;;;;;;;;WASV;;YAGC;;WAED;;;YAIC;YAEA,6BAA6B;WAC9B,MAAM;WACN,SAAS;WACT;WACA,SAAS;WACT,SAAS;;;;;;;;;;;;;;;;;;qBA8yBP,mBAAoB,SAAO,SAC7B,wBAAwB,aAChC,iBAAiB"}
|
package/dist/tool.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { searchCodeModeTools } from "./search.mjs";
|
|
|
4
4
|
import { Cause, Clock, Data, Duration, Effect, Exit, Fiber, FiberSet, Option, Predicate, Result, Scope } from "effect";
|
|
5
5
|
import * as Schema from "effect/Schema";
|
|
6
6
|
import { toCodemodeIdentifier } from "@earendil-works/pi-codemode/declarations";
|
|
7
|
-
import { ToolCall, ToolResult, boundNestedToolCallArgs,
|
|
7
|
+
import { ToolCall, ToolResult, boundNestedToolCallArgs, makeNestedToolCallRecorder, nestedToolCallMaxErrorChars, nestedToolCallRecordLimit, nestedToolCallResultFields, recordNestedToolCall, truncateCodePoints } from "@yolk-sdk/agent/protocol";
|
|
8
8
|
import { makeTool } from "@yolk-sdk/agent/tools";
|
|
9
9
|
import { ToolError } from "@yolk-sdk/agent/loop";
|
|
10
10
|
// src/tool.ts
|
|
@@ -25,45 +25,49 @@ const codeModeMinimumTimeoutMs = 1e3;
|
|
|
25
25
|
const CodeModeParams = Schema.Struct({ code: Schema.String.annotate({ description: "Raw JavaScript: the body of an async function. Top-level await and return work. Not a function declaration and not a module." }) });
|
|
26
26
|
var CodeModeExecutorRejected = class extends Data.TaggedError("CodeModeExecutorRejected") {};
|
|
27
27
|
const errorMessage = (error) => error instanceof Error ? error.message : Predicate.isString(error) ? error : "unknown error";
|
|
28
|
-
const nestedText = (content) => Predicate.isString(content) ? content : content.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
*
|
|
28
|
+
const nestedText = (content) => Predicate.isString(content) ? content : content.flatMap((part) => Predicate.isTagged(part, "Text") ? [part.text] : []).filter((text) => text.length > 0).join("\n");
|
|
29
|
+
const decodeErrorCode = Schema.decodeUnknownOption(Schema.Struct({ code: Schema.String }));
|
|
30
|
+
const errorCode = (result) => Option.getOrUndefined(Option.map(decodeErrorCode(result.structuredContent), (envelope) => envelope.code));
|
|
31
|
+
/** A typed tool's successful result without its value: the script never falls back to text. */
|
|
32
|
+
const isInvalidTypedResult = (tool, result) => tool.structured && result.isError !== true && result.structuredContent === void 0;
|
|
33
|
+
/**
|
|
34
|
+
* What a nested call resolves to (ADR 0013). A typed tool (one with an output schema) resolves to
|
|
35
|
+
* its value as declared, file fields as `FileRef` or `FileUnavailable`; a typed result without a
|
|
36
|
+
* value rejects ("returned an invalid result"). An untyped tool resolves to its text parts joined
|
|
37
|
+
* with newlines. Error results reject with their text and the `code` of their structured error
|
|
38
|
+
* (a model-visible error's code, a connector failure's code). Files never reach scripts as labels.
|
|
35
39
|
*/
|
|
36
40
|
const resolveNestedResult = (tool, result) => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
if (result.isError === true) {
|
|
42
|
+
const text = nestedText(result.content);
|
|
43
|
+
const message = text.length > 0 ? text : `Tool ${tool.name} failed.`;
|
|
44
|
+
const code = errorCode(result);
|
|
45
|
+
return code === void 0 ? {
|
|
46
|
+
ok: false,
|
|
47
|
+
message
|
|
48
|
+
} : {
|
|
49
|
+
ok: false,
|
|
50
|
+
message,
|
|
51
|
+
code
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (!tool.structured) return {
|
|
44
55
|
ok: true,
|
|
45
|
-
value
|
|
56
|
+
value: nestedText(result.content)
|
|
46
57
|
};
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
mimeType: file.mimeType,
|
|
51
|
-
size: file.size
|
|
52
|
-
}));
|
|
53
|
-
return Predicate.isObject(value) && !Array.isArray(value) ? {
|
|
54
|
-
ok: true,
|
|
55
|
-
value: {
|
|
56
|
-
...value,
|
|
57
|
-
files
|
|
58
|
-
}
|
|
58
|
+
return result.structuredContent === void 0 ? {
|
|
59
|
+
ok: false,
|
|
60
|
+
message: "returned an invalid result"
|
|
59
61
|
} : {
|
|
60
62
|
ok: true,
|
|
61
|
-
value:
|
|
62
|
-
text,
|
|
63
|
-
files
|
|
64
|
-
}
|
|
63
|
+
value: result.structuredContent
|
|
65
64
|
};
|
|
66
65
|
};
|
|
66
|
+
/** The script-visible rejection of a nested call, with the tool's error `code` when it has one. */
|
|
67
|
+
const nestedCallError = (label, resolution) => {
|
|
68
|
+
const error = /* @__PURE__ */ new Error(`${label}: ${resolution.message}`);
|
|
69
|
+
return resolution.code === void 0 ? error : Object.assign(error, { code: resolution.code });
|
|
70
|
+
};
|
|
67
71
|
const recordedOutcome = (exit, durationMs) => {
|
|
68
72
|
if (Exit.isFailure(exit)) return Cause.hasInterruptsOnly(exit.cause) ? {
|
|
69
73
|
status: "cancelled",
|
|
@@ -258,7 +262,7 @@ const runScript = (input) => Effect.gen(function* () {
|
|
|
258
262
|
const started = yield* Clock.currentTimeMillis;
|
|
259
263
|
return yield* admitted.pipe(Effect.onExit((exit) => Effect.map(Clock.currentTimeMillis, (finished) => {
|
|
260
264
|
record.outcome = recordedOutcome(exit, finished - started);
|
|
261
|
-
})));
|
|
265
|
+
})), Effect.tap((result) => isInvalidTypedResult(tool, result) ? Effect.logWarning(`Code mode: ${tool.name} declares an output schema but returned no value (call ${nestedCall.id}).`) : Effect.void));
|
|
262
266
|
});
|
|
263
267
|
return new Promise((resolve, reject) => {
|
|
264
268
|
runFork(execution, { signal }).addObserver((exit) => {
|
|
@@ -268,7 +272,7 @@ const runScript = (input) => Effect.gen(function* () {
|
|
|
268
272
|
}
|
|
269
273
|
const resolution = resolveNestedResult(tool, exit.value);
|
|
270
274
|
if (resolution.ok) resolve(resolution.value);
|
|
271
|
-
else reject(
|
|
275
|
+
else reject(nestedCallError(tool.callLabel, resolution));
|
|
272
276
|
});
|
|
273
277
|
});
|
|
274
278
|
};
|
package/dist/tool.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.mjs","names":[],"sources":["../src/tool.ts"],"sourcesContent":["import {\n Cause,\n Clock,\n Data,\n Duration,\n Effect,\n Exit,\n Fiber,\n FiberSet,\n Option,\n Predicate,\n Result,\n Scope\n} from 'effect'\nimport * as Schema from 'effect/Schema'\nimport { ToolError } from '@yolk-sdk/agent/loop'\nimport {\n boundNestedToolCallArgs,\n makeNestedToolCallRecorder,\n nestedToolCallMaxErrorChars,\n nestedToolCallRecordLimit,\n nestedToolCallResultFields,\n recordNestedToolCall,\n truncateCodePoints,\n contentPartText,\n ToolCall,\n ToolResult,\n type AgentUsage,\n type Content,\n type NestedToolCallAccess,\n type NestedToolCallInput,\n type NestedToolCallStatus\n} from '@yolk-sdk/agent/protocol'\nimport { toCodemodeIdentifier } from '@earendil-works/pi-codemode/declarations'\nimport {\n makeTool,\n type NestedTool,\n type NestedToolExecutor,\n type NestedToolInstructor,\n type StagedCallReceipt,\n type ToolExecutionInput,\n type ToolLedgerAbandonedInput,\n type ToolLedgerEntry,\n type ToolPlanBuilder,\n type ToolPlanStageError,\n type ToolRegistration\n} from '@yolk-sdk/agent/tools'\nimport {\n codeModeCatalog,\n codeModeCatalogInstruction,\n codeModeStageOnlyCatalog,\n defaultCodeModeInlineBudget,\n describeCodeModeTool,\n findCodeModeTool,\n renderCodeModeDescription,\n renderCodeModeInstructedDescription,\n type CodeModeCatalogTool,\n type CodeModeStagingDescription\n} from './catalog.ts'\nimport type {\n CodeModeExecutionResult,\n CodeModeExecutor,\n CodeModeExecutorGlobal,\n CodeModeExecutorTool,\n CodeModeStore\n} from './executor.ts'\nimport {\n boundCodeModeSegments,\n codeModeResultSegments,\n codeModeSegmentsContent,\n defaultCodeModeMaxImageBytes,\n defaultCodeModeMaxImages\n} from './output.ts'\nimport { searchCodeModeTools } from './search.ts'\nimport type {\n CodeModeInterruptedCall,\n CodeModeInterruptedCalls,\n CodeModeInterruptedCallStatus,\n CodeModeStagedPlan,\n CodeModeStructuredContent\n} from './store.ts'\n\n/** Default name of the code mode tool. */\nexport const codeModeToolName = 'codemode'\n\n/** Host-owned limits of one script. */\nexport type CodeModeLimits = {\n /** Overall deadline including nested calls. Default 120000 (clamped by `deadline`). */\n readonly timeoutMs?: number\n /** VM heap cap. Default 64 MiB. */\n readonly memoryLimitBytes?: number\n /** Nested tool calls per script; further calls reject with an Error. Default 256. The\n * `nestedCalls` record keeps up to this many calls, at most `nestedToolCallMaxRecordedCalls`\n * (4096) whatever the limit (argument byte budgets still apply).\n */\n readonly maxNestedCalls?: number\n /** Model-visible result characters, cut head and tail with an omission marker. Default 40000. */\n readonly maxOutputChars?: number\n /** Images kept in the result, in order; later images are dropped with a note. Default 8. */\n readonly maxImages?: number\n /** Base64 characters of images kept in the result in total; an image that would exceed it is\n * dropped with a note. Default 4 MiB.\n */\n readonly maxImageBytes?: number\n}\n\nexport const defaultCodeModeLimits = {\n timeoutMs: 120_000,\n memoryLimitBytes: 64 * 1024 * 1024,\n maxNestedCalls: 256,\n maxOutputChars: 40_000,\n maxImages: defaultCodeModeMaxImages,\n maxImageBytes: defaultCodeModeMaxImageBytes\n} as const satisfies Required<CodeModeLimits>\n\n/** Kept between a host deadline and the script deadline, for result handling. */\nexport const codeModeDeadlineMarginMs = 5_000\n\n/** A deadline never clamps a script below this timeout. */\nexport const codeModeMinimumTimeoutMs = 1_000\n\nexport type MakeCodeModeToolOptions<Context> = {\n readonly executor: CodeModeExecutor\n /** Default `codemode`. */\n readonly name?: string\n /** Estimated tokens (four characters each) for listing nested tools. Default 3000. */\n readonly inlineBudget?: number\n readonly limits?: CodeModeLimits\n /**\n * Epoch milliseconds by which the tool call must end, for example the remaining function budget\n * of a Workflow step. The script timeout is clamped to it minus 5 s, but never below 1 s.\n */\n readonly deadline?: (context: Context) => number | undefined\n /**\n * The store scripts read with `load(key)`, usually rebuilt from the transcript with\n * `codeModeStoreFromToolResults`. Without it every script starts with an empty store.\n */\n readonly loadStore?: (context: Context) => Effect.Effect<CodeModeStore, ToolError>\n /**\n * Runs before each nested call executes, with the nested call (id `<toolCallId>/<seq>`) and the\n * host context. A failure rejects that call in the script with the message and records it as an\n * `error` without executing it. Host decorators around the `ToolExecutor` (outside\n * `ResolvedToolSet.execute`) never see nested calls: put per-call run-authority checks here or in\n * registration-level wrappers.\n */\n readonly beforeNestedCall?: (input: {\n readonly call: ToolCall\n readonly context: Context\n }) => Effect.Effect<void, string>\n /**\n * Runs after each nested call that `beforeNestedCall` admitted, with its outcome: `success` (a\n * result without `isError`), `failure` (an error result or an unexpected failure), or\n * `interrupted` (cancelled, for example still running when the script ended). `durationMs`\n * covers the execution; `result` is present when the call produced one. Calls rejected by\n * `beforeNestedCall` or the call limit never ran and are not reported. The script waits for the\n * hook before it sees the call settle. A failing hook (a failure, a defect, or a synchronous\n * throw) is logged and never changes the call's result.\n */\n readonly afterNestedCall?: (input: CodeModeAfterNestedCallInput<Context>) => Effect.Effect<void>\n /**\n * Staged tool plans (ADR 0005). When the resolution offers staging (`resolveTools(..., { plans,\n * interactionHost })` with a plan review tool), scripts get `stage(name, args)` for stageable\n * approval-gated tools. `false` turns it off for this tool; `maxCalls` may only lower the\n * resolution's cap.\n */\n readonly staging?: CodeModeStagingOptions | false\n /**\n * Where the nested tool catalog goes (ADR 0007). `description` (default): in this tool's\n * description, which changes with the catalog. `instructions`: the description stays invariant\n * and the catalog (every namespace with its tool count, listed tools within `inlineBudget`) is\n * the resolution's `instructions` entry; hosts pass `ResolvedToolSet.instructions` to\n * `RunConfig.instructions`, so a change is appended to the conversation instead of rewriting the\n * cached request prefix.\n */\n readonly catalog?: 'description' | 'instructions'\n}\n\nexport type CodeModeStagingOptions = {\n /** Staged calls per script; `stage` rejects past it. At most the resolution's `maxCalls`. */\n readonly maxCalls?: number\n}\n\n/** Outcome of a nested call for `afterNestedCall`. */\nexport type CodeModeNestedCallOutcome = 'success' | 'failure' | 'interrupted'\n\nexport type CodeModeAfterNestedCallInput<Context> = {\n readonly call: ToolCall\n readonly outcome: CodeModeNestedCallOutcome\n readonly durationMs: number\n readonly context: Context\n readonly result?: ToolResult\n}\n\nconst CodeModeParams = Schema.Struct({\n code: Schema.String.annotate({\n description:\n 'Raw JavaScript: the body of an async function. Top-level await and return work. Not a function declaration and not a module.'\n })\n})\n\ntype CodeModeParams = typeof CodeModeParams.Type\n\nclass CodeModeExecutorRejected extends Data.TaggedError('CodeModeExecutorRejected')<{\n readonly message: string\n}> {}\n\nconst errorMessage = (error: unknown) =>\n error instanceof Error ? error.message : Predicate.isString(error) ? error : 'unknown error'\n\nconst nestedText = (content: Content) =>\n Predicate.isString(content)\n ? content\n : content\n .map(contentPartText)\n .filter(text => text.length > 0)\n .join('\\n')\n\ntype NestedResolution =\n | { readonly ok: true; readonly value: unknown }\n | { readonly ok: false; readonly message: string }\n\n/** What a nested call resolves to: `structuredContent` for tools with an output schema (when\n * present), text content otherwise; error results reject with their text. A tool that declares an\n * output schema but returns no `structuredContent` resolves to its text: that is a tool bug, kept\n * readable rather than turned into a failure. When the result captured files (ADR 0009), the\n * script also gets their descriptors as `files`: merged into an object `structuredContent`,\n * otherwise as `{ text, files }`.\n */\nconst resolveNestedResult = (tool: CodeModeCatalogTool, result: ToolResult): NestedResolution => {\n const text = nestedText(result.content)\n\n if (result.isError === true) {\n return { ok: false, message: text.length > 0 ? text : `Tool ${tool.name} failed.` }\n }\n\n const value =\n tool.structured && result.structuredContent !== undefined ? result.structuredContent : text\n\n if (result.files === undefined || result.files.length === 0) return { ok: true, value }\n\n const files = result.files.map(file => ({\n fileId: file.fileId,\n name: file.name,\n mimeType: file.mimeType,\n size: file.size\n }))\n\n return Predicate.isObject(value) && !Array.isArray(value)\n ? { ok: true, value: { ...value, files } }\n : { ok: true, value: { text, files } }\n}\n\ntype CallOutcome = {\n status: NestedToolCallStatus\n durationMs: number\n error?: string\n usage?: AgentUsage\n}\n\ntype RecordedCallFields = {\n id: string\n name: string\n args: unknown\n status: NestedToolCallStatus\n access?: NestedToolCallAccess\n durationMs?: number\n error?: string\n usage?: AgentUsage\n}\n\ntype CallRecord = {\n readonly name: string\n readonly args: unknown\n readonly id: string\n access?: NestedToolCallAccess\n outcome?: CallOutcome\n}\n\nconst recordedOutcome = (exit: Exit.Exit<ToolResult>, durationMs: number): CallOutcome => {\n if (Exit.isFailure(exit)) {\n return Cause.hasInterruptsOnly(exit.cause)\n ? { status: 'cancelled', durationMs }\n : { status: 'error', durationMs, error: 'The tool call failed unexpectedly.' }\n }\n\n const result = exit.value\n\n const outcome: CallOutcome =\n result.isError === true\n ? { status: 'error', durationMs, error: nestedText(result.content) }\n : { status: 'ok', durationMs }\n\n if (result.usage !== undefined) {\n outcome.usage = result.usage\n }\n\n return outcome\n}\n\nconst hookOutcome = (exit: Exit.Exit<ToolResult>): CodeModeNestedCallOutcome =>\n Exit.isSuccess(exit)\n ? exit.value.isError === true\n ? 'failure'\n : 'success'\n : Cause.hasInterruptsOnly(exit.cause)\n ? 'interrupted'\n : 'failure'\n\n/** What `describeNamespace(name)` resolves to. */\ntype CodeModeNamespaceDescription = {\n readonly name: string\n description?: string\n readonly tools: ReadonlyArray<{\n readonly name: string\n readonly description: string\n readonly stageOnly?: true\n }>\n}\n\nconst SearchOptions = Schema.Struct({\n limit: Schema.optionalKey(Schema.Finite),\n namespace: Schema.optionalKey(Schema.String)\n})\n\nconst decodeSearchOptions = Schema.decodeUnknownOption(SearchOptions)\n\n/** `searchTools`, `describeTool`, and `describeNamespace` over every nested tool and, while the\n * script may stage, every stageable tool. */\nconst discoveryGlobals = (\n catalog: ReadonlyArray<CodeModeCatalogTool>\n): ReadonlyArray<CodeModeExecutorGlobal> => [\n {\n name: 'searchTools',\n spread: true,\n execute: args => {\n const [query, options] = Array.isArray(args) ? args : []\n\n return Promise.resolve(\n searchCodeModeTools(\n catalog,\n Predicate.isString(query) ? query : '',\n Option.getOrElse(decodeSearchOptions(options ?? {}), () => ({}))\n )\n )\n }\n },\n {\n name: 'describeTool',\n execute: name => {\n const tool = Predicate.isString(name) ? findCodeModeTool(catalog, name) : undefined\n\n return Promise.resolve(tool === undefined ? undefined : describeCodeModeTool(tool))\n }\n },\n {\n name: 'describeNamespace',\n execute: name => {\n const tools = catalog.filter(tool => tool.namespace === name)\n\n if (!Predicate.isString(name) || tools.length === 0) return Promise.resolve(undefined)\n\n const description = tools.find(\n tool => tool.namespaceDescription !== undefined\n )?.namespaceDescription\n\n const namespace: CodeModeNamespaceDescription = {\n name,\n tools: tools.map(tool =>\n tool.exposure === 'stage'\n ? { name: tool.name, description: tool.description, stageOnly: true }\n : { name: tool.identifier, description: tool.description }\n )\n }\n\n if (description !== undefined) namespace.description = description\n\n return Promise.resolve(namespace)\n }\n }\n]\n\ntype StageFork = (\n effect: Effect.Effect<StagedCallReceipt, ToolPlanStageError>,\n options: { readonly signal: AbortSignal }\n) => Fiber.Fiber<StagedCallReceipt, ToolPlanStageError>\n\n/**\n * `stage(name, args)`: records one call into the script's plan (never runs it). `name` is the raw\n * tool name or its catalog identifier (what `searchTools` returns for callable tools).\n */\nconst stageGlobal = (\n plan: ToolPlanBuilder,\n fork: StageFork,\n stageable: ReadonlyArray<NestedTool>\n): CodeModeExecutorGlobal => ({\n name: 'stage',\n spread: true,\n signature: '(name: string, args: object): Promise<{ staged: true; key: string; index: number }>',\n description:\n 'Record a call of a stageable tool into this script’s plan for a person to review; it does not run.',\n execute: (args, { signal }) => {\n const [name, params] = Array.isArray(args) ? args : []\n\n if (signal.aborted) return Promise.reject(new Error('stage was cancelled.'))\n\n if (!Predicate.isString(name))\n return Promise.reject(new Error('stage: the first argument must be a tool name.'))\n\n const toolName =\n stageable.find(({ def }) => def.name === name)?.def.name ??\n stageable.find(({ def }) => toCodemodeIdentifier(def.name) === name)?.def.name ??\n name\n\n return new Promise((resolve, reject) => {\n fork(plan.stage({ name: toolName, params: params === undefined ? {} : params }), {\n signal\n }).addObserver(exit => {\n if (Exit.isSuccess(exit)) {\n resolve(exit.value)\n\n return\n }\n\n const error = Cause.findErrorOption(exit.cause)\n\n reject(\n new Error(\n Option.isSome(error)\n ? `stage: ${error.value.message}`\n : Cause.hasInterruptsOnly(exit.cause)\n ? 'stage was cancelled.'\n : 'stage failed unexpectedly.'\n )\n )\n })\n })\n }\n})\n\n/** A direct call of a stageable tool rejects with a hint to stage it (ADR 0007). */\nconst stageOnlyRejections = (stageOnly: ReadonlyArray<CodeModeCatalogTool>) =>\n stageOnly.flatMap(tool => {\n const message = `${tool.name} is approval-gated: record it with stage(${JSON.stringify(tool.name)}, args) instead of calling it.`\n\n return tool.identifier === tool.name\n ? [{ key: tool.name, message }]\n : [\n { key: tool.identifier, message },\n { key: tool.name, message }\n ]\n })\n\nconst planNotice = (plan: CodeModeStagedPlan) =>\n `\\n\\nStaged ${plan.count} call${plan.count === 1 ? '' : 's'} as plan ${plan.id}; nothing was applied yet. To apply them, call ${plan.reviewToolName}(${JSON.stringify({ planId: plan.id, planDigest: plan.digest })}): a person reviews the plan and selects the calls to apply.`\n\nconst hasStoreWrites = (result: CodeModeExecutionResult) =>\n result.storeWrites !== undefined &&\n (Object.keys(result.storeWrites.set).length > 0 || result.storeWrites.delete.length > 0)\n\nconst timeoutFor = (limit: number, deadline: number | undefined, now: number) =>\n deadline === undefined\n ? limit\n : Math.max(codeModeMinimumTimeoutMs, Math.min(limit, deadline - now - codeModeDeadlineMarginMs))\n\n/**\n * Waits at most `codeModeDeadlineMarginMs` for an effect (interrupting nested fibers) to finish; it\n * keeps running detached when a nested call does not respond to interruption in time.\n */\nconst boundedWait = (effect: Effect.Effect<void>) =>\n Effect.forkDetach(effect).pipe(\n Effect.flatMap(fiber =>\n Fiber.await(fiber).pipe(\n Effect.timeoutOption(Duration.millis(codeModeDeadlineMarginMs)),\n Effect.interruptible\n )\n ),\n Effect.asVoid\n )\n\ntype RunInput<Context> = {\n readonly options: MakeCodeModeToolOptions<Context>\n readonly limits: Required<CodeModeLimits>\n readonly call: ToolCall\n readonly context: Context\n readonly code: string\n readonly nested: NestedToolExecutor\n}\n\nconst runScript = <Context>(input: RunInput<Context>): Effect.Effect<ToolResult, ToolError> =>\n Effect.gen(function* () {\n const { call, limits, nested, options } = input\n const store = options.loadStore === undefined ? {} : yield* options.loadStore(input.context)\n const startedAt = yield* Clock.currentTimeMillis\n const timeoutMs = timeoutFor(limits.timeoutMs, options.deadline?.(input.context), startedAt)\n const catalog = codeModeCatalog(nested.tools)\n\n return yield* Effect.acquireUseRelease(\n Scope.make(),\n scope =>\n Effect.gen(function* () {\n // Nested calls run as fibers of this tool call (same services, interrupted with it).\n const fibers = yield* FiberSet.make<ToolResult>().pipe(Scope.provide(scope))\n const runFork = yield* FiberSet.runtime(fibers)<never>()\n const records: Array<CallRecord> = []\n\n // Staged tool plans: only when the resolution offers staging and the host keeps it on.\n const stagingOptions = options.staging === false ? undefined : options.staging\n const staging = options.staging === false ? undefined : nested.staging\n const maxStagedCalls = stagingOptions?.maxCalls\n\n const plan =\n staging === undefined\n ? undefined\n : staging.begin(\n maxStagedCalls === undefined ? undefined : { maxCalls: maxStagedCalls }\n )\n\n const stageFibers = yield* FiberSet.make<StagedCallReceipt, ToolPlanStageError>().pipe(\n Scope.provide(scope)\n )\n\n const stageFork = yield* FiberSet.runtime(stageFibers)<never>()\n\n const callTool =\n (tool: CodeModeCatalogTool): CodeModeExecutorTool['execute'] =>\n (args, { signal }) => {\n if (signal.aborted) {\n return Promise.reject(new Error(`${tool.callLabel} was cancelled.`))\n }\n\n if (records.length >= limits.maxNestedCalls) {\n return Promise.reject(\n new Error(\n `${tool.callLabel}: Nested call limit reached: a script may make at most ${limits.maxNestedCalls} tool calls. Batch the work or return partial results.`\n )\n )\n }\n\n const params = args === undefined ? {} : args\n\n const record: CallRecord = {\n id: `${call.id}/${records.length + 1}`,\n name: tool.name,\n args: params\n }\n\n records.push(record)\n\n const nestedCall = ToolCall.make({ id: record.id, name: tool.name, params })\n const afterNestedCall = options.afterNestedCall\n\n const run =\n afterNestedCall === undefined\n ? nested.execute(nestedCall)\n : Effect.gen(function* () {\n const started = yield* Clock.currentTimeMillis\n\n // Host observability never changes the call: a hook failure, defects and\n // synchronous throws included, is only logged.\n const afterNestedCallSafely = (\n hookInput: CodeModeAfterNestedCallInput<Context>\n ) =>\n Effect.suspend(() => afterNestedCall(hookInput)).pipe(\n Effect.exit,\n Effect.flatMap(hookExit =>\n Exit.isSuccess(hookExit)\n ? Effect.void\n : Effect.logWarning(\n `Code mode afterNestedCall failed for ${nestedCall.id}; ignored: ${Cause.pretty(hookExit.cause)}`\n )\n )\n )\n\n return yield* nested.execute(nestedCall).pipe(\n Effect.onExit(exit =>\n Effect.flatMap(Clock.currentTimeMillis, finished =>\n afterNestedCallSafely(\n Exit.isSuccess(exit)\n ? {\n call: nestedCall,\n outcome: hookOutcome(exit),\n durationMs: finished - started,\n context: input.context,\n result: exit.value\n }\n : {\n call: nestedCall,\n outcome: hookOutcome(exit),\n durationMs: finished - started,\n context: input.context\n }\n )\n )\n )\n )\n })\n\n // The plan's ordering guardrail: once a script stages, only read tools run.\n const guarded =\n plan === undefined\n ? run\n : plan.admit(nestedCall).pipe(\n Effect.matchEffect({\n onFailure: error =>\n Effect.succeed(\n ToolResult.make({\n toolCallId: nestedCall.id,\n content: error.message,\n isError: true\n })\n ),\n onSuccess: () => run\n })\n )\n\n const admitted =\n options.beforeNestedCall === undefined\n ? guarded\n : options.beforeNestedCall({ call: nestedCall, context: input.context }).pipe(\n Effect.matchEffect({\n onFailure: message =>\n Effect.succeed(\n ToolResult.make({\n toolCallId: nestedCall.id,\n content: message,\n isError: true\n })\n ),\n onSuccess: () => guarded\n })\n )\n\n const execution = Effect.gen(function* () {\n const access = yield* nested.access(nestedCall)\n\n if (access !== undefined) record.access = access\n\n const started = yield* Clock.currentTimeMillis\n\n return yield* admitted.pipe(\n Effect.onExit(exit =>\n Effect.map(Clock.currentTimeMillis, finished => {\n record.outcome = recordedOutcome(exit, finished - started)\n })\n )\n )\n })\n\n return new Promise((resolve, reject) => {\n runFork(execution, { signal }).addObserver(exit => {\n if (Exit.isFailure(exit)) {\n reject(\n new Error(\n Cause.hasInterruptsOnly(exit.cause)\n ? `${tool.callLabel} was cancelled.`\n : `${tool.callLabel} failed unexpectedly.`\n )\n )\n\n return\n }\n\n const resolution = resolveNestedResult(tool, exit.value)\n\n if (resolution.ok) {\n resolve(resolution.value)\n } else {\n // The script sees which call failed; the nested-call record keeps the raw text.\n reject(new Error(`${tool.callLabel}: ${resolution.message}`))\n }\n })\n })\n }\n\n const tools: ReadonlyArray<CodeModeExecutorTool> = catalog.map(tool => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n outputSchema: tool.outputSchema,\n callLabel: tool.callLabel,\n execute: callTool(tool)\n }))\n\n const stageOnly =\n plan === undefined || staging === undefined\n ? []\n : codeModeStageOnlyCatalog(staging.tools)\n\n const result = yield* Effect.tryPromise({\n try: signal =>\n options.executor.execute(input.code, {\n tools,\n globals:\n plan === undefined || staging === undefined\n ? discoveryGlobals(catalog)\n : [\n ...discoveryGlobals([...catalog, ...stageOnly]),\n stageGlobal(plan, stageFork, staging.tools)\n ],\n unbound: stageOnlyRejections(stageOnly),\n timeoutMs,\n memoryLimitBytes: limits.memoryLimitBytes,\n store,\n signal\n }),\n catch: error => new CodeModeExecutorRejected({ message: errorMessage(error) })\n }).pipe(\n Effect.catch(error =>\n Effect.succeed<CodeModeExecutionResult>({\n ok: false,\n error: {\n kind: 'sandbox',\n message: `The code mode executor failed: ${error.message}`\n },\n output: []\n })\n ),\n // Backstop for executors that miss their own deadline: interrupting aborts the signal.\n Effect.timeoutOption(Duration.millis(timeoutMs + codeModeDeadlineMarginMs)),\n Effect.map(\n Option.getOrElse((): CodeModeExecutionResult => ({\n ok: false,\n error: {\n kind: 'timeout',\n message: `Execution timed out after ${timeoutMs} ms (the executor did not stop in time)`\n },\n output: []\n }))\n )\n )\n\n // Calls still running when the script ended are cancelled and recorded as such.\n yield* boundedWait(FiberSet.clear(fibers))\n yield* boundedWait(FiberSet.clear(stageFibers))\n\n const finishedAt = yield* Clock.currentTimeMillis\n\n // A successful script's staged calls are saved once as a plan; a failed script's are\n // discarded (a partial plan is never offered for review). Nothing staged ever ran.\n const stagedCount = plan === undefined ? 0 : (yield* plan.staged).length\n\n const saved =\n plan === undefined || stagedCount === 0 || !result.ok\n ? undefined\n : yield* plan.finish.pipe(Effect.result)\n\n const savedPlan: CodeModeStagedPlan | undefined =\n staging === undefined ||\n saved === undefined ||\n Result.isFailure(saved) ||\n saved.success === undefined\n ? undefined\n : {\n id: saved.success.id,\n digest: saved.success.digest,\n count: saved.success.calls.length,\n reviewToolName: staging.reviewToolName\n }\n\n const planFailure =\n saved !== undefined && Result.isFailure(saved) ? saved.failure : undefined\n\n const planFailed = planFailure !== undefined\n const plural = stagedCount === 1 ? '' : 's'\n\n const stagingNotice =\n stagedCount === 0\n ? undefined\n : !result.ok\n ? `\\n\\nThe script failed, so its ${stagedCount} staged call${plural} ${stagedCount === 1 ? 'was' : 'were'} discarded; nothing was applied.`\n : planFailure !== undefined\n ? `\\n\\nThe script staged ${stagedCount} call${plural}, but the plan could not be saved (${planFailure.message}); nothing was applied. Run the script again.`\n : savedPlan === undefined\n ? undefined\n : planNotice(savedPlan)\n\n const recorded = records.map((record): NestedToolCallInput => {\n const fields: RecordedCallFields = {\n id: record.id,\n name: record.name,\n args: record.args,\n // A call interrupted before it started has no outcome.\n ...(record.outcome ?? { status: 'cancelled' })\n }\n\n if (record.access !== undefined) fields.access = record.access\n\n return fields\n })\n\n const recorder = recorded.reduce(\n recordNestedToolCall,\n makeNestedToolCallRecorder({ maxCalls: limits.maxNestedCalls })\n )\n\n const { nestedCalls, usage } = nestedToolCallResultFields(recorder)\n\n const segments = codeModeResultSegments({\n result,\n wallTimeMs: finishedAt - startedAt,\n calls: recorded,\n maxChars: limits.maxOutputChars,\n maxImages: limits.maxImages,\n maxImageBytes: limits.maxImageBytes\n })\n\n // The staging notice follows the bounded output so a cut never hides the plan.\n const content = codeModeSegmentsContent(\n stagingNotice === undefined\n ? segments\n : [...segments, { type: 'text', text: stagingNotice }]\n )\n\n const ok = result.ok && !planFailed\n\n const codemode: CodeModeStructuredContent['codemode'] =\n ok && result.storeWrites !== undefined && hasStoreWrites(result)\n ? { ok: true, storeWrites: result.storeWrites }\n : { ok }\n\n const structuredContent: CodeModeStructuredContent = {\n codemode: savedPlan === undefined ? codemode : { ...codemode, plan: savedPlan }\n }\n\n type ResultFields = {\n toolCallId: string\n content: Content\n isError?: boolean\n structuredContent: CodeModeStructuredContent\n nestedCalls: typeof nestedCalls\n usage?: AgentUsage\n }\n\n const fields: ResultFields = {\n toolCallId: call.id,\n content,\n structuredContent,\n nestedCalls\n }\n\n if (!ok) {\n fields.isError = true\n }\n\n if (usage !== undefined) {\n fields.usage = usage\n }\n\n return ToolResult.make(fields)\n }),\n (scope, exit) => boundedWait(Scope.close(scope, exit))\n )\n })\n\nconst argsPreviewChars = 200\n\nconst interruptedCallStatus = (entry: ToolLedgerEntry): CodeModeInterruptedCallStatus => {\n const outcome = entry.outcome\n\n if (outcome === undefined) return 'unknown'\n\n if (Predicate.isTagged(outcome, 'Failed')) return 'failed'\n\n return outcome.result.isError === true ? 'failed' : 'applied'\n}\n\nconst nestedEntryState = (entry: ToolLedgerEntry) => {\n const outcome = entry.outcome\n\n if (outcome === undefined) {\n return 'unknown: it started but never recorded a result, so it may have been applied'\n }\n\n if (Predicate.isTagged(outcome, 'Failed'))\n return `completed with an error: ${truncateCodePoints(outcome.error.message, nestedToolCallMaxErrorChars)}`\n\n return outcome.result.isError === true ? 'completed with an error result' : 'applied'\n}\n\n/** The bounded, wire-safe `interruptedCalls` of an abandoned execution's nested ledger entries:\n * the `nestedCalls` record bounds (`maxCalls`, 8 KiB of arguments per call, 32 KiB in total).\n */\nconst interruptedCalls = (\n nested: ReadonlyArray<ToolLedgerEntry>,\n maxCalls: number\n): CodeModeInterruptedCalls => {\n const counts = { applied: 0, failed: 0, unknown: 0 }\n const calls: Array<CodeModeInterruptedCall> = []\n let argsBytes = 0\n let complete = true\n\n for (const entry of nested) {\n const status = interruptedCallStatus(entry)\n\n counts[status]++\n\n if (calls.length >= maxCalls) {\n complete = false\n continue\n }\n\n const { args, bytes, truncated } = boundNestedToolCallArgs(entry.args, argsBytes)\n\n // `argsTruncated`: the ledger already cut the arguments when the call was claimed.\n if (truncated || entry.argsTruncated) complete = false\n\n argsBytes += bytes\n calls.push({ key: entry.key, toolName: entry.toolName, args, status })\n }\n\n return { calls, complete, counts }\n}\n\n/**\n * The result of a code mode call whose earlier execution was abandoned (claimed, lease expired,\n * no result recorded). The script never runs again: the result lists that execution's ledgered\n * nested calls as applied, failed, or unknown, and says they were not undone. The text is bounded\n * by `maxOutputChars`; `structuredContent.codemode.interruptedCalls` carries the same entries for\n * hosts, bounded like `nestedCalls`. When the ledger cannot list them, the result stays\n * interrupted, says they may have been applied, and sets `interruptedCallsUnavailable` instead.\n */\nconst abandonedScriptResult =\n (limits: Required<CodeModeLimits>) =>\n ({ call, nested }: ToolLedgerAbandonedInput): ToolResult => {\n const maxChars = limits.maxOutputChars\n\n const listing =\n nested === undefined\n ? 'Its ledgered nested tool calls could not be listed (the tool ledger is unavailable), so any of them may already have been applied.'\n : nested.length === 0\n ? 'No ledgered nested tool calls were recorded for that execution.'\n : [\n `Ledgered nested tool calls of that execution (they were not undone):`,\n ...nested.map(\n entry =>\n `- ${entry.key} ${entry.toolName} ${truncateCodePoints(entry.args, argsPreviewChars)}: ${nestedEntryState(entry)}`\n )\n ].join('\\n')\n\n const text = [\n `Script interrupted: an earlier execution of this ${call.name} call (${call.id}) started but never recorded a result. The script was not run again.`,\n listing,\n 'Calls the ledger policy skips (by default read-only calls) are not listed. Verify the state these calls affect before repeating any work.'\n ].join('\\n\\n')\n\n const structuredContent: CodeModeStructuredContent = {\n codemode:\n nested === undefined\n ? { ok: false, interrupted: true, interruptedCallsUnavailable: true }\n : {\n ok: false,\n interrupted: true,\n interruptedCalls: interruptedCalls(\n nested,\n nestedToolCallRecordLimit(limits.maxNestedCalls)\n )\n }\n }\n\n return ToolResult.make({\n toolCallId: call.id,\n content: codeModeSegmentsContent(boundCodeModeSegments([{ type: 'text', text }], maxChars)),\n isError: true,\n structuredContent\n })\n }\n\n/**\n * The code mode tool: one registration (default name `codemode`, input `{ code }`) whose scripts\n * call the other code-mode-callable tools of the same `resolveTools` resolution. Nested calls run\n * through the resolved execute path with the same host context (input decoding, enablement,\n * registration wrappers), get ids `<toolCallId>/<seq>`, and are recorded on the result's\n * `nestedCalls`. The resolved description lists the callable tools (see\n * `renderCodeModeDescription`).\n *\n * Access is `write`: scripts can call any write tool the resolution exposes to code mode; each\n * nested call keeps its own access metadata and host wrappers.\n *\n * With a tool ledger (`resolveTools(..., { ledger })`) the code mode call itself is ledgered, so a\n * re-executed call never runs its script again: a completed call returns its stored result, an\n * in-flight one is awaited, and an abandoned one returns an interrupted result listing its\n * ledgered nested calls. Nested write calls are ledgered under `<toolCallId>/<seq>`.\n */\nexport const makeCodeModeTool = <Context>(\n options: MakeCodeModeToolOptions<Context>\n): ToolRegistration<Context> => {\n const name = options.name ?? codeModeToolName\n const limits: Required<CodeModeLimits> = { ...defaultCodeModeLimits, ...options.limits }\n const inlineBudget = options.inlineBudget ?? defaultCodeModeInlineBudget\n const store = options.loadStore !== undefined\n\n const instructed = options.catalog === 'instructions'\n\n // In description mode `stage()` is documented once a stageable tool exists (the description\n // lists them anyway). In instructions mode the description must not depend on tools: staging\n // availability alone decides.\n const offered = (staging: CodeModeStagingDescription | undefined) =>\n options.staging === false ||\n staging === undefined ||\n (!instructed && staging.tools.length === 0)\n ? undefined\n : staging\n\n const registration = makeTool<Context, typeof CodeModeParams>({\n name,\n description: instructed\n ? renderCodeModeInstructedDescription({ store })\n : renderCodeModeDescription({ tools: [], inlineBudget, store }),\n parameters: CodeModeParams,\n access: 'write',\n nestedToolAccess: true,\n describe: ({ tools, staging }) => {\n const offeredStaging = offered(staging)\n\n if (instructed)\n return renderCodeModeInstructedDescription(\n offeredStaging === undefined ? { store } : { store, staging: offeredStaging }\n )\n\n return renderCodeModeDescription(\n offeredStaging === undefined\n ? { tools, inlineBudget, store }\n : { tools, inlineBudget, store, staging: offeredStaging }\n )\n },\n\n abandonedResult: abandonedScriptResult(limits),\n execute: ({\n call,\n context,\n params,\n nested\n }: ToolExecutionInput<Context> & { readonly params: CodeModeParams }) =>\n nested === undefined\n ? Effect.fail(\n new ToolError({\n tool: name,\n cause: 'unavailable',\n message: `${name} requires nested tool access; resolve it with resolveTools.`\n })\n )\n : runScript({ options, limits, call, context, code: params.code, nested })\n })\n\n if (!instructed) return registration\n\n const instruct: NestedToolInstructor = ({ tools, staging }) => {\n const offeredStaging = offered(staging)\n\n return codeModeCatalogInstruction(\n offeredStaging === undefined\n ? { tools, inlineBudget }\n : { tools, inlineBudget, staging: offeredStaging }\n )\n }\n\n return { ...registration, instruct }\n}\n"],"mappings":";;;;;;;;;;;AAmFA,MAAa,mBAAmB;AAuBhC,MAAa,wBAAwB;CACnC,WAAW;CACX,kBAAkB;CAClB,gBAAgB;CAChB,gBAAgB;CAChB,WAAA;CACA,eAAe;AACjB;;AAGA,MAAa,2BAA2B;;AAGxC,MAAa,2BAA2B;AA0ExC,MAAM,iBAAiB,OAAO,OAAO,EACnC,MAAM,OAAO,OAAO,SAAS,EAC3B,aACE,+HACJ,CAAC,EACH,CAAC;AAID,IAAM,2BAAN,cAAuC,KAAK,YAAY,0BAA0B,CAAC,CAEhF,CAAC;AAEJ,MAAM,gBAAgB,UACpB,iBAAiB,QAAQ,MAAM,UAAU,UAAU,SAAS,KAAK,IAAI,QAAQ;AAE/E,MAAM,cAAc,YAClB,UAAU,SAAS,OAAO,IACtB,UACA,QACG,IAAI,eAAe,CAAC,CACpB,QAAO,SAAQ,KAAK,SAAS,CAAC,CAAC,CAC/B,KAAK,IAAI;;;;;;;;AAalB,MAAM,uBAAuB,MAA2B,WAAyC;CAC/F,MAAM,OAAO,WAAW,OAAO,OAAO;CAEtC,IAAI,OAAO,YAAY,MACrB,OAAO;EAAE,IAAI;EAAO,SAAS,KAAK,SAAS,IAAI,OAAO,QAAQ,KAAK,KAAK;CAAU;CAGpF,MAAM,QACJ,KAAK,cAAc,OAAO,sBAAsB,KAAA,IAAY,OAAO,oBAAoB;CAEzF,IAAI,OAAO,UAAU,KAAA,KAAa,OAAO,MAAM,WAAW,GAAG,OAAO;EAAE,IAAI;EAAM;CAAM;CAEtF,MAAM,QAAQ,OAAO,MAAM,KAAI,UAAS;EACtC,QAAQ,KAAK;EACb,MAAM,KAAK;EACX,UAAU,KAAK;EACf,MAAM,KAAK;CACb,EAAE;CAEF,OAAO,UAAU,SAAS,KAAK,KAAK,CAAC,MAAM,QAAQ,KAAK,IACpD;EAAE,IAAI;EAAM,OAAO;GAAE,GAAG;GAAO;EAAM;CAAE,IACvC;EAAE,IAAI;EAAM,OAAO;GAAE;GAAM;EAAM;CAAE;AACzC;AA4BA,MAAM,mBAAmB,MAA6B,eAAoC;CACxF,IAAI,KAAK,UAAU,IAAI,GACrB,OAAO,MAAM,kBAAkB,KAAK,KAAK,IACrC;EAAE,QAAQ;EAAa;CAAW,IAClC;EAAE,QAAQ;EAAS;EAAY,OAAO;CAAqC;CAGjF,MAAM,SAAS,KAAK;CAEpB,MAAM,UACJ,OAAO,YAAY,OACf;EAAE,QAAQ;EAAS;EAAY,OAAO,WAAW,OAAO,OAAO;CAAE,IACjE;EAAE,QAAQ;EAAM;CAAW;CAEjC,IAAI,OAAO,UAAU,KAAA,GACnB,QAAQ,QAAQ,OAAO;CAGzB,OAAO;AACT;AAEA,MAAM,eAAe,SACnB,KAAK,UAAU,IAAI,IACf,KAAK,MAAM,YAAY,OACrB,YACA,YACF,MAAM,kBAAkB,KAAK,KAAK,IAChC,gBACA;AAaR,MAAM,gBAAgB,OAAO,OAAO;CAClC,OAAO,OAAO,YAAY,OAAO,MAAM;CACvC,WAAW,OAAO,YAAY,OAAO,MAAM;AAC7C,CAAC;AAED,MAAM,sBAAsB,OAAO,oBAAoB,aAAa;;;AAIpE,MAAM,oBACJ,YAC0C;CAC1C;EACE,MAAM;EACN,QAAQ;EACR,UAAS,SAAQ;GACf,MAAM,CAAC,OAAO,WAAW,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC;GAEvD,OAAO,QAAQ,QACb,oBACE,SACA,UAAU,SAAS,KAAK,IAAI,QAAQ,IACpC,OAAO,UAAU,oBAAoB,WAAW,CAAC,CAAC,UAAU,CAAC,EAAE,CACjE,CACF;EACF;CACF;CACA;EACE,MAAM;EACN,UAAS,SAAQ;GACf,MAAM,OAAO,UAAU,SAAS,IAAI,IAAI,iBAAiB,SAAS,IAAI,IAAI,KAAA;GAE1E,OAAO,QAAQ,QAAQ,SAAS,KAAA,IAAY,KAAA,IAAY,qBAAqB,IAAI,CAAC;EACpF;CACF;CACA;EACE,MAAM;EACN,UAAS,SAAQ;GACf,MAAM,QAAQ,QAAQ,QAAO,SAAQ,KAAK,cAAc,IAAI;GAE5D,IAAI,CAAC,UAAU,SAAS,IAAI,KAAK,MAAM,WAAW,GAAG,OAAO,QAAQ,QAAQ,KAAA,CAAS;GAErF,MAAM,cAAc,MAAM,MACxB,SAAQ,KAAK,yBAAyB,KAAA,CACxC,CAAC,EAAE;GAEH,MAAM,YAA0C;IAC9C;IACA,OAAO,MAAM,KAAI,SACf,KAAK,aAAa,UACd;KAAE,MAAM,KAAK;KAAM,aAAa,KAAK;KAAa,WAAW;IAAK,IAClE;KAAE,MAAM,KAAK;KAAY,aAAa,KAAK;IAAY,CAC7D;GACF;GAEA,IAAI,gBAAgB,KAAA,GAAW,UAAU,cAAc;GAEvD,OAAO,QAAQ,QAAQ,SAAS;EAClC;CACF;AACF;;;;;AAWA,MAAM,eACJ,MACA,MACA,eAC4B;CAC5B,MAAM;CACN,QAAQ;CACR,WAAW;CACX,aACE;CACF,UAAU,MAAM,EAAE,aAAa;EAC7B,MAAM,CAAC,MAAM,UAAU,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC;EAErD,IAAI,OAAO,SAAS,OAAO,QAAQ,uBAAO,IAAI,MAAM,sBAAsB,CAAC;EAE3E,IAAI,CAAC,UAAU,SAAS,IAAI,GAC1B,OAAO,QAAQ,uBAAO,IAAI,MAAM,gDAAgD,CAAC;EAEnF,MAAM,WACJ,UAAU,MAAM,EAAE,UAAU,IAAI,SAAS,IAAI,CAAC,EAAE,IAAI,QACpD,UAAU,MAAM,EAAE,UAAU,qBAAqB,IAAI,IAAI,MAAM,IAAI,CAAC,EAAE,IAAI,QAC1E;EAEF,OAAO,IAAI,SAAS,SAAS,WAAW;GACtC,KAAK,KAAK,MAAM;IAAE,MAAM;IAAU,QAAQ,WAAW,KAAA,IAAY,CAAC,IAAI;GAAO,CAAC,GAAG,EAC/E,OACF,CAAC,CAAC,CAAC,aAAY,SAAQ;IACrB,IAAI,KAAK,UAAU,IAAI,GAAG;KACxB,QAAQ,KAAK,KAAK;KAElB;IACF;IAEA,MAAM,QAAQ,MAAM,gBAAgB,KAAK,KAAK;IAE9C,uBACE,IAAI,MACF,OAAO,OAAO,KAAK,IACf,UAAU,MAAM,MAAM,YACtB,MAAM,kBAAkB,KAAK,KAAK,IAChC,yBACA,4BACR,CACF;GACF,CAAC;EACH,CAAC;CACH;AACF;;AAGA,MAAM,uBAAuB,cAC3B,UAAU,SAAQ,SAAQ;CACxB,MAAM,UAAU,GAAG,KAAK,KAAK,2CAA2C,KAAK,UAAU,KAAK,IAAI,EAAE;CAElG,OAAO,KAAK,eAAe,KAAK,OAC5B,CAAC;EAAE,KAAK,KAAK;EAAM;CAAQ,CAAC,IAC5B,CACE;EAAE,KAAK,KAAK;EAAY;CAAQ,GAChC;EAAE,KAAK,KAAK;EAAM;CAAQ,CAC5B;AACN,CAAC;AAEH,MAAM,cAAc,SAClB,cAAc,KAAK,MAAM,OAAO,KAAK,UAAU,IAAI,KAAK,IAAI,WAAW,KAAK,GAAG,iDAAiD,KAAK,eAAe,GAAG,KAAK,UAAU;CAAE,QAAQ,KAAK;CAAI,YAAY,KAAK;AAAO,CAAC,EAAE;AAEtN,MAAM,kBAAkB,WACtB,OAAO,gBAAgB,KAAA,MACtB,OAAO,KAAK,OAAO,YAAY,GAAG,CAAC,CAAC,SAAS,KAAK,OAAO,YAAY,OAAO,SAAS;AAExF,MAAM,cAAc,OAAe,UAA8B,QAC/D,aAAa,KAAA,IACT,QACA,KAAK,IAAI,0BAA0B,KAAK,IAAI,OAAO,WAAW,MAAM,wBAAwB,CAAC;;;;;AAMnG,MAAM,eAAe,WACnB,OAAO,WAAW,MAAM,CAAC,CAAC,KACxB,OAAO,SAAQ,UACb,MAAM,MAAM,KAAK,CAAC,CAAC,KACjB,OAAO,cAAc,SAAS,OAAO,wBAAwB,CAAC,GAC9D,OAAO,aACT,CACF,GACA,OAAO,MACT;AAWF,MAAM,aAAsB,UAC1B,OAAO,IAAI,aAAa;CACtB,MAAM,EAAE,MAAM,QAAQ,QAAQ,YAAY;CAC1C,MAAM,QAAQ,QAAQ,cAAc,KAAA,IAAY,CAAC,IAAI,OAAO,QAAQ,UAAU,MAAM,OAAO;CAC3F,MAAM,YAAY,OAAO,MAAM;CAC/B,MAAM,YAAY,WAAW,OAAO,WAAW,QAAQ,WAAW,MAAM,OAAO,GAAG,SAAS;CAC3F,MAAM,UAAU,gBAAgB,OAAO,KAAK;CAE5C,OAAO,OAAO,OAAO,kBACnB,MAAM,KAAK,IACX,UACE,OAAO,IAAI,aAAa;EAEtB,MAAM,SAAS,OAAO,SAAS,KAAiB,CAAC,CAAC,KAAK,MAAM,QAAQ,KAAK,CAAC;EAC3E,MAAM,UAAU,OAAO,SAAS,QAAQ,MAAM,CAAC,CAAQ;EACvD,MAAM,UAA6B,CAAC;EAGpC,MAAM,iBAAiB,QAAQ,YAAY,QAAQ,KAAA,IAAY,QAAQ;EACvE,MAAM,UAAU,QAAQ,YAAY,QAAQ,KAAA,IAAY,OAAO;EAC/D,MAAM,iBAAiB,gBAAgB;EAEvC,MAAM,OACJ,YAAY,KAAA,IACR,KAAA,IACA,QAAQ,MACN,mBAAmB,KAAA,IAAY,KAAA,IAAY,EAAE,UAAU,eAAe,CACxE;EAEN,MAAM,cAAc,OAAO,SAAS,KAA4C,CAAC,CAAC,KAChF,MAAM,QAAQ,KAAK,CACrB;EAEA,MAAM,YAAY,OAAO,SAAS,QAAQ,WAAW,CAAC,CAAQ;EAE9D,MAAM,YACH,UACA,MAAM,EAAE,aAAa;GACpB,IAAI,OAAO,SACT,OAAO,QAAQ,uBAAO,IAAI,MAAM,GAAG,KAAK,UAAU,gBAAgB,CAAC;GAGrE,IAAI,QAAQ,UAAU,OAAO,gBAC3B,OAAO,QAAQ,uBACb,IAAI,MACF,GAAG,KAAK,UAAU,yDAAyD,OAAO,eAAe,uDACnG,CACF;GAGF,MAAM,SAAS,SAAS,KAAA,IAAY,CAAC,IAAI;GAEzC,MAAM,SAAqB;IACzB,IAAI,GAAG,KAAK,GAAG,GAAG,QAAQ,SAAS;IACnC,MAAM,KAAK;IACX,MAAM;GACR;GAEA,QAAQ,KAAK,MAAM;GAEnB,MAAM,aAAa,SAAS,KAAK;IAAE,IAAI,OAAO;IAAI,MAAM,KAAK;IAAM;GAAO,CAAC;GAC3E,MAAM,kBAAkB,QAAQ;GAEhC,MAAM,MACJ,oBAAoB,KAAA,IAChB,OAAO,QAAQ,UAAU,IACzB,OAAO,IAAI,aAAa;IACtB,MAAM,UAAU,OAAO,MAAM;IAI7B,MAAM,yBACJ,cAEA,OAAO,cAAc,gBAAgB,SAAS,CAAC,CAAC,CAAC,KAC/C,OAAO,MACP,OAAO,SAAQ,aACb,KAAK,UAAU,QAAQ,IACnB,OAAO,OACP,OAAO,WACL,wCAAwC,WAAW,GAAG,aAAa,MAAM,OAAO,SAAS,KAAK,GAChG,CACN,CACF;IAEF,OAAO,OAAO,OAAO,QAAQ,UAAU,CAAC,CAAC,KACvC,OAAO,QAAO,SACZ,OAAO,QAAQ,MAAM,oBAAmB,aACtC,sBACE,KAAK,UAAU,IAAI,IACf;KACE,MAAM;KACN,SAAS,YAAY,IAAI;KACzB,YAAY,WAAW;KACvB,SAAS,MAAM;KACf,QAAQ,KAAK;IACf,IACA;KACE,MAAM;KACN,SAAS,YAAY,IAAI;KACzB,YAAY,WAAW;KACvB,SAAS,MAAM;IACjB,CACN,CACF,CACF,CACF;GACF,CAAC;GAGP,MAAM,UACJ,SAAS,KAAA,IACL,MACA,KAAK,MAAM,UAAU,CAAC,CAAC,KACrB,OAAO,YAAY;IACjB,YAAW,UACT,OAAO,QACL,WAAW,KAAK;KACd,YAAY,WAAW;KACvB,SAAS,MAAM;KACf,SAAS;IACX,CAAC,CACH;IACF,iBAAiB;GACnB,CAAC,CACH;GAEN,MAAM,WACJ,QAAQ,qBAAqB,KAAA,IACzB,UACA,QAAQ,iBAAiB;IAAE,MAAM;IAAY,SAAS,MAAM;GAAQ,CAAC,CAAC,CAAC,KACrE,OAAO,YAAY;IACjB,YAAW,YACT,OAAO,QACL,WAAW,KAAK;KACd,YAAY,WAAW;KACvB,SAAS;KACT,SAAS;IACX,CAAC,CACH;IACF,iBAAiB;GACnB,CAAC,CACH;GAEN,MAAM,YAAY,OAAO,IAAI,aAAa;IACxC,MAAM,SAAS,OAAO,OAAO,OAAO,UAAU;IAE9C,IAAI,WAAW,KAAA,GAAW,OAAO,SAAS;IAE1C,MAAM,UAAU,OAAO,MAAM;IAE7B,OAAO,OAAO,SAAS,KACrB,OAAO,QAAO,SACZ,OAAO,IAAI,MAAM,oBAAmB,aAAY;KAC9C,OAAO,UAAU,gBAAgB,MAAM,WAAW,OAAO;IAC3D,CAAC,CACH,CACF;GACF,CAAC;GAED,OAAO,IAAI,SAAS,SAAS,WAAW;IACtC,QAAQ,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,aAAY,SAAQ;KACjD,IAAI,KAAK,UAAU,IAAI,GAAG;MACxB,uBACE,IAAI,MACF,MAAM,kBAAkB,KAAK,KAAK,IAC9B,GAAG,KAAK,UAAU,mBAClB,GAAG,KAAK,UAAU,sBACxB,CACF;MAEA;KACF;KAEA,MAAM,aAAa,oBAAoB,MAAM,KAAK,KAAK;KAEvD,IAAI,WAAW,IACb,QAAQ,WAAW,KAAK;UAGxB,uBAAO,IAAI,MAAM,GAAG,KAAK,UAAU,IAAI,WAAW,SAAS,CAAC;IAEhE,CAAC;GACH,CAAC;EACH;EAEF,MAAM,QAA6C,QAAQ,KAAI,UAAS;GACtE,MAAM,KAAK;GACX,aAAa,KAAK;GAClB,aAAa,KAAK;GAClB,cAAc,KAAK;GACnB,WAAW,KAAK;GAChB,SAAS,SAAS,IAAI;EACxB,EAAE;EAEF,MAAM,YACJ,SAAS,KAAA,KAAa,YAAY,KAAA,IAC9B,CAAC,IACD,yBAAyB,QAAQ,KAAK;EAE5C,MAAM,SAAS,OAAO,OAAO,WAAW;GACtC,MAAK,WACH,QAAQ,SAAS,QAAQ,MAAM,MAAM;IACnC;IACA,SACE,SAAS,KAAA,KAAa,YAAY,KAAA,IAC9B,iBAAiB,OAAO,IACxB,CACE,GAAG,iBAAiB,CAAC,GAAG,SAAS,GAAG,SAAS,CAAC,GAC9C,YAAY,MAAM,WAAW,QAAQ,KAAK,CAC5C;IACN,SAAS,oBAAoB,SAAS;IACtC;IACA,kBAAkB,OAAO;IACzB;IACA;GACF,CAAC;GACH,QAAO,UAAS,IAAI,yBAAyB,EAAE,SAAS,aAAa,KAAK,EAAE,CAAC;EAC/E,CAAC,CAAC,CAAC,KACD,OAAO,OAAM,UACX,OAAO,QAAiC;GACtC,IAAI;GACJ,OAAO;IACL,MAAM;IACN,SAAS,kCAAkC,MAAM;GACnD;GACA,QAAQ,CAAC;EACX,CAAC,CACH,GAEA,OAAO,cAAc,SAAS,OAAO,YAAY,wBAAwB,CAAC,GAC1E,OAAO,IACL,OAAO,iBAA0C;GAC/C,IAAI;GACJ,OAAO;IACL,MAAM;IACN,SAAS,6BAA6B,UAAU;GAClD;GACA,QAAQ,CAAC;EACX,EAAE,CACJ,CACF;EAGA,OAAO,YAAY,SAAS,MAAM,MAAM,CAAC;EACzC,OAAO,YAAY,SAAS,MAAM,WAAW,CAAC;EAE9C,MAAM,aAAa,OAAO,MAAM;EAIhC,MAAM,cAAc,SAAS,KAAA,IAAY,KAAK,OAAO,KAAK,OAAA,CAAQ;EAElE,MAAM,QACJ,SAAS,KAAA,KAAa,gBAAgB,KAAK,CAAC,OAAO,KAC/C,KAAA,IACA,OAAO,KAAK,OAAO,KAAK,OAAO,MAAM;EAE3C,MAAM,YACJ,YAAY,KAAA,KACZ,UAAU,KAAA,KACV,OAAO,UAAU,KAAK,KACtB,MAAM,YAAY,KAAA,IACd,KAAA,IACA;GACE,IAAI,MAAM,QAAQ;GAClB,QAAQ,MAAM,QAAQ;GACtB,OAAO,MAAM,QAAQ,MAAM;GAC3B,gBAAgB,QAAQ;EAC1B;EAEN,MAAM,cACJ,UAAU,KAAA,KAAa,OAAO,UAAU,KAAK,IAAI,MAAM,UAAU,KAAA;EAEnE,MAAM,aAAa,gBAAgB,KAAA;EACnC,MAAM,SAAS,gBAAgB,IAAI,KAAK;EAExC,MAAM,gBACJ,gBAAgB,IACZ,KAAA,IACA,CAAC,OAAO,KACN,iCAAiC,YAAY,cAAc,OAAO,GAAG,gBAAgB,IAAI,QAAQ,OAAO,oCACxG,gBAAgB,KAAA,IACd,yBAAyB,YAAY,OAAO,OAAO,qCAAqC,YAAY,QAAQ,iDAC5G,cAAc,KAAA,IACZ,KAAA,IACA,WAAW,SAAS;EAEhC,MAAM,WAAW,QAAQ,KAAK,WAAgC;GAC5D,MAAM,SAA6B;IACjC,IAAI,OAAO;IACX,MAAM,OAAO;IACb,MAAM,OAAO;IAEb,GAAI,OAAO,WAAW,EAAE,QAAQ,YAAY;GAC9C;GAEA,IAAI,OAAO,WAAW,KAAA,GAAW,OAAO,SAAS,OAAO;GAExD,OAAO;EACT,CAAC;EAED,MAAM,WAAW,SAAS,OACxB,sBACA,2BAA2B,EAAE,UAAU,OAAO,eAAe,CAAC,CAChE;EAEA,MAAM,EAAE,aAAa,UAAU,2BAA2B,QAAQ;EAElE,MAAM,WAAW,uBAAuB;GACtC;GACA,YAAY,aAAa;GACzB,OAAO;GACP,UAAU,OAAO;GACjB,WAAW,OAAO;GAClB,eAAe,OAAO;EACxB,CAAC;EAGD,MAAM,UAAU,wBACd,kBAAkB,KAAA,IACd,WACA,CAAC,GAAG,UAAU;GAAE,MAAM;GAAQ,MAAM;EAAc,CAAC,CACzD;EAEA,MAAM,KAAK,OAAO,MAAM,CAAC;EAEzB,MAAM,WACJ,MAAM,OAAO,gBAAgB,KAAA,KAAa,eAAe,MAAM,IAC3D;GAAE,IAAI;GAAM,aAAa,OAAO;EAAY,IAC5C,EAAE,GAAG;EAEX,MAAM,oBAA+C,EACnD,UAAU,cAAc,KAAA,IAAY,WAAW;GAAE,GAAG;GAAU,MAAM;EAAU,EAChF;EAWA,MAAM,SAAuB;GAC3B,YAAY,KAAK;GACjB;GACA;GACA;EACF;EAEA,IAAI,CAAC,IACH,OAAO,UAAU;EAGnB,IAAI,UAAU,KAAA,GACZ,OAAO,QAAQ;EAGjB,OAAO,WAAW,KAAK,MAAM;CAC/B,CAAC,IACF,OAAO,SAAS,YAAY,MAAM,MAAM,OAAO,IAAI,CAAC,CACvD;AACF,CAAC;AAEH,MAAM,mBAAmB;AAEzB,MAAM,yBAAyB,UAA0D;CACvF,MAAM,UAAU,MAAM;CAEtB,IAAI,YAAY,KAAA,GAAW,OAAO;CAElC,IAAI,UAAU,SAAS,SAAS,QAAQ,GAAG,OAAO;CAElD,OAAO,QAAQ,OAAO,YAAY,OAAO,WAAW;AACtD;AAEA,MAAM,oBAAoB,UAA2B;CACnD,MAAM,UAAU,MAAM;CAEtB,IAAI,YAAY,KAAA,GACd,OAAO;CAGT,IAAI,UAAU,SAAS,SAAS,QAAQ,GACtC,OAAO,4BAA4B,mBAAmB,QAAQ,MAAM,SAAS,2BAA2B;CAE1G,OAAO,QAAQ,OAAO,YAAY,OAAO,mCAAmC;AAC9E;;;;AAKA,MAAM,oBACJ,QACA,aAC6B;CAC7B,MAAM,SAAS;EAAE,SAAS;EAAG,QAAQ;EAAG,SAAS;CAAE;CACnD,MAAM,QAAwC,CAAC;CAC/C,IAAI,YAAY;CAChB,IAAI,WAAW;CAEf,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,SAAS,sBAAsB,KAAK;EAE1C,OAAO,OAAO;EAEd,IAAI,MAAM,UAAU,UAAU;GAC5B,WAAW;GACX;EACF;EAEA,MAAM,EAAE,MAAM,OAAO,cAAc,wBAAwB,MAAM,MAAM,SAAS;EAGhF,IAAI,aAAa,MAAM,eAAe,WAAW;EAEjD,aAAa;EACb,MAAM,KAAK;GAAE,KAAK,MAAM;GAAK,UAAU,MAAM;GAAU;GAAM;EAAO,CAAC;CACvE;CAEA,OAAO;EAAE;EAAO;EAAU;CAAO;AACnC;;;;;;;;;AAUA,MAAM,yBACH,YACA,EAAE,MAAM,aAAmD;CAC1D,MAAM,WAAW,OAAO;CAExB,MAAM,UACJ,WAAW,KAAA,IACP,uIACA,OAAO,WAAW,IAChB,oEACA,CACE,wEACA,GAAG,OAAO,KACR,UACE,KAAK,MAAM,IAAI,GAAG,MAAM,SAAS,GAAG,mBAAmB,MAAM,MAAM,gBAAgB,EAAE,IAAI,iBAAiB,KAAK,GACnH,CACF,CAAC,CAAC,KAAK,IAAI;CAEnB,MAAM,OAAO;EACX,oDAAoD,KAAK,KAAK,SAAS,KAAK,GAAG;EAC/E;EACA;CACF,CAAC,CAAC,KAAK,MAAM;CAEb,MAAM,oBAA+C,EACnD,UACE,WAAW,KAAA,IACP;EAAE,IAAI;EAAO,aAAa;EAAM,6BAA6B;CAAK,IAClE;EACE,IAAI;EACJ,aAAa;EACb,kBAAkB,iBAChB,QACA,0BAA0B,OAAO,cAAc,CACjD;CACF,EACR;CAEA,OAAO,WAAW,KAAK;EACrB,YAAY,KAAK;EACjB,SAAS,wBAAwB,sBAAsB,CAAC;GAAE,MAAM;GAAQ;EAAK,CAAC,GAAG,QAAQ,CAAC;EAC1F,SAAS;EACT;CACF,CAAC;AACH;;;;;;;;;;;;;;;;;AAkBF,MAAa,oBACX,YAC8B;CAC9B,MAAM,OAAO,QAAQ,QAAA;CACrB,MAAM,SAAmC;EAAE,GAAG;EAAuB,GAAG,QAAQ;CAAO;CACvF,MAAM,eAAe,QAAQ,gBAAA;CAC7B,MAAM,QAAQ,QAAQ,cAAc,KAAA;CAEpC,MAAM,aAAa,QAAQ,YAAY;CAKvC,MAAM,WAAW,YACf,QAAQ,YAAY,SACpB,YAAY,KAAA,KACX,CAAC,cAAc,QAAQ,MAAM,WAAW,IACrC,KAAA,IACA;CAEN,MAAM,eAAe,SAAyC;EAC5D;EACA,aAAa,aACT,oCAAoC,EAAE,MAAM,CAAC,IAC7C,0BAA0B;GAAE,OAAO,CAAC;GAAG;GAAc;EAAM,CAAC;EAChE,YAAY;EACZ,QAAQ;EACR,kBAAkB;EAClB,WAAW,EAAE,OAAO,cAAc;GAChC,MAAM,iBAAiB,QAAQ,OAAO;GAEtC,IAAI,YACF,OAAO,oCACL,mBAAmB,KAAA,IAAY,EAAE,MAAM,IAAI;IAAE;IAAO,SAAS;GAAe,CAC9E;GAEF,OAAO,0BACL,mBAAmB,KAAA,IACf;IAAE;IAAO;IAAc;GAAM,IAC7B;IAAE;IAAO;IAAc;IAAO,SAAS;GAAe,CAC5D;EACF;EAEA,iBAAiB,sBAAsB,MAAM;EAC7C,UAAU,EACR,MACA,SACA,QACA,aAEA,WAAW,KAAA,IACP,OAAO,KACL,IAAI,UAAU;GACZ,MAAM;GACN,OAAO;GACP,SAAS,GAAG,KAAK;EACnB,CAAC,CACH,IACA,UAAU;GAAE;GAAS;GAAQ;GAAM;GAAS,MAAM,OAAO;GAAM;EAAO,CAAC;CAC/E,CAAC;CAED,IAAI,CAAC,YAAY,OAAO;CAExB,MAAM,YAAkC,EAAE,OAAO,cAAc;EAC7D,MAAM,iBAAiB,QAAQ,OAAO;EAEtC,OAAO,2BACL,mBAAmB,KAAA,IACf;GAAE;GAAO;EAAa,IACtB;GAAE;GAAO;GAAc,SAAS;EAAe,CACrD;CACF;CAEA,OAAO;EAAE,GAAG;EAAc;CAAS;AACrC"}
|
|
1
|
+
{"version":3,"file":"tool.mjs","names":[],"sources":["../src/tool.ts"],"sourcesContent":["import {\n Cause,\n Clock,\n Data,\n Duration,\n Effect,\n Exit,\n Fiber,\n FiberSet,\n Option,\n Predicate,\n Result,\n Scope\n} from 'effect'\nimport * as Schema from 'effect/Schema'\nimport { ToolError } from '@yolk-sdk/agent/loop'\nimport {\n boundNestedToolCallArgs,\n makeNestedToolCallRecorder,\n nestedToolCallMaxErrorChars,\n nestedToolCallRecordLimit,\n nestedToolCallResultFields,\n recordNestedToolCall,\n truncateCodePoints,\n ToolCall,\n ToolResult,\n type AgentUsage,\n type Content,\n type NestedToolCallAccess,\n type NestedToolCallInput,\n type NestedToolCallStatus\n} from '@yolk-sdk/agent/protocol'\nimport { toCodemodeIdentifier } from '@earendil-works/pi-codemode/declarations'\nimport {\n makeTool,\n type NestedTool,\n type NestedToolExecutor,\n type NestedToolInstructor,\n type StagedCallReceipt,\n type ToolExecutionInput,\n type ToolLedgerAbandonedInput,\n type ToolLedgerEntry,\n type ToolPlanBuilder,\n type ToolPlanStageError,\n type ToolRegistration\n} from '@yolk-sdk/agent/tools'\nimport {\n codeModeCatalog,\n codeModeCatalogInstruction,\n codeModeStageOnlyCatalog,\n defaultCodeModeInlineBudget,\n describeCodeModeTool,\n findCodeModeTool,\n renderCodeModeDescription,\n renderCodeModeInstructedDescription,\n type CodeModeCatalogTool,\n type CodeModeStagingDescription\n} from './catalog.ts'\nimport type {\n CodeModeExecutionResult,\n CodeModeExecutor,\n CodeModeExecutorGlobal,\n CodeModeExecutorTool,\n CodeModeStore\n} from './executor.ts'\nimport {\n boundCodeModeSegments,\n codeModeResultSegments,\n codeModeSegmentsContent,\n defaultCodeModeMaxImageBytes,\n defaultCodeModeMaxImages\n} from './output.ts'\nimport { searchCodeModeTools } from './search.ts'\nimport type {\n CodeModeInterruptedCall,\n CodeModeInterruptedCalls,\n CodeModeInterruptedCallStatus,\n CodeModeStagedPlan,\n CodeModeStructuredContent\n} from './store.ts'\n\n/** Default name of the code mode tool. */\nexport const codeModeToolName = 'codemode'\n\n/** Host-owned limits of one script. */\nexport type CodeModeLimits = {\n /** Overall deadline including nested calls. Default 120000 (clamped by `deadline`). */\n readonly timeoutMs?: number\n /** VM heap cap. Default 64 MiB. */\n readonly memoryLimitBytes?: number\n /** Nested tool calls per script; further calls reject with an Error. Default 256. The\n * `nestedCalls` record keeps up to this many calls, at most `nestedToolCallMaxRecordedCalls`\n * (4096) whatever the limit (argument byte budgets still apply).\n */\n readonly maxNestedCalls?: number\n /** Model-visible result characters, cut head and tail with an omission marker. Default 40000. */\n readonly maxOutputChars?: number\n /** Images kept in the result, in order; later images are dropped with a note. Default 8. */\n readonly maxImages?: number\n /** Base64 characters of images kept in the result in total; an image that would exceed it is\n * dropped with a note. Default 4 MiB.\n */\n readonly maxImageBytes?: number\n}\n\nexport const defaultCodeModeLimits = {\n timeoutMs: 120_000,\n memoryLimitBytes: 64 * 1024 * 1024,\n maxNestedCalls: 256,\n maxOutputChars: 40_000,\n maxImages: defaultCodeModeMaxImages,\n maxImageBytes: defaultCodeModeMaxImageBytes\n} as const satisfies Required<CodeModeLimits>\n\n/** Kept between a host deadline and the script deadline, for result handling. */\nexport const codeModeDeadlineMarginMs = 5_000\n\n/** A deadline never clamps a script below this timeout. */\nexport const codeModeMinimumTimeoutMs = 1_000\n\nexport type MakeCodeModeToolOptions<Context> = {\n readonly executor: CodeModeExecutor\n /** Default `codemode`. */\n readonly name?: string\n /** Estimated tokens (four characters each) for listing nested tools. Default 3000. */\n readonly inlineBudget?: number\n readonly limits?: CodeModeLimits\n /**\n * Epoch milliseconds by which the tool call must end, for example the remaining function budget\n * of a Workflow step. The script timeout is clamped to it minus 5 s, but never below 1 s.\n */\n readonly deadline?: (context: Context) => number | undefined\n /**\n * The store scripts read with `load(key)`, usually rebuilt from the transcript with\n * `codeModeStoreFromToolResults`. Without it every script starts with an empty store.\n */\n readonly loadStore?: (context: Context) => Effect.Effect<CodeModeStore, ToolError>\n /**\n * Runs before each nested call executes, with the nested call (id `<toolCallId>/<seq>`) and the\n * host context. A failure rejects that call in the script with the message and records it as an\n * `error` without executing it. Host decorators around the `ToolExecutor` (outside\n * `ResolvedToolSet.execute`) never see nested calls: put per-call run-authority checks here or in\n * registration-level wrappers.\n */\n readonly beforeNestedCall?: (input: {\n readonly call: ToolCall\n readonly context: Context\n }) => Effect.Effect<void, string>\n /**\n * Runs after each nested call that `beforeNestedCall` admitted, with its outcome: `success` (a\n * result without `isError`), `failure` (an error result or an unexpected failure), or\n * `interrupted` (cancelled, for example still running when the script ended). `durationMs`\n * covers the execution; `result` is present when the call produced one. Calls rejected by\n * `beforeNestedCall` or the call limit never ran and are not reported. The script waits for the\n * hook before it sees the call settle. A failing hook (a failure, a defect, or a synchronous\n * throw) is logged and never changes the call's result.\n */\n readonly afterNestedCall?: (input: CodeModeAfterNestedCallInput<Context>) => Effect.Effect<void>\n /**\n * Staged tool plans (ADR 0005). When the resolution offers staging (`resolveTools(..., { plans,\n * interactionHost })` with a plan review tool), scripts get `stage(name, args)` for stageable\n * approval-gated tools. `false` turns it off for this tool; `maxCalls` may only lower the\n * resolution's cap.\n */\n readonly staging?: CodeModeStagingOptions | false\n /**\n * Where the nested tool catalog goes (ADR 0007). `description` (default): in this tool's\n * description, which changes with the catalog. `instructions`: the description stays invariant\n * and the catalog (every namespace with its tool count, listed tools within `inlineBudget`) is\n * the resolution's `instructions` entry; hosts pass `ResolvedToolSet.instructions` to\n * `RunConfig.instructions`, so a change is appended to the conversation instead of rewriting the\n * cached request prefix.\n */\n readonly catalog?: 'description' | 'instructions'\n}\n\nexport type CodeModeStagingOptions = {\n /** Staged calls per script; `stage` rejects past it. At most the resolution's `maxCalls`. */\n readonly maxCalls?: number\n}\n\n/** Outcome of a nested call for `afterNestedCall`. */\nexport type CodeModeNestedCallOutcome = 'success' | 'failure' | 'interrupted'\n\nexport type CodeModeAfterNestedCallInput<Context> = {\n readonly call: ToolCall\n readonly outcome: CodeModeNestedCallOutcome\n readonly durationMs: number\n readonly context: Context\n readonly result?: ToolResult\n}\n\nconst CodeModeParams = Schema.Struct({\n code: Schema.String.annotate({\n description:\n 'Raw JavaScript: the body of an async function. Top-level await and return work. Not a function declaration and not a module.'\n })\n})\n\ntype CodeModeParams = typeof CodeModeParams.Type\n\nclass CodeModeExecutorRejected extends Data.TaggedError('CodeModeExecutorRejected')<{\n readonly message: string\n}> {}\n\nconst errorMessage = (error: unknown) =>\n error instanceof Error ? error.message : Predicate.isString(error) ? error : 'unknown error'\n\n// The text a script sees of a result: its text parts only. File, image, document and audio parts\n// (and the labels providers render for them) never enter scripts (ADR 0013).\nconst nestedText = (content: Content) =>\n Predicate.isString(content)\n ? content\n : content\n .flatMap(part => (Predicate.isTagged(part, 'Text') ? [part.text] : []))\n .filter(text => text.length > 0)\n .join('\\n')\n\ntype NestedResolution =\n | { readonly ok: true; readonly value: unknown }\n | { readonly ok: false; readonly message: string; readonly code?: string }\n\n// The `code` of an error result: a model-visible error's (`ModelVisibleToolError.code`) or any\n// structured error with a string `code` (a connector's `ProviderFailure`).\nconst decodeErrorCode = Schema.decodeUnknownOption(Schema.Struct({ code: Schema.String }))\n\nconst errorCode = (result: ToolResult) =>\n Option.getOrUndefined(\n Option.map(decodeErrorCode(result.structuredContent), envelope => envelope.code)\n )\n\n/** A typed tool's successful result without its value: the script never falls back to text. */\nconst isInvalidTypedResult = (tool: CodeModeCatalogTool, result: ToolResult) =>\n tool.structured && result.isError !== true && result.structuredContent === undefined\n\n/**\n * What a nested call resolves to (ADR 0013). A typed tool (one with an output schema) resolves to\n * its value as declared, file fields as `FileRef` or `FileUnavailable`; a typed result without a\n * value rejects (\"returned an invalid result\"). An untyped tool resolves to its text parts joined\n * with newlines. Error results reject with their text and the `code` of their structured error\n * (a model-visible error's code, a connector failure's code). Files never reach scripts as labels.\n */\nconst resolveNestedResult = (tool: CodeModeCatalogTool, result: ToolResult): NestedResolution => {\n if (result.isError === true) {\n const text = nestedText(result.content)\n const message = text.length > 0 ? text : `Tool ${tool.name} failed.`\n const code = errorCode(result)\n\n return code === undefined ? { ok: false, message } : { ok: false, message, code }\n }\n\n if (!tool.structured) return { ok: true, value: nestedText(result.content) }\n\n return result.structuredContent === undefined\n ? { ok: false, message: 'returned an invalid result' }\n : { ok: true, value: result.structuredContent }\n}\n\n/** The script-visible rejection of a nested call, with the tool's error `code` when it has one. */\nconst nestedCallError = (label: string, resolution: { message: string; code?: string }) => {\n const error = new Error(`${label}: ${resolution.message}`)\n\n return resolution.code === undefined ? error : Object.assign(error, { code: resolution.code })\n}\n\ntype CallOutcome = {\n status: NestedToolCallStatus\n durationMs: number\n error?: string\n usage?: AgentUsage\n}\n\ntype RecordedCallFields = {\n id: string\n name: string\n args: unknown\n status: NestedToolCallStatus\n access?: NestedToolCallAccess\n durationMs?: number\n error?: string\n usage?: AgentUsage\n}\n\ntype CallRecord = {\n readonly name: string\n readonly args: unknown\n readonly id: string\n access?: NestedToolCallAccess\n outcome?: CallOutcome\n}\n\nconst recordedOutcome = (exit: Exit.Exit<ToolResult>, durationMs: number): CallOutcome => {\n if (Exit.isFailure(exit)) {\n return Cause.hasInterruptsOnly(exit.cause)\n ? { status: 'cancelled', durationMs }\n : { status: 'error', durationMs, error: 'The tool call failed unexpectedly.' }\n }\n\n const result = exit.value\n\n const outcome: CallOutcome =\n result.isError === true\n ? { status: 'error', durationMs, error: nestedText(result.content) }\n : { status: 'ok', durationMs }\n\n if (result.usage !== undefined) {\n outcome.usage = result.usage\n }\n\n return outcome\n}\n\nconst hookOutcome = (exit: Exit.Exit<ToolResult>): CodeModeNestedCallOutcome =>\n Exit.isSuccess(exit)\n ? exit.value.isError === true\n ? 'failure'\n : 'success'\n : Cause.hasInterruptsOnly(exit.cause)\n ? 'interrupted'\n : 'failure'\n\n/** What `describeNamespace(name)` resolves to. */\ntype CodeModeNamespaceDescription = {\n readonly name: string\n description?: string\n readonly tools: ReadonlyArray<{\n readonly name: string\n readonly description: string\n readonly stageOnly?: true\n }>\n}\n\nconst SearchOptions = Schema.Struct({\n limit: Schema.optionalKey(Schema.Finite),\n namespace: Schema.optionalKey(Schema.String)\n})\n\nconst decodeSearchOptions = Schema.decodeUnknownOption(SearchOptions)\n\n/** `searchTools`, `describeTool`, and `describeNamespace` over every nested tool and, while the\n * script may stage, every stageable tool. */\nconst discoveryGlobals = (\n catalog: ReadonlyArray<CodeModeCatalogTool>\n): ReadonlyArray<CodeModeExecutorGlobal> => [\n {\n name: 'searchTools',\n spread: true,\n execute: args => {\n const [query, options] = Array.isArray(args) ? args : []\n\n return Promise.resolve(\n searchCodeModeTools(\n catalog,\n Predicate.isString(query) ? query : '',\n Option.getOrElse(decodeSearchOptions(options ?? {}), () => ({}))\n )\n )\n }\n },\n {\n name: 'describeTool',\n execute: name => {\n const tool = Predicate.isString(name) ? findCodeModeTool(catalog, name) : undefined\n\n return Promise.resolve(tool === undefined ? undefined : describeCodeModeTool(tool))\n }\n },\n {\n name: 'describeNamespace',\n execute: name => {\n const tools = catalog.filter(tool => tool.namespace === name)\n\n if (!Predicate.isString(name) || tools.length === 0) return Promise.resolve(undefined)\n\n const description = tools.find(\n tool => tool.namespaceDescription !== undefined\n )?.namespaceDescription\n\n const namespace: CodeModeNamespaceDescription = {\n name,\n tools: tools.map(tool =>\n tool.exposure === 'stage'\n ? { name: tool.name, description: tool.description, stageOnly: true }\n : { name: tool.identifier, description: tool.description }\n )\n }\n\n if (description !== undefined) namespace.description = description\n\n return Promise.resolve(namespace)\n }\n }\n]\n\ntype StageFork = (\n effect: Effect.Effect<StagedCallReceipt, ToolPlanStageError>,\n options: { readonly signal: AbortSignal }\n) => Fiber.Fiber<StagedCallReceipt, ToolPlanStageError>\n\n/**\n * `stage(name, args)`: records one call into the script's plan (never runs it). `name` is the raw\n * tool name or its catalog identifier (what `searchTools` returns for callable tools).\n */\nconst stageGlobal = (\n plan: ToolPlanBuilder,\n fork: StageFork,\n stageable: ReadonlyArray<NestedTool>\n): CodeModeExecutorGlobal => ({\n name: 'stage',\n spread: true,\n signature: '(name: string, args: object): Promise<{ staged: true; key: string; index: number }>',\n description:\n 'Record a call of a stageable tool into this script’s plan for a person to review; it does not run.',\n execute: (args, { signal }) => {\n const [name, params] = Array.isArray(args) ? args : []\n\n if (signal.aborted) return Promise.reject(new Error('stage was cancelled.'))\n\n if (!Predicate.isString(name))\n return Promise.reject(new Error('stage: the first argument must be a tool name.'))\n\n const toolName =\n stageable.find(({ def }) => def.name === name)?.def.name ??\n stageable.find(({ def }) => toCodemodeIdentifier(def.name) === name)?.def.name ??\n name\n\n return new Promise((resolve, reject) => {\n fork(plan.stage({ name: toolName, params: params === undefined ? {} : params }), {\n signal\n }).addObserver(exit => {\n if (Exit.isSuccess(exit)) {\n resolve(exit.value)\n\n return\n }\n\n const error = Cause.findErrorOption(exit.cause)\n\n reject(\n new Error(\n Option.isSome(error)\n ? `stage: ${error.value.message}`\n : Cause.hasInterruptsOnly(exit.cause)\n ? 'stage was cancelled.'\n : 'stage failed unexpectedly.'\n )\n )\n })\n })\n }\n})\n\n/** A direct call of a stageable tool rejects with a hint to stage it (ADR 0007). */\nconst stageOnlyRejections = (stageOnly: ReadonlyArray<CodeModeCatalogTool>) =>\n stageOnly.flatMap(tool => {\n const message = `${tool.name} is approval-gated: record it with stage(${JSON.stringify(tool.name)}, args) instead of calling it.`\n\n return tool.identifier === tool.name\n ? [{ key: tool.name, message }]\n : [\n { key: tool.identifier, message },\n { key: tool.name, message }\n ]\n })\n\nconst planNotice = (plan: CodeModeStagedPlan) =>\n `\\n\\nStaged ${plan.count} call${plan.count === 1 ? '' : 's'} as plan ${plan.id}; nothing was applied yet. To apply them, call ${plan.reviewToolName}(${JSON.stringify({ planId: plan.id, planDigest: plan.digest })}): a person reviews the plan and selects the calls to apply.`\n\nconst hasStoreWrites = (result: CodeModeExecutionResult) =>\n result.storeWrites !== undefined &&\n (Object.keys(result.storeWrites.set).length > 0 || result.storeWrites.delete.length > 0)\n\nconst timeoutFor = (limit: number, deadline: number | undefined, now: number) =>\n deadline === undefined\n ? limit\n : Math.max(codeModeMinimumTimeoutMs, Math.min(limit, deadline - now - codeModeDeadlineMarginMs))\n\n/**\n * Waits at most `codeModeDeadlineMarginMs` for an effect (interrupting nested fibers) to finish; it\n * keeps running detached when a nested call does not respond to interruption in time.\n */\nconst boundedWait = (effect: Effect.Effect<void>) =>\n Effect.forkDetach(effect).pipe(\n Effect.flatMap(fiber =>\n Fiber.await(fiber).pipe(\n Effect.timeoutOption(Duration.millis(codeModeDeadlineMarginMs)),\n Effect.interruptible\n )\n ),\n Effect.asVoid\n )\n\ntype RunInput<Context> = {\n readonly options: MakeCodeModeToolOptions<Context>\n readonly limits: Required<CodeModeLimits>\n readonly call: ToolCall\n readonly context: Context\n readonly code: string\n readonly nested: NestedToolExecutor\n}\n\nconst runScript = <Context>(input: RunInput<Context>): Effect.Effect<ToolResult, ToolError> =>\n Effect.gen(function* () {\n const { call, limits, nested, options } = input\n const store = options.loadStore === undefined ? {} : yield* options.loadStore(input.context)\n const startedAt = yield* Clock.currentTimeMillis\n const timeoutMs = timeoutFor(limits.timeoutMs, options.deadline?.(input.context), startedAt)\n const catalog = codeModeCatalog(nested.tools)\n\n return yield* Effect.acquireUseRelease(\n Scope.make(),\n scope =>\n Effect.gen(function* () {\n // Nested calls run as fibers of this tool call (same services, interrupted with it).\n const fibers = yield* FiberSet.make<ToolResult>().pipe(Scope.provide(scope))\n const runFork = yield* FiberSet.runtime(fibers)<never>()\n const records: Array<CallRecord> = []\n\n // Staged tool plans: only when the resolution offers staging and the host keeps it on.\n const stagingOptions = options.staging === false ? undefined : options.staging\n const staging = options.staging === false ? undefined : nested.staging\n const maxStagedCalls = stagingOptions?.maxCalls\n\n const plan =\n staging === undefined\n ? undefined\n : staging.begin(\n maxStagedCalls === undefined ? undefined : { maxCalls: maxStagedCalls }\n )\n\n const stageFibers = yield* FiberSet.make<StagedCallReceipt, ToolPlanStageError>().pipe(\n Scope.provide(scope)\n )\n\n const stageFork = yield* FiberSet.runtime(stageFibers)<never>()\n\n const callTool =\n (tool: CodeModeCatalogTool): CodeModeExecutorTool['execute'] =>\n (args, { signal }) => {\n if (signal.aborted) {\n return Promise.reject(new Error(`${tool.callLabel} was cancelled.`))\n }\n\n if (records.length >= limits.maxNestedCalls) {\n return Promise.reject(\n new Error(\n `${tool.callLabel}: Nested call limit reached: a script may make at most ${limits.maxNestedCalls} tool calls. Batch the work or return partial results.`\n )\n )\n }\n\n const params = args === undefined ? {} : args\n\n const record: CallRecord = {\n id: `${call.id}/${records.length + 1}`,\n name: tool.name,\n args: params\n }\n\n records.push(record)\n\n const nestedCall = ToolCall.make({ id: record.id, name: tool.name, params })\n const afterNestedCall = options.afterNestedCall\n\n const run =\n afterNestedCall === undefined\n ? nested.execute(nestedCall)\n : Effect.gen(function* () {\n const started = yield* Clock.currentTimeMillis\n\n // Host observability never changes the call: a hook failure, defects and\n // synchronous throws included, is only logged.\n const afterNestedCallSafely = (\n hookInput: CodeModeAfterNestedCallInput<Context>\n ) =>\n Effect.suspend(() => afterNestedCall(hookInput)).pipe(\n Effect.exit,\n Effect.flatMap(hookExit =>\n Exit.isSuccess(hookExit)\n ? Effect.void\n : Effect.logWarning(\n `Code mode afterNestedCall failed for ${nestedCall.id}; ignored: ${Cause.pretty(hookExit.cause)}`\n )\n )\n )\n\n return yield* nested.execute(nestedCall).pipe(\n Effect.onExit(exit =>\n Effect.flatMap(Clock.currentTimeMillis, finished =>\n afterNestedCallSafely(\n Exit.isSuccess(exit)\n ? {\n call: nestedCall,\n outcome: hookOutcome(exit),\n durationMs: finished - started,\n context: input.context,\n result: exit.value\n }\n : {\n call: nestedCall,\n outcome: hookOutcome(exit),\n durationMs: finished - started,\n context: input.context\n }\n )\n )\n )\n )\n })\n\n // The plan's ordering guardrail: once a script stages, only read tools run.\n const guarded =\n plan === undefined\n ? run\n : plan.admit(nestedCall).pipe(\n Effect.matchEffect({\n onFailure: error =>\n Effect.succeed(\n ToolResult.make({\n toolCallId: nestedCall.id,\n content: error.message,\n isError: true\n })\n ),\n onSuccess: () => run\n })\n )\n\n const admitted =\n options.beforeNestedCall === undefined\n ? guarded\n : options.beforeNestedCall({ call: nestedCall, context: input.context }).pipe(\n Effect.matchEffect({\n onFailure: message =>\n Effect.succeed(\n ToolResult.make({\n toolCallId: nestedCall.id,\n content: message,\n isError: true\n })\n ),\n onSuccess: () => guarded\n })\n )\n\n const execution = Effect.gen(function* () {\n const access = yield* nested.access(nestedCall)\n\n if (access !== undefined) record.access = access\n\n const started = yield* Clock.currentTimeMillis\n\n return yield* admitted.pipe(\n Effect.onExit(exit =>\n Effect.map(Clock.currentTimeMillis, finished => {\n record.outcome = recordedOutcome(exit, finished - started)\n })\n ),\n Effect.tap(result =>\n isInvalidTypedResult(tool, result)\n ? Effect.logWarning(\n `Code mode: ${tool.name} declares an output schema but returned no value (call ${nestedCall.id}).`\n )\n : Effect.void\n )\n )\n })\n\n return new Promise((resolve, reject) => {\n runFork(execution, { signal }).addObserver(exit => {\n if (Exit.isFailure(exit)) {\n reject(\n new Error(\n Cause.hasInterruptsOnly(exit.cause)\n ? `${tool.callLabel} was cancelled.`\n : `${tool.callLabel} failed unexpectedly.`\n )\n )\n\n return\n }\n\n const resolution = resolveNestedResult(tool, exit.value)\n\n if (resolution.ok) {\n resolve(resolution.value)\n } else {\n // The script sees which call failed; the nested-call record keeps the raw text.\n reject(nestedCallError(tool.callLabel, resolution))\n }\n })\n })\n }\n\n const tools: ReadonlyArray<CodeModeExecutorTool> = catalog.map(tool => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n outputSchema: tool.outputSchema,\n callLabel: tool.callLabel,\n execute: callTool(tool)\n }))\n\n const stageOnly =\n plan === undefined || staging === undefined\n ? []\n : codeModeStageOnlyCatalog(staging.tools)\n\n const result = yield* Effect.tryPromise({\n try: signal =>\n options.executor.execute(input.code, {\n tools,\n globals:\n plan === undefined || staging === undefined\n ? discoveryGlobals(catalog)\n : [\n ...discoveryGlobals([...catalog, ...stageOnly]),\n stageGlobal(plan, stageFork, staging.tools)\n ],\n unbound: stageOnlyRejections(stageOnly),\n timeoutMs,\n memoryLimitBytes: limits.memoryLimitBytes,\n store,\n signal\n }),\n catch: error => new CodeModeExecutorRejected({ message: errorMessage(error) })\n }).pipe(\n Effect.catch(error =>\n Effect.succeed<CodeModeExecutionResult>({\n ok: false,\n error: {\n kind: 'sandbox',\n message: `The code mode executor failed: ${error.message}`\n },\n output: []\n })\n ),\n // Backstop for executors that miss their own deadline: interrupting aborts the signal.\n Effect.timeoutOption(Duration.millis(timeoutMs + codeModeDeadlineMarginMs)),\n Effect.map(\n Option.getOrElse((): CodeModeExecutionResult => ({\n ok: false,\n error: {\n kind: 'timeout',\n message: `Execution timed out after ${timeoutMs} ms (the executor did not stop in time)`\n },\n output: []\n }))\n )\n )\n\n // Calls still running when the script ended are cancelled and recorded as such.\n yield* boundedWait(FiberSet.clear(fibers))\n yield* boundedWait(FiberSet.clear(stageFibers))\n\n const finishedAt = yield* Clock.currentTimeMillis\n\n // A successful script's staged calls are saved once as a plan; a failed script's are\n // discarded (a partial plan is never offered for review). Nothing staged ever ran.\n const stagedCount = plan === undefined ? 0 : (yield* plan.staged).length\n\n const saved =\n plan === undefined || stagedCount === 0 || !result.ok\n ? undefined\n : yield* plan.finish.pipe(Effect.result)\n\n const savedPlan: CodeModeStagedPlan | undefined =\n staging === undefined ||\n saved === undefined ||\n Result.isFailure(saved) ||\n saved.success === undefined\n ? undefined\n : {\n id: saved.success.id,\n digest: saved.success.digest,\n count: saved.success.calls.length,\n reviewToolName: staging.reviewToolName\n }\n\n const planFailure =\n saved !== undefined && Result.isFailure(saved) ? saved.failure : undefined\n\n const planFailed = planFailure !== undefined\n const plural = stagedCount === 1 ? '' : 's'\n\n const stagingNotice =\n stagedCount === 0\n ? undefined\n : !result.ok\n ? `\\n\\nThe script failed, so its ${stagedCount} staged call${plural} ${stagedCount === 1 ? 'was' : 'were'} discarded; nothing was applied.`\n : planFailure !== undefined\n ? `\\n\\nThe script staged ${stagedCount} call${plural}, but the plan could not be saved (${planFailure.message}); nothing was applied. Run the script again.`\n : savedPlan === undefined\n ? undefined\n : planNotice(savedPlan)\n\n const recorded = records.map((record): NestedToolCallInput => {\n const fields: RecordedCallFields = {\n id: record.id,\n name: record.name,\n args: record.args,\n // A call interrupted before it started has no outcome.\n ...(record.outcome ?? { status: 'cancelled' })\n }\n\n if (record.access !== undefined) fields.access = record.access\n\n return fields\n })\n\n const recorder = recorded.reduce(\n recordNestedToolCall,\n makeNestedToolCallRecorder({ maxCalls: limits.maxNestedCalls })\n )\n\n const { nestedCalls, usage } = nestedToolCallResultFields(recorder)\n\n const segments = codeModeResultSegments({\n result,\n wallTimeMs: finishedAt - startedAt,\n calls: recorded,\n maxChars: limits.maxOutputChars,\n maxImages: limits.maxImages,\n maxImageBytes: limits.maxImageBytes\n })\n\n // The staging notice follows the bounded output so a cut never hides the plan.\n const content = codeModeSegmentsContent(\n stagingNotice === undefined\n ? segments\n : [...segments, { type: 'text', text: stagingNotice }]\n )\n\n const ok = result.ok && !planFailed\n\n const codemode: CodeModeStructuredContent['codemode'] =\n ok && result.storeWrites !== undefined && hasStoreWrites(result)\n ? { ok: true, storeWrites: result.storeWrites }\n : { ok }\n\n const structuredContent: CodeModeStructuredContent = {\n codemode: savedPlan === undefined ? codemode : { ...codemode, plan: savedPlan }\n }\n\n type ResultFields = {\n toolCallId: string\n content: Content\n isError?: boolean\n structuredContent: CodeModeStructuredContent\n nestedCalls: typeof nestedCalls\n usage?: AgentUsage\n }\n\n const fields: ResultFields = {\n toolCallId: call.id,\n content,\n structuredContent,\n nestedCalls\n }\n\n if (!ok) {\n fields.isError = true\n }\n\n if (usage !== undefined) {\n fields.usage = usage\n }\n\n return ToolResult.make(fields)\n }),\n (scope, exit) => boundedWait(Scope.close(scope, exit))\n )\n })\n\nconst argsPreviewChars = 200\n\nconst interruptedCallStatus = (entry: ToolLedgerEntry): CodeModeInterruptedCallStatus => {\n const outcome = entry.outcome\n\n if (outcome === undefined) return 'unknown'\n\n if (Predicate.isTagged(outcome, 'Failed')) return 'failed'\n\n return outcome.result.isError === true ? 'failed' : 'applied'\n}\n\nconst nestedEntryState = (entry: ToolLedgerEntry) => {\n const outcome = entry.outcome\n\n if (outcome === undefined) {\n return 'unknown: it started but never recorded a result, so it may have been applied'\n }\n\n if (Predicate.isTagged(outcome, 'Failed'))\n return `completed with an error: ${truncateCodePoints(outcome.error.message, nestedToolCallMaxErrorChars)}`\n\n return outcome.result.isError === true ? 'completed with an error result' : 'applied'\n}\n\n/** The bounded, wire-safe `interruptedCalls` of an abandoned execution's nested ledger entries:\n * the `nestedCalls` record bounds (`maxCalls`, 8 KiB of arguments per call, 32 KiB in total).\n */\nconst interruptedCalls = (\n nested: ReadonlyArray<ToolLedgerEntry>,\n maxCalls: number\n): CodeModeInterruptedCalls => {\n const counts = { applied: 0, failed: 0, unknown: 0 }\n const calls: Array<CodeModeInterruptedCall> = []\n let argsBytes = 0\n let complete = true\n\n for (const entry of nested) {\n const status = interruptedCallStatus(entry)\n\n counts[status]++\n\n if (calls.length >= maxCalls) {\n complete = false\n continue\n }\n\n const { args, bytes, truncated } = boundNestedToolCallArgs(entry.args, argsBytes)\n\n // `argsTruncated`: the ledger already cut the arguments when the call was claimed.\n if (truncated || entry.argsTruncated) complete = false\n\n argsBytes += bytes\n calls.push({ key: entry.key, toolName: entry.toolName, args, status })\n }\n\n return { calls, complete, counts }\n}\n\n/**\n * The result of a code mode call whose earlier execution was abandoned (claimed, lease expired,\n * no result recorded). The script never runs again: the result lists that execution's ledgered\n * nested calls as applied, failed, or unknown, and says they were not undone. The text is bounded\n * by `maxOutputChars`; `structuredContent.codemode.interruptedCalls` carries the same entries for\n * hosts, bounded like `nestedCalls`. When the ledger cannot list them, the result stays\n * interrupted, says they may have been applied, and sets `interruptedCallsUnavailable` instead.\n */\nconst abandonedScriptResult =\n (limits: Required<CodeModeLimits>) =>\n ({ call, nested }: ToolLedgerAbandonedInput): ToolResult => {\n const maxChars = limits.maxOutputChars\n\n const listing =\n nested === undefined\n ? 'Its ledgered nested tool calls could not be listed (the tool ledger is unavailable), so any of them may already have been applied.'\n : nested.length === 0\n ? 'No ledgered nested tool calls were recorded for that execution.'\n : [\n `Ledgered nested tool calls of that execution (they were not undone):`,\n ...nested.map(\n entry =>\n `- ${entry.key} ${entry.toolName} ${truncateCodePoints(entry.args, argsPreviewChars)}: ${nestedEntryState(entry)}`\n )\n ].join('\\n')\n\n const text = [\n `Script interrupted: an earlier execution of this ${call.name} call (${call.id}) started but never recorded a result. The script was not run again.`,\n listing,\n 'Calls the ledger policy skips (by default read-only calls) are not listed. Verify the state these calls affect before repeating any work.'\n ].join('\\n\\n')\n\n const structuredContent: CodeModeStructuredContent = {\n codemode:\n nested === undefined\n ? { ok: false, interrupted: true, interruptedCallsUnavailable: true }\n : {\n ok: false,\n interrupted: true,\n interruptedCalls: interruptedCalls(\n nested,\n nestedToolCallRecordLimit(limits.maxNestedCalls)\n )\n }\n }\n\n return ToolResult.make({\n toolCallId: call.id,\n content: codeModeSegmentsContent(boundCodeModeSegments([{ type: 'text', text }], maxChars)),\n isError: true,\n structuredContent\n })\n }\n\n/**\n * The code mode tool: one registration (default name `codemode`, input `{ code }`) whose scripts\n * call the other code-mode-callable tools of the same `resolveTools` resolution. Nested calls run\n * through the resolved execute path with the same host context (input decoding, enablement,\n * registration wrappers), get ids `<toolCallId>/<seq>`, and are recorded on the result's\n * `nestedCalls`. The resolved description lists the callable tools (see\n * `renderCodeModeDescription`).\n *\n * Access is `write`: scripts can call any write tool the resolution exposes to code mode; each\n * nested call keeps its own access metadata and host wrappers.\n *\n * With a tool ledger (`resolveTools(..., { ledger })`) the code mode call itself is ledgered, so a\n * re-executed call never runs its script again: a completed call returns its stored result, an\n * in-flight one is awaited, and an abandoned one returns an interrupted result listing its\n * ledgered nested calls. Nested write calls are ledgered under `<toolCallId>/<seq>`.\n */\nexport const makeCodeModeTool = <Context>(\n options: MakeCodeModeToolOptions<Context>\n): ToolRegistration<Context> => {\n const name = options.name ?? codeModeToolName\n const limits: Required<CodeModeLimits> = { ...defaultCodeModeLimits, ...options.limits }\n const inlineBudget = options.inlineBudget ?? defaultCodeModeInlineBudget\n const store = options.loadStore !== undefined\n\n const instructed = options.catalog === 'instructions'\n\n // In description mode `stage()` is documented once a stageable tool exists (the description\n // lists them anyway). In instructions mode the description must not depend on tools: staging\n // availability alone decides.\n const offered = (staging: CodeModeStagingDescription | undefined) =>\n options.staging === false ||\n staging === undefined ||\n (!instructed && staging.tools.length === 0)\n ? undefined\n : staging\n\n const registration = makeTool<Context, typeof CodeModeParams>({\n name,\n description: instructed\n ? renderCodeModeInstructedDescription({ store })\n : renderCodeModeDescription({ tools: [], inlineBudget, store }),\n parameters: CodeModeParams,\n access: 'write',\n nestedToolAccess: true,\n describe: ({ tools, staging }) => {\n const offeredStaging = offered(staging)\n\n if (instructed)\n return renderCodeModeInstructedDescription(\n offeredStaging === undefined ? { store } : { store, staging: offeredStaging }\n )\n\n return renderCodeModeDescription(\n offeredStaging === undefined\n ? { tools, inlineBudget, store }\n : { tools, inlineBudget, store, staging: offeredStaging }\n )\n },\n\n abandonedResult: abandonedScriptResult(limits),\n execute: ({\n call,\n context,\n params,\n nested\n }: ToolExecutionInput<Context> & { readonly params: CodeModeParams }) =>\n nested === undefined\n ? Effect.fail(\n new ToolError({\n tool: name,\n cause: 'unavailable',\n message: `${name} requires nested tool access; resolve it with resolveTools.`\n })\n )\n : runScript({ options, limits, call, context, code: params.code, nested })\n })\n\n if (!instructed) return registration\n\n const instruct: NestedToolInstructor = ({ tools, staging }) => {\n const offeredStaging = offered(staging)\n\n return codeModeCatalogInstruction(\n offeredStaging === undefined\n ? { tools, inlineBudget }\n : { tools, inlineBudget, staging: offeredStaging }\n )\n }\n\n return { ...registration, instruct }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yolk-sdk/codemode",
|
|
3
|
-
"version": "0.1.0-canary.
|
|
3
|
+
"version": "0.1.0-canary.126",
|
|
4
4
|
"description": "Code mode for Yolk agents: one tool that runs model-written JavaScript calling the host's resolved tools, plus a Node executor on a confined QuickJS sandbox.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@earendil-works/pi-codemode": "1.0.0",
|
|
54
54
|
"effect": "4.1.2",
|
|
55
|
-
"@yolk-sdk/agent": "^0.1.0-canary.
|
|
55
|
+
"@yolk-sdk/agent": "^0.1.0-canary.126"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"build": "tsdown",
|
package/src/catalog.ts
CHANGED
|
@@ -7,7 +7,12 @@ import {
|
|
|
7
7
|
schemaToType,
|
|
8
8
|
toCodemodeIdentifier
|
|
9
9
|
} from '@earendil-works/pi-codemode/declarations'
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
interactionJsonEquals,
|
|
12
|
+
isDeferredTool,
|
|
13
|
+
toolDiscovery,
|
|
14
|
+
toolFileJsonSchemaDefinitions
|
|
15
|
+
} from '@yolk-sdk/agent/protocol'
|
|
11
16
|
import type { RunInstruction } from '@yolk-sdk/agent/loop'
|
|
12
17
|
import type { NestedTool } from '@yolk-sdk/agent/tools'
|
|
13
18
|
import type { CodeModeJsonSchema } from './executor.ts'
|
|
@@ -126,10 +131,98 @@ export const defaultCodeModeInlineBudget = 3000
|
|
|
126
131
|
/** Estimated tokens of a text: four characters per token, rounded up. */
|
|
127
132
|
export const estimateCodeModeTokens = (text: string): number => Math.ceil(text.length / 4)
|
|
128
133
|
|
|
134
|
+
// File fields render by name (`FileRef | FileUnavailable`, declared once in the intro): their
|
|
135
|
+
// `$ref`s become sentinel constants the renderer quotes, and the quoted sentinels become the names.
|
|
136
|
+
const fileTypeNames = { FileRef: 'FileRef', FileUnavailable: 'FileUnavailable' } as const
|
|
137
|
+
|
|
138
|
+
type FileTypeName = keyof typeof fileTypeNames
|
|
139
|
+
|
|
140
|
+
const fileTypeSentinel = (name: FileTypeName) => `\u0000yolk:${name}`
|
|
141
|
+
|
|
142
|
+
const isJsonObject = (value: Schema.Json | undefined): value is Schema.JsonObject =>
|
|
143
|
+
Predicate.isObject(value) && !Array.isArray(value)
|
|
144
|
+
|
|
145
|
+
// The file definitions an output schema holds exactly as tool output schemas lower them.
|
|
146
|
+
const fileDefinitions = (schema: CodeModeJsonSchema): ReadonlySet<FileTypeName> => {
|
|
147
|
+
const defs = isJsonObject(schema) ? schema['$defs'] : undefined
|
|
148
|
+
|
|
149
|
+
if (!isJsonObject(defs)) return new Set()
|
|
150
|
+
|
|
151
|
+
return new Set(
|
|
152
|
+
(['FileRef', 'FileUnavailable'] as const).filter(name =>
|
|
153
|
+
interactionJsonEquals(defs[name], toolFileJsonSchemaDefinitions[name])
|
|
154
|
+
)
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Keywords whose values are data, not schemas: a `$ref`-shaped object there is a literal value.
|
|
159
|
+
const dataKeywords: ReadonlySet<string> = new Set(['const', 'enum', 'default', 'examples'])
|
|
160
|
+
|
|
161
|
+
// Keywords whose values map author-chosen names to schemas: their keys are names, never keywords.
|
|
162
|
+
const schemaMapKeywords: ReadonlySet<string> = new Set([
|
|
163
|
+
'properties',
|
|
164
|
+
'patternProperties',
|
|
165
|
+
'$defs',
|
|
166
|
+
'definitions',
|
|
167
|
+
'dependentSchemas'
|
|
168
|
+
])
|
|
169
|
+
|
|
170
|
+
const mapValues = (
|
|
171
|
+
value: Schema.JsonObject,
|
|
172
|
+
f: (key: string, item: Schema.Json) => Schema.Json
|
|
173
|
+
): Schema.Json =>
|
|
174
|
+
Object.fromEntries(Object.entries(value).map(([key, item]) => [key, f(key, item)]))
|
|
175
|
+
|
|
176
|
+
// `value` sits at a schema position (or holds schemas, as an array of `anyOf` members does).
|
|
177
|
+
const withFileSentinels = (value: Schema.Json, names: ReadonlySet<FileTypeName>): Schema.Json => {
|
|
178
|
+
if (Array.isArray(value)) return value.map((item: Schema.Json) => withFileSentinels(item, names))
|
|
179
|
+
|
|
180
|
+
if (!isJsonObject(value)) return value
|
|
181
|
+
|
|
182
|
+
const ref = value['$ref']
|
|
183
|
+
|
|
184
|
+
const named = (['FileRef', 'FileUnavailable'] as const).find(
|
|
185
|
+
name => names.has(name) && ref === `#/$defs/${name}`
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
if (named !== undefined) return { const: fileTypeSentinel(named) }
|
|
189
|
+
|
|
190
|
+
return mapValues(value, (key, item) => {
|
|
191
|
+
if (dataKeywords.has(key)) return item
|
|
192
|
+
|
|
193
|
+
// A named map's values are schemas, whatever their names (a property may be called `enum`).
|
|
194
|
+
if (schemaMapKeywords.has(key) && isJsonObject(item)) {
|
|
195
|
+
return mapValues(item, (_name, schema) => withFileSentinels(schema, names))
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return withFileSentinels(item, names)
|
|
199
|
+
})
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** An output schema whose file fields render as `FileRef` / `FileUnavailable`. */
|
|
203
|
+
const renderableOutput = (schema: CodeModeJsonSchema): CodeModeJsonSchema => {
|
|
204
|
+
const names = fileDefinitions(schema)
|
|
205
|
+
|
|
206
|
+
if (names.size === 0) return schema
|
|
207
|
+
|
|
208
|
+
const replaced = withFileSentinels(schema, names)
|
|
209
|
+
|
|
210
|
+
return isJsonObject(replaced) ? replaced : schema
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const withFileTypeNames = (rendered: string) =>
|
|
214
|
+
(['FileRef', 'FileUnavailable'] as const).reduce(
|
|
215
|
+
(text, name) => text.replaceAll(JSON.stringify(fileTypeSentinel(name)), fileTypeNames[name]),
|
|
216
|
+
rendered
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
const renderOutputType = (schema: CodeModeJsonSchema) =>
|
|
220
|
+
withFileTypeNames(renderToolOutputType(renderableOutput(schema)))
|
|
221
|
+
|
|
129
222
|
const maxShortTypeChars = 60
|
|
130
223
|
|
|
131
224
|
const shortType = (schema: CodeModeJsonSchema): string => {
|
|
132
|
-
const rendered =
|
|
225
|
+
const rendered = renderOutputType(schema)
|
|
133
226
|
|
|
134
227
|
if (rendered.length <= maxShortTypeChars) return rendered
|
|
135
228
|
|
|
@@ -147,7 +240,7 @@ const declarationTool = (tool: CodeModeCatalogTool) => ({
|
|
|
147
240
|
name: tool.name,
|
|
148
241
|
description: tool.description,
|
|
149
242
|
inputSchema: tool.inputSchema,
|
|
150
|
-
outputSchema: tool.outputSchema,
|
|
243
|
+
outputSchema: renderableOutput(tool.outputSchema),
|
|
151
244
|
execute: () => undefined
|
|
152
245
|
})
|
|
153
246
|
|
|
@@ -155,7 +248,7 @@ const directToolLine = (tool: CodeModeCatalogTool) =>
|
|
|
155
248
|
`- \`tools.${tool.identifier}(args)\` takes the arguments of the \`${tool.name}\` tool and resolves to \`${shortType(tool.outputSchema)}\`.`
|
|
156
249
|
|
|
157
250
|
const declarationMembers = (tools: ReadonlyArray<CodeModeCatalogTool>) =>
|
|
158
|
-
renderDeclarations({ tools: tools.map(declarationTool) })
|
|
251
|
+
withFileTypeNames(renderDeclarations({ tools: tools.map(declarationTool) }))
|
|
159
252
|
|
|
160
253
|
type Candidate = {
|
|
161
254
|
readonly tool: CodeModeCatalogTool
|
|
@@ -255,8 +348,9 @@ export const selectCodeModeListing = (
|
|
|
255
348
|
const intro = [
|
|
256
349
|
'Run a JavaScript script that calls tools and returns only what matters.',
|
|
257
350
|
'`code` is the body of an async function: top-level `await` and `return` work. Write plain JavaScript; simple TypeScript annotations are stripped. There is no Node.js, network, filesystem, `require`, `fetch`, or timers.',
|
|
258
|
-
'Call tools as `await tools.<id>(args)`. Arguments must be plain JSON (no `NaN`, `undefined` array items, `Map`, or functions). A call resolves to the declared result type and rejects with an Error whose message starts with `tools.<id>:` when the tool fails. Calls still running when the script ends are cancelled, so await every call (use `Promise.all` for parallel calls).',
|
|
259
|
-
'
|
|
351
|
+
'Call tools as `await tools.<id>(args)`. Arguments must be plain JSON (no `NaN`, `undefined` array items, `Map`, or functions). A call resolves to the declared result type and rejects with an Error whose message starts with `tools.<id>:` when the tool fails (`error.code` is set when the tool reports one). Calls still running when the script ends are cancelled, so await every call (use `Promise.all` for parallel calls).',
|
|
352
|
+
'`string` results are text to read; parse JSON only when the tool says it returns JSON.',
|
|
353
|
+
'Files are typed fields of results: `type FileRef = { fileId: string; name: string; mimeType: string; size: number }`; `type FileUnavailable = { unavailable: string; name: string; mimeType: string }` (`unavailable` says why the file was not stored). Pass `fileId`s to other tools; file bytes never enter the script.',
|
|
260
354
|
'Only the script output and its return value come back to you: filter and aggregate inside the script and return a small JSON value.'
|
|
261
355
|
].join('\n')
|
|
262
356
|
|
|
@@ -410,7 +504,7 @@ const compactText = (rendered: string) =>
|
|
|
410
504
|
.join(' ')
|
|
411
505
|
|
|
412
506
|
const compactResultType = (schema: CodeModeJsonSchema) => {
|
|
413
|
-
const rendered = compactText(
|
|
507
|
+
const rendered = compactText(renderOutputType(schema))
|
|
414
508
|
|
|
415
509
|
return rendered.length <= maxShortTypeChars ? rendered : shortType(schema)
|
|
416
510
|
}
|
|
@@ -449,7 +543,7 @@ export const describeCodeModeTool = (tool: CodeModeCatalogTool): string =>
|
|
|
449
543
|
`Stage-only (approval-gated): record a call with \`await stage(${JSON.stringify(tool.name)}, args)\`; it runs only after a person approves the plan.`,
|
|
450
544
|
`args: ${schemaToType(tool.inputSchema)}`
|
|
451
545
|
].join('\n\n')
|
|
452
|
-
: renderToolSample(declarationTool(tool))
|
|
546
|
+
: withFileTypeNames(renderToolSample(declarationTool(tool)))
|
|
453
547
|
|
|
454
548
|
/**
|
|
455
549
|
* Finds a tool by identifier or raw name. A stageable tool's exact raw name wins first: it has no
|
package/src/executor.ts
CHANGED
|
@@ -16,8 +16,9 @@ export type CodeModeToolContext = {
|
|
|
16
16
|
* A function a script can call. Tools are called as `tools.<identifier>(args)` and
|
|
17
17
|
* `tools["<name>"](args)`; the identifier replaces characters that are not valid in a JavaScript
|
|
18
18
|
* identifier with `_`. Arguments and results make a JSON round trip; a rejection surfaces in the
|
|
19
|
-
* script as an `Error` with the same message
|
|
20
|
-
* `<call label>: <message>`, the label being
|
|
19
|
+
* script as an `Error` with the same message and, when the rejected error has a string `code`, that
|
|
20
|
+
* `code` (`makeCodeModeTool` rejects with `<call label>: <message>`, the label being
|
|
21
|
+
* `tools.<identifier>` or `tools["<name>"]`, and the tool's model-visible error code).
|
|
21
22
|
*
|
|
22
23
|
* `args` is the JSON value of the script's first argument (`undefined` when there is none), read
|
|
23
24
|
* once the way `JSON.stringify` reads it (getters and `toJSON` run once); the checked value is the
|