@yolk-sdk/codemode 0.1.0-canary.108 → 0.1.0-canary.109
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 +2 -1
- package/dist/catalog.d.mts +18 -10
- package/dist/catalog.d.mts.map +1 -1
- package/dist/catalog.mjs +19 -13
- package/dist/catalog.mjs.map +1 -1
- package/dist/tool.mjs +2 -2
- package/dist/tool.mjs.map +1 -1
- package/package.json +2 -2
- package/src/catalog.ts +29 -19
- package/src/tool.ts +2 -2
package/README.md
CHANGED
|
@@ -145,7 +145,8 @@ to lower the cap.
|
|
|
145
145
|
A stageable tool may be **stage-only** (`callableBy: 'codemode'`, usually with `discovery: 'search'`):
|
|
146
146
|
it is never declared to the model, scripts find it with `searchTools()` (hits marked
|
|
147
147
|
`stageOnly: true`) and read it with `describeTool()`, and the only thing they can do with it is
|
|
148
|
-
`stage()` it.
|
|
148
|
+
`stage()` it. Model-callable stageable tools (`all`, deferred or not) are found the same way. See
|
|
149
|
+
[ADR 0007](https://github.com/magoz/yolk-sdk/blob/main/docs/adr/0007-tool-exposure-and-catalog.md).
|
|
149
150
|
|
|
150
151
|
Applied plan calls run inside the review action: they bypass `beforeNestedCall` and `ToolExecutor`
|
|
151
152
|
decorators. Wire the same per-call check as `makePlanReviewTool({ beforeCall })`. Review screens
|
package/dist/catalog.d.mts
CHANGED
|
@@ -5,8 +5,8 @@ import { RunInstruction } from "@yolk-sdk/agent/loop";
|
|
|
5
5
|
|
|
6
6
|
//#region src/catalog.d.ts
|
|
7
7
|
/** How a nested tool reaches scripts: `all` tools are also direct model tools; `listed` and
|
|
8
|
-
* `search` are the two discovery modes of `codemode`-only tools; `stage` marks a
|
|
9
|
-
* (ADR 0007): found by search, never callable, only passed to `stage()`.
|
|
8
|
+
* `search` are the two discovery modes of `codemode`-only tools; `stage` marks a stageable tool
|
|
9
|
+
* (approval-gated, ADR 0007): found by search, never callable, only passed to `stage()`.
|
|
10
10
|
*/
|
|
11
11
|
type CodeModeToolExposure = 'all' | 'listed' | 'search' | 'pinned' | 'stage';
|
|
12
12
|
/** One nested tool as scripts see it. */
|
|
@@ -38,9 +38,10 @@ declare const codeModeCallLabels: (names: ReadonlyArray<string>) => ReadonlyArra
|
|
|
38
38
|
/** Catalog of nested tools in resolution order. */
|
|
39
39
|
declare const codeModeCatalog: (tools: ReadonlyArray<NestedTool>) => ReadonlyArray<CodeModeCatalogTool>;
|
|
40
40
|
/**
|
|
41
|
-
* Catalog entries of the
|
|
42
|
-
*
|
|
43
|
-
*
|
|
41
|
+
* Catalog entries of the stageable tools (ADR 0007). Stageable tools are approval-gated, so scripts
|
|
42
|
+
* can only `stage()` them whatever their `callableBy` (stage-only `codemode` ones are also never
|
|
43
|
+
* declared to the model): searchable and describable, never callable (no `tools` binding), so
|
|
44
|
+
* their call label is the `stage()` call that records them.
|
|
44
45
|
*/
|
|
45
46
|
declare const codeModeStageOnlyCatalog: (stageable: ReadonlyArray<NestedTool>) => ReadonlyArray<CodeModeCatalogTool>;
|
|
46
47
|
/** Default inline budget of the nested tool listing, in estimated tokens. */
|
|
@@ -70,7 +71,7 @@ type CodeModeStagingDescription = {
|
|
|
70
71
|
type CodeModeDescriptionInput = {
|
|
71
72
|
readonly tools: ReadonlyArray<NestedTool>;
|
|
72
73
|
readonly inlineBudget?: number; /** Mention `store()`/`load()` persistence. */
|
|
73
|
-
readonly store?: boolean; /** Document `stage()` and list the stageable tools that are
|
|
74
|
+
readonly store?: boolean; /** Document `stage()` and list the stageable tools that are neither `search` nor deferred. */
|
|
74
75
|
readonly staging?: CodeModeStagingDescription;
|
|
75
76
|
};
|
|
76
77
|
/**
|
|
@@ -79,8 +80,9 @@ type CodeModeDescriptionInput = {
|
|
|
79
80
|
* `all` tools get one line each outside the budget; `listed` tools are declared within the inline
|
|
80
81
|
* budget; `search` tools never contribute, so adding or removing them (even whole namespaces of
|
|
81
82
|
* them) leaves the text byte-identical. With `staging` (and stageable tools), `stage()` is listed
|
|
82
|
-
* with the globals and the stageable tool names follow the nested tools;
|
|
83
|
-
* are never named, so they leave the text byte-identical too once any stageable
|
|
83
|
+
* with the globals and the stageable tool names follow the nested tools; `search` and deferred
|
|
84
|
+
* stageable tools are never named, so they leave the text byte-identical too once any stageable
|
|
85
|
+
* tool exists.
|
|
84
86
|
*/
|
|
85
87
|
declare const renderCodeModeDescription: (input: CodeModeDescriptionInput) => string;
|
|
86
88
|
/**
|
|
@@ -88,7 +90,11 @@ declare const renderCodeModeDescription: (input: CodeModeDescriptionInput) => st
|
|
|
88
90
|
* has no `tools` binding, so it is described as the `stage()` call that records it.
|
|
89
91
|
*/
|
|
90
92
|
declare const describeCodeModeTool: (tool: CodeModeCatalogTool) => string;
|
|
91
|
-
/**
|
|
93
|
+
/**
|
|
94
|
+
* Finds a tool by identifier or raw name. A stageable tool's exact raw name wins first: it has no
|
|
95
|
+
* binding, so a callable tool sharing its identifier (`archive-resource` vs `archive_resource`)
|
|
96
|
+
* must not answer for it; callable lookups keep identifier precedence, as their bindings do.
|
|
97
|
+
*/
|
|
92
98
|
declare const findCodeModeTool: (catalog: ReadonlyArray<CodeModeCatalogTool>, name: string) => CodeModeCatalogTool | undefined;
|
|
93
99
|
/** The instruction key of the code mode catalog (`catalog: 'instructions'`, ADR 0007). */
|
|
94
100
|
declare const codeModeCatalogInstructionKey = "yolk.codemode.catalog";
|
|
@@ -100,7 +106,9 @@ declare const CodeModeCatalogSummary: Schema.Struct<{
|
|
|
100
106
|
readonly count: Schema.Number; /** Tools the listing shows. */
|
|
101
107
|
readonly shown: Schema.Number; /** The rendered declarations and direct tool lines of the shown tools. */
|
|
102
108
|
readonly listing: Schema.String;
|
|
103
|
-
}>>;
|
|
109
|
+
}>>;
|
|
110
|
+
/** Stageable tool names the catalog lists: `pinned` ones, then the others (never `search` or
|
|
111
|
+
* deferred ones). */
|
|
104
112
|
readonly stageable: Schema.Struct<{
|
|
105
113
|
readonly pinned: Schema.$Array<Schema.String>;
|
|
106
114
|
readonly listed: Schema.$Array<Schema.String>;
|
package/dist/catalog.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.d.mts","names":[],"sources":["../src/catalog.ts"],"mappings":";;;;;;;;AAkBA;;KAAY,oBAAA;;KAGA,mBAAA;EAAA,wEAED,IAAA;WAEA,UAAA;EAcc;;;;;EAAA,SARd,SAAA;EAAA,SAEA,SAAA,UAEA;EAAA,SAAA,oBAAA;EAAA,SACA,WAAA;EAAA,SACA,WAAA,EAAa,kBAAA,EAEb;EAAA,SAAA,YAAA,EAAc,kBAAA,EAEd;EAAA,SAAA,UAAA;EAAA,SACA,QAAA,EAAU,oBAAA;AAAA;AAAoB;AAYzC;;;;;;AAZyC,cAY5B,kBAAA,GAAsB,KAAA,EAAO,aAAA,aAAwB,aAAa;;cAelE,eAAA,GACX,KAAA,EAAO,aAAA,CAAc,UAAA,MACpB,aAAA,CAAc,mBAAA;AAFjB
|
|
1
|
+
{"version":3,"file":"catalog.d.mts","names":[],"sources":["../src/catalog.ts"],"mappings":";;;;;;;;AAkBA;;KAAY,oBAAA;;KAGA,mBAAA;EAAA,wEAED,IAAA;WAEA,UAAA;EAcc;;;;;EAAA,SARd,SAAA;EAAA,SAEA,SAAA,UAEA;EAAA,SAAA,oBAAA;EAAA,SACA,WAAA;EAAA,SACA,WAAA,EAAa,kBAAA,EAEb;EAAA,SAAA,YAAA,EAAc,kBAAA,EAEd;EAAA,SAAA,UAAA;EAAA,SACA,QAAA,EAAU,oBAAA;AAAA;AAAoB;AAYzC;;;;;;AAZyC,cAY5B,kBAAA,GAAsB,KAAA,EAAO,aAAA,aAAwB,aAAa;;cAelE,eAAA,GACX,KAAA,EAAO,aAAA,CAAc,UAAA,MACpB,aAAA,CAAc,mBAAA;AAFjB;;;;;;AAAA,cAgCa,wBAAA,GACX,SAAA,EAAW,aAAA,CAAc,UAAA,MACxB,aAAA,CAAc,mBAAA;;cAoBJ,2BAAA;;cAGA,sBAAA,GAA0B,IAAY;AAAA,KA4DvC,eAAA;EAnHT;;;EAAA,SAuHQ,MAAA,EAAQ,aAAA,CAAc,mBAAA,GAzFpB;EAAA,SA2FF,kBAAA,EAAoB,aAAA;AAAA;;;;;;;;cAUlB,qBAAA,GACX,OAAA,EAAS,aAAA,CAAc,mBAAA,GACvB,MAAA,aACC,eAAA;;KAoIS,0BAAA;EAAA,SACD,KAAA,EAAO,aAAa,CAAC,UAAA;EAAA,SACrB,cAAA;AAAA;AAAA,KAGC,wBAAA;EAAA,SACD,KAAA,EAAO,aAAA,CAAc,UAAA;EAAA,SACrB,YAAA,WA7N6B;EAAA,SA+N7B,KAAA,YA5NE;EAAA,SA8NF,OAAA,GAAU,0BAAA;AAAA;;AA9N8B;AA4DnD;;;;;;;;cA+Ka,yBAAA,GAA6B,KAA+B,EAAxB,wBAAwB;;;;;cAsC5D,oBAAA,GAAwB,IAAyB,EAAnB,mBAAmB;AA/MlB;AAU5C;;;;AAV4C,cA6N/B,gBAAA,GACX,OAAA,EAAS,aAAA,CAAc,mBAAA,GACvB,IAAA,aACC,mBAAA;;cAMU,6BAAA;;cAcA,sBAAA,EAAsB,MAAA,CAAA,MAAA;EAAA;;0DAvOhC;IAAA,+BA+CF;IAAA,+BAqFqC;IAAA;;EAC3B;;EAAA;;;;;KA4GC,sBAAA,UAAgC,sBAAA,CAAuB,IAAI;;;;;;cAqB1D,wBAAA,GAA4B,KAAA;EAAA,SAC9B,KAAA,EAAO,aAAA,CAAc,UAAA;EAAA,SACrB,OAAA,GAAU,0BAAA;EAAA,SACV,YAAA;AAAA,MACP,sBAAA;;cA6CS,qBAAA,GAAyB,OAA+B,EAAtB,sBAAsB;;;AAxKtB;AAa/C;cA0Ka,0BAAA,GAA8B,KAAA;EAAA,SAChC,KAAA,EAAO,aAAA,CAAc,UAAA;EAAA,SACrB,OAAA,GAAU,0BAAA;EAAA,SACV,YAAA;AAAA,MACP,cAAA;;;;AAxI0D;cA+JjD,mCAAA,GAAuC,KAAA;EAAA,SACzC,KAAA;EAAA,SACA,OAAA,GAAU,0BAA0B;AAAA"}
|
package/dist/catalog.mjs
CHANGED
|
@@ -43,12 +43,12 @@ const codeModeCatalog = (tools) => {
|
|
|
43
43
|
});
|
|
44
44
|
};
|
|
45
45
|
/**
|
|
46
|
-
* Catalog entries of the
|
|
47
|
-
*
|
|
48
|
-
*
|
|
46
|
+
* Catalog entries of the stageable tools (ADR 0007). Stageable tools are approval-gated, so scripts
|
|
47
|
+
* can only `stage()` them whatever their `callableBy` (stage-only `codemode` ones are also never
|
|
48
|
+
* declared to the model): searchable and describable, never callable (no `tools` binding), so
|
|
49
|
+
* their call label is the `stage()` call that records them.
|
|
49
50
|
*/
|
|
50
|
-
const codeModeStageOnlyCatalog = (stageable) => stageable.
|
|
51
|
-
if (def.callableBy !== "codemode") return [];
|
|
51
|
+
const codeModeStageOnlyCatalog = (stageable) => stageable.map(({ def, moduleId, moduleDescription }) => {
|
|
52
52
|
const tool = {
|
|
53
53
|
name: def.name,
|
|
54
54
|
identifier: toCodemodeIdentifier(def.name),
|
|
@@ -60,10 +60,10 @@ const codeModeStageOnlyCatalog = (stageable) => stageable.flatMap(({ def, module
|
|
|
60
60
|
structured: def.outputSchema !== void 0,
|
|
61
61
|
exposure: "stage"
|
|
62
62
|
};
|
|
63
|
-
return
|
|
63
|
+
return moduleDescription === void 0 ? tool : {
|
|
64
64
|
...tool,
|
|
65
65
|
namespaceDescription: moduleDescription
|
|
66
|
-
}
|
|
66
|
+
};
|
|
67
67
|
});
|
|
68
68
|
/** Default inline budget of the nested tool listing, in estimated tokens. */
|
|
69
69
|
const defaultCodeModeInlineBudget = 3e3;
|
|
@@ -144,7 +144,7 @@ const listedStageableNames = (staging) => ({
|
|
|
144
144
|
pinned: staging.tools.flatMap(({ def }) => toolDiscovery(def) === "pinned" ? [def.name] : []),
|
|
145
145
|
listed: staging.tools.flatMap(({ def }) => {
|
|
146
146
|
const discovery = toolDiscovery(def);
|
|
147
|
-
return discovery === "search" || discovery === "pinned" ? [] : [def.name];
|
|
147
|
+
return discovery === "search" || discovery === "pinned" || isDeferredTool(def) ? [] : [def.name];
|
|
148
148
|
})
|
|
149
149
|
});
|
|
150
150
|
const hasStageableNames = (names) => names.pinned.length > 0 || names.listed.length > 0;
|
|
@@ -191,8 +191,9 @@ const unlistedToolsLine = "More tools may be callable than are listed here: find
|
|
|
191
191
|
* `all` tools get one line each outside the budget; `listed` tools are declared within the inline
|
|
192
192
|
* budget; `search` tools never contribute, so adding or removing them (even whole namespaces of
|
|
193
193
|
* them) leaves the text byte-identical. With `staging` (and stageable tools), `stage()` is listed
|
|
194
|
-
* with the globals and the stageable tool names follow the nested tools;
|
|
195
|
-
* are never named, so they leave the text byte-identical too once any stageable
|
|
194
|
+
* with the globals and the stageable tool names follow the nested tools; `search` and deferred
|
|
195
|
+
* stageable tools are never named, so they leave the text byte-identical too once any stageable
|
|
196
|
+
* tool exists.
|
|
196
197
|
*/
|
|
197
198
|
const renderCodeModeDescription = (input) => {
|
|
198
199
|
const sections = [...groupByNamespace(selectCodeModeListing(codeModeCatalog(input.tools), input.inlineBudget ?? 3e3).listed.map((tool) => ({ tool })))].map(([namespace, items]) => namespaceSection(namespace, items.map((item) => item.tool)));
|
|
@@ -222,8 +223,12 @@ const describeCodeModeTool = (tool) => tool.exposure === "stage" ? [
|
|
|
222
223
|
`Stage-only (approval-gated): record a call with \`await stage(${JSON.stringify(tool.name)}, args)\`; it runs only after a person approves the plan.`,
|
|
223
224
|
`args: ${schemaToType(tool.inputSchema)}`
|
|
224
225
|
].join("\n\n") : renderToolSample(declarationTool(tool));
|
|
225
|
-
/**
|
|
226
|
-
|
|
226
|
+
/**
|
|
227
|
+
* Finds a tool by identifier or raw name. A stageable tool's exact raw name wins first: it has no
|
|
228
|
+
* binding, so a callable tool sharing its identifier (`archive-resource` vs `archive_resource`)
|
|
229
|
+
* must not answer for it; callable lookups keep identifier precedence, as their bindings do.
|
|
230
|
+
*/
|
|
231
|
+
const findCodeModeTool = (catalog, name) => catalog.find((tool) => tool.exposure === "stage" && tool.name === name) ?? catalog.find((tool) => tool.identifier === name) ?? catalog.find((tool) => tool.name === name);
|
|
227
232
|
/** The instruction key of the code mode catalog (`catalog: 'instructions'`, ADR 0007). */
|
|
228
233
|
const codeModeCatalogInstructionKey = "yolk.codemode.catalog";
|
|
229
234
|
const CodeModeCatalogNamespace = Schema.Struct({
|
|
@@ -239,7 +244,8 @@ const CodeModeCatalogNamespace = Schema.Struct({
|
|
|
239
244
|
/** The catalog an instruction message records as its state (JSON, never model-visible). */
|
|
240
245
|
const CodeModeCatalogSummary = Schema.Struct({
|
|
241
246
|
namespaces: Schema.Array(CodeModeCatalogNamespace),
|
|
242
|
-
/** Stageable tool names the catalog lists: `pinned` ones, then
|
|
247
|
+
/** Stageable tool names the catalog lists: `pinned` ones, then the others (never `search` or
|
|
248
|
+
* deferred ones). */
|
|
243
249
|
stageable: Schema.Struct({
|
|
244
250
|
pinned: Schema.Array(Schema.String),
|
|
245
251
|
listed: Schema.Array(Schema.String)
|
package/dist/catalog.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.mjs","names":[],"sources":["../src/catalog.ts"],"sourcesContent":["import { Option, Predicate } from 'effect'\nimport * as Schema from 'effect/Schema'\nimport {\n renderDeclarations,\n renderToolOutputType,\n renderToolSample,\n schemaToType,\n toCodemodeIdentifier\n} from '@earendil-works/pi-codemode/declarations'\nimport { isDeferredTool, toolDiscovery } from '@yolk-sdk/agent/protocol'\nimport type { RunInstruction } from '@yolk-sdk/agent/loop'\nimport type { NestedTool } from '@yolk-sdk/agent/tools'\nimport type { CodeModeJsonSchema } from './executor.ts'\n\n/** How a nested tool reaches scripts: `all` tools are also direct model tools; `listed` and\n * `search` are the two discovery modes of `codemode`-only tools; `stage` marks a stage-only tool\n * (ADR 0007): found by search, never callable, only passed to `stage()`.\n */\nexport type CodeModeToolExposure = 'all' | 'listed' | 'search' | 'pinned' | 'stage'\n\n/** One nested tool as scripts see it. */\nexport type CodeModeCatalogTool = {\n /** Raw tool name; scripts may call `tools[\"<name>\"](args)`. */\n readonly name: string\n /** Identifier for `tools.<identifier>(args)` (invalid identifier characters become `_`). */\n readonly identifier: string\n /**\n * How scripts call this tool, used to prefix its rejections: `tools.<identifier>`, or\n * `tools[\"<name>\"]` when an earlier tool already has the identifier (see `codeModeCallLabels`;\n * when the name is taken too, the tool is unreachable and the label only names it).\n */\n readonly callLabel: string\n /** The tool's `ToolModule.id`. */\n readonly namespace: string\n /** The module's `ToolModule.description`, when set. */\n readonly namespaceDescription?: string\n readonly description: string\n readonly inputSchema: CodeModeJsonSchema\n /** The declared output schema, or `{ type: 'string' }` for text results. */\n readonly outputSchema: CodeModeJsonSchema\n /** True when the tool declares an output schema (calls resolve to `structuredContent`). */\n readonly structured: boolean\n readonly exposure: CodeModeToolExposure\n}\n\nconst textOutputSchema: CodeModeJsonSchema = { type: 'string' }\n\n/**\n * The call label of each tool name, in order, as pi binds `tools`: each tool takes\n * `tools[<identifier>]` unless an earlier tool holds that key (first tool wins), then\n * `tools[<name>]` if still free. The label is `tools.<identifier>` for the tool that holds its\n * identifier, otherwise `tools[\"<name>\"]`. The executor guard and the host rejection prefix share\n * it, so both name a call the same way.\n */\nexport const codeModeCallLabels = (names: ReadonlyArray<string>): ReadonlyArray<string> => {\n const bound = new Set<string>()\n\n return names.map(name => {\n const identifier = toCodemodeIdentifier(name)\n const ownsIdentifier = !bound.has(identifier)\n\n bound.add(identifier)\n bound.add(name)\n\n return ownsIdentifier ? `tools.${identifier}` : `tools[${JSON.stringify(name)}]`\n })\n}\n\n/** Catalog of nested tools in resolution order. */\nexport const codeModeCatalog = (\n tools: ReadonlyArray<NestedTool>\n): ReadonlyArray<CodeModeCatalogTool> => {\n const labels = codeModeCallLabels(tools.map(({ def }) => def.name))\n\n return tools.map(({ def, moduleId, moduleDescription }, index) => {\n const tool: CodeModeCatalogTool = {\n name: def.name,\n identifier: toCodemodeIdentifier(def.name),\n callLabel: labels[index] ?? `tools[${JSON.stringify(def.name)}]`,\n namespace: moduleId,\n description: def.description,\n inputSchema: def.parameters,\n outputSchema: def.outputSchema ?? textOutputSchema,\n structured: def.outputSchema !== undefined,\n // A deferred tool's declaration is not in model context until activated: scripts find it\n // by search like a codemode-only `search` tool (ADR 0007).\n exposure: toolDiscovery(def) ?? (isDeferredTool(def) ? 'search' : 'all')\n }\n\n return moduleDescription === undefined\n ? tool\n : { ...tool, namespaceDescription: moduleDescription }\n })\n}\n\n/**\n * Catalog entries of the stage-only tools among the stageable ones (`callableBy: 'codemode'`,\n * ADR 0007): searchable and describable, never callable (no `tools` binding), so their call label\n * is the `stage()` call that records them.\n */\nexport const codeModeStageOnlyCatalog = (\n stageable: ReadonlyArray<NestedTool>\n): ReadonlyArray<CodeModeCatalogTool> =>\n stageable.flatMap(({ def, moduleId, moduleDescription }) => {\n if (def.callableBy !== 'codemode') return []\n\n const tool: CodeModeCatalogTool = {\n name: def.name,\n identifier: toCodemodeIdentifier(def.name),\n callLabel: `stage(${JSON.stringify(def.name)})`,\n namespace: moduleId,\n description: def.description,\n inputSchema: def.parameters,\n outputSchema: def.outputSchema ?? textOutputSchema,\n structured: def.outputSchema !== undefined,\n exposure: 'stage'\n }\n\n return [\n moduleDescription === undefined ? tool : { ...tool, namespaceDescription: moduleDescription }\n ]\n })\n\n/** Default inline budget of the nested tool listing, in estimated tokens. */\nexport const defaultCodeModeInlineBudget = 3000\n\n/** Estimated tokens of a text: four characters per token, rounded up. */\nexport const estimateCodeModeTokens = (text: string): number => Math.ceil(text.length / 4)\n\nconst maxShortTypeChars = 60\n\nconst shortType = (schema: CodeModeJsonSchema): string => {\n const rendered = renderToolOutputType(schema)\n\n if (rendered.length <= maxShortTypeChars) return rendered\n\n if (!Predicate.isBoolean(schema)) {\n if (schema.type === 'array') return 'Array<unknown>'\n\n if (schema.type === 'object') return 'object'\n }\n\n return 'unknown'\n}\n\n// Declarations only read names, descriptions, and schemas; `execute` is never called.\nconst declarationTool = (tool: CodeModeCatalogTool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n outputSchema: tool.outputSchema,\n execute: () => undefined\n})\n\nconst directToolLine = (tool: CodeModeCatalogTool) =>\n `- \\`tools.${tool.identifier}(args)\\` takes the arguments of the \\`${tool.name}\\` tool and resolves to \\`${shortType(tool.outputSchema)}\\`.`\n\nconst declarationMembers = (tools: ReadonlyArray<CodeModeCatalogTool>) =>\n renderDeclarations({ tools: tools.map(declarationTool) })\n\ntype Candidate = {\n readonly tool: CodeModeCatalogTool\n readonly index: number\n readonly cost: number\n}\n\nconst candidateCost = (tool: CodeModeCatalogTool) =>\n estimateCodeModeTokens(declarationMembers([tool]))\n\nconst groupByNamespace = <A extends { readonly tool: CodeModeCatalogTool }>(\n items: ReadonlyArray<A>\n): ReadonlyMap<string, ReadonlyArray<A>> => {\n const groups = new Map<string, Array<A>>()\n\n for (const item of items) {\n const group = groups.get(item.tool.namespace)\n\n if (group === undefined) {\n groups.set(item.tool.namespace, [item])\n } else {\n group.push(item)\n }\n }\n\n return groups\n}\n\nexport type CodeModeListing = {\n /** Tools placed in the description, in catalog order: every `all` tool, and the `listed` tools\n * that fit the budget.\n */\n readonly listed: ReadonlyArray<CodeModeCatalogTool>\n /** Namespaces (catalog order) with callable tools the description does not list. */\n readonly unlistedNamespaces: ReadonlyArray<string>\n}\n\n/**\n * Chooses the tools the description lists. `all` tools are always placed, outside the budget\n * (the model already has their declarations), and so are `pinned` tools. `listed` tools fill\n * `budget` estimated tokens fairly across namespaces: each round, every namespace still in play\n * places its cheapest remaining tool; a namespace whose next tool does not fit drops out. `search`\n * tools are never candidates.\n */\nexport const selectCodeModeListing = (\n catalog: ReadonlyArray<CodeModeCatalogTool>,\n budget: number\n): CodeModeListing => {\n const candidates = catalog.flatMap((tool, index): ReadonlyArray<Candidate> =>\n tool.exposure === 'listed' ? [{ tool, index, cost: candidateCost(tool) }] : []\n )\n\n const queues = new Map(\n [...groupByNamespace(candidates)].map(([namespace, group]) => [\n namespace,\n [...group].sort((left, right) => left.cost - right.cost || left.index - right.index)\n ])\n )\n\n const placed = new Set(\n catalog.flatMap((tool, index) =>\n tool.exposure === 'all' || tool.exposure === 'pinned' ? [index] : []\n )\n )\n\n const inPlay = new Set(queues.keys())\n let remaining = budget\n\n while (inPlay.size > 0) {\n for (const [namespace, queue] of queues) {\n if (!inPlay.has(namespace)) continue\n\n const next = queue.shift()\n\n if (next === undefined || next.cost > remaining) {\n inPlay.delete(namespace)\n continue\n }\n\n placed.add(next.index)\n remaining -= next.cost\n }\n }\n\n const unlisted = new Set(\n catalog.flatMap((tool, index) => (placed.has(index) ? [] : [tool.namespace]))\n )\n\n return {\n listed: catalog.filter((_, index) => placed.has(index)),\n unlistedNamespaces: [...new Set(catalog.map(tool => tool.namespace))].filter(namespace =>\n unlisted.has(namespace)\n )\n }\n}\n\nconst intro = [\n 'Run a JavaScript script that calls tools and returns only what matters.',\n '`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.',\n '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).',\n 'Only the script output and its return value come back to you: filter and aggregate inside the script and return a small JSON value.'\n].join('\\n')\n\nconst stageLine = (reviewToolName: string) =>\n `- \\`await stage(name, args)\\`: record a call of a stageable tool for review instead of running it; resolves to \\`{ staged: true, key, index }\\`. Nothing runs until a person approves the plan through the \\`${reviewToolName}\\` tool, which the result tells you how to call. Once a script stages, it may only run read tools; a script that already ran a write tool cannot stage. \\`searchTools\\` marks approval-gated tools \\`stageOnly: true\\`: they have no \\`tools\\` binding, only \\`stage()\\` them.`\n\n/** Stageable tool names listed in the description; the rest are summarized with a count. */\nconst maxListedStageableTools = 20\n\n/** Stageable tools the description names: `pinned` ones first, never stage-only `search` ones. */\ntype StageableNames = {\n readonly pinned: ReadonlyArray<string>\n readonly listed: ReadonlyArray<string>\n}\n\nconst listedStageableNames = (staging: CodeModeStagingDescription): StageableNames => ({\n pinned: staging.tools.flatMap(({ def }) => (toolDiscovery(def) === 'pinned' ? [def.name] : [])),\n listed: staging.tools.flatMap(({ def }) => {\n const discovery = toolDiscovery(def)\n\n return discovery === 'search' || discovery === 'pinned' ? [] : [def.name]\n })\n})\n\nconst hasStageableNames = (names: StageableNames) =>\n names.pinned.length > 0 || names.listed.length > 0\n\n/** `pinned` names are always shown; the cap applies to the others. */\nconst stageableSection = (names: StageableNames) => {\n const room = Math.max(0, maxListedStageableTools - names.pinned.length)\n const hidden = names.listed.length - room\n\n return [\n '## Stageable tools',\n 'Approval-gated tools a script cannot call through `tools`, only stage with `await stage(\"<name>\", args)` (arguments as for the tool of the same name):',\n ...[...names.pinned, ...names.listed.slice(0, room)].map(name => `- \\`${name}\\``),\n ...(hidden > 0 ? [`- … and ${hidden} more (find them with \\`searchTools\\`).`] : [])\n ].join('\\n')\n}\n\nconst globalLines = (store: boolean) => [\n '- `text(value)` and `console.log(...values)`: append text to the output.',\n '- `image(dataUrl)`: append a base64 image (a `data:` URL or `{ type: \"image\", data, mimeType }`).',\n '- `exit()`: end the script successfully.',\n '- `ALL_TOOLS`: `{ name, description }` of every callable tool.',\n '- `await searchTools(query, { limit?, namespace? })`: find tools by topic; resolves to `Array<{ name: string; description: string }>` (default limit 8).',\n '- `await describeTool(name)`: the description and TypeScript declaration of a tool, or `undefined`.',\n '- `await describeNamespace(name)`: `{ name, description?, tools: Array<{ name, description }> }` for a namespace, or `undefined`.',\n ...(store\n ? [\n '- `store(key, value)` and `load(key)`: keep small JSON values for later scripts; writes are saved only when the script succeeds.'\n ]\n : [])\n]\n\nconst namespaceSection = (namespace: string, tools: ReadonlyArray<CodeModeCatalogTool>) => {\n const declared = tools.filter(tool => tool.exposure !== 'all')\n const direct = tools.filter(tool => tool.exposure === 'all')\n\n const description = tools.find(\n tool => tool.namespaceDescription !== undefined\n )?.namespaceDescription\n\n return [\n `### ${namespace}`,\n ...(description === undefined ? [] : [description]),\n ...(declared.length > 0 ? ['```ts', declarationMembers(declared), '```'] : []),\n ...direct.map(directToolLine)\n ].join('\\n')\n}\n\n// Fixed text: never derived from `search` tools or from which tools did not fit the budget.\nconst unlistedToolsLine =\n 'More tools may be callable than are listed here: find them with `await searchTools(query, { namespace? })` and read one with `await describeTool(name)` or `await describeNamespace(name)` before calling it.'\n\n/** Staged tool plans as the description shows them (`NestedToolStagingDescription`). */\nexport type CodeModeStagingDescription = {\n readonly tools: ReadonlyArray<NestedTool>\n readonly reviewToolName: string\n}\n\nexport type CodeModeDescriptionInput = {\n readonly tools: ReadonlyArray<NestedTool>\n readonly inlineBudget?: number\n /** Mention `store()`/`load()` persistence. */\n readonly store?: boolean\n /** Document `stage()` and list the stageable tools that are not stage-only `search` tools. */\n readonly staging?: CodeModeStagingDescription\n}\n\n/**\n * The code mode tool description: intro, globals one per line, then nested tools grouped by\n * namespace, then one fixed line pointing to `searchTools`/`describeTool`/`describeNamespace`.\n * `all` tools get one line each outside the budget; `listed` tools are declared within the inline\n * budget; `search` tools never contribute, so adding or removing them (even whole namespaces of\n * them) leaves the text byte-identical. With `staging` (and stageable tools), `stage()` is listed\n * with the globals and the stageable tool names follow the nested tools; stage-only `search` tools\n * are never named, so they leave the text byte-identical too once any stageable tool exists.\n */\nexport const renderCodeModeDescription = (input: CodeModeDescriptionInput): string => {\n const catalog = codeModeCatalog(input.tools)\n\n const listing = selectCodeModeListing(catalog, input.inlineBudget ?? defaultCodeModeInlineBudget)\n\n const sections = [...groupByNamespace(listing.listed.map(tool => ({ tool })))].map(\n ([namespace, items]) =>\n namespaceSection(\n namespace,\n items.map(item => item.tool)\n )\n )\n\n const staging =\n input.staging !== undefined && input.staging.tools.length > 0 ? input.staging : undefined\n\n const stageableNames =\n staging === undefined ? { pinned: [], listed: [] } : listedStageableNames(staging)\n\n return [\n intro,\n [\n 'Globals:',\n ...globalLines(input.store === true),\n ...(staging === undefined ? [] : [stageLine(staging.reviewToolName)])\n ].join('\\n'),\n sections.length === 0\n ? 'Nested tools: none are listed here.'\n : ['## Nested tools by namespace', ...sections].join('\\n\\n'),\n ...(hasStageableNames(stageableNames) ? [stageableSection(stageableNames)] : []),\n unlistedToolsLine\n ].join('\\n\\n')\n}\n\n/**\n * `describeTool` text: the description and TypeScript declaration of one tool. A stage-only tool\n * has no `tools` binding, so it is described as the `stage()` call that records it.\n */\nexport const describeCodeModeTool = (tool: CodeModeCatalogTool): string =>\n tool.exposure === 'stage'\n ? [\n tool.description,\n `Stage-only (approval-gated): record a call with \\`await stage(${JSON.stringify(tool.name)}, args)\\`; it runs only after a person approves the plan.`,\n `args: ${schemaToType(tool.inputSchema)}`\n ].join('\\n\\n')\n : renderToolSample(declarationTool(tool))\n\n/** Finds a tool by identifier or raw name. */\nexport const findCodeModeTool = (\n catalog: ReadonlyArray<CodeModeCatalogTool>,\n name: string\n): CodeModeCatalogTool | undefined =>\n catalog.find(tool => tool.identifier === name) ?? catalog.find(tool => tool.name === name)\n\n/** The instruction key of the code mode catalog (`catalog: 'instructions'`, ADR 0007). */\nexport const codeModeCatalogInstructionKey = 'yolk.codemode.catalog'\n\nconst CodeModeCatalogNamespace = Schema.Struct({\n name: Schema.String,\n description: Schema.optional(Schema.String),\n /** Every tool scripts reach in the namespace: callable and stage-only. */\n count: Schema.Number,\n /** Tools the listing shows. */\n shown: Schema.Number,\n /** The rendered declarations and direct tool lines of the shown tools. */\n listing: Schema.String\n})\n\n/** The catalog an instruction message records as its state (JSON, never model-visible). */\nexport const CodeModeCatalogSummary = Schema.Struct({\n namespaces: Schema.Array(CodeModeCatalogNamespace),\n /** Stageable tool names the catalog lists: `pinned` ones, then `listed` ones (never `search`). */\n stageable: Schema.Struct({\n pinned: Schema.Array(Schema.String),\n listed: Schema.Array(Schema.String)\n })\n})\n\nexport type CodeModeCatalogSummary = typeof CodeModeCatalogSummary.Type\n\nconst decodeCatalogSummary = Schema.decodeUnknownOption(CodeModeCatalogSummary)\n\nconst encodeCatalogSummary = Schema.encodeOption(CodeModeCatalogSummary)\n\nconst namespaceListing = (tools: ReadonlyArray<CodeModeCatalogTool>) => {\n const declared = tools.filter(tool => tool.exposure !== 'all')\n const direct = tools.filter(tool => tool.exposure === 'all')\n\n return [\n ...(declared.length > 0 ? ['```ts', declarationMembers(declared), '```'] : []),\n ...direct.map(directToolLine)\n ].join('\\n')\n}\n\n/**\n * The catalog of one resolution: every namespace with its tool count and description, and the\n * listing of the tools the inline budget (or `pinned`) places. `search` and stage-only tools are\n * counted, never listed.\n */\nexport const summarizeCodeModeCatalog = (input: {\n readonly tools: ReadonlyArray<NestedTool>\n readonly staging?: CodeModeStagingDescription\n readonly inlineBudget?: number\n}): CodeModeCatalogSummary => {\n const catalog = codeModeCatalog(input.tools)\n const stageOnly = input.staging === undefined ? [] : codeModeStageOnlyCatalog(input.staging.tools)\n const listing = selectCodeModeListing(catalog, input.inlineBudget ?? defaultCodeModeInlineBudget)\n const listedByNamespace = groupByNamespace(listing.listed.map(tool => ({ tool })))\n\n const namespaces = [...groupByNamespace([...catalog, ...stageOnly].map(tool => ({ tool })))].map(\n ([name, items]) => {\n const shown = (listedByNamespace.get(name) ?? []).map(item => item.tool)\n\n const description = items.find(item => item.tool.namespaceDescription !== undefined)?.tool\n .namespaceDescription\n\n const namespace = {\n name,\n count: items.length,\n shown: shown.length,\n listing: namespaceListing(shown)\n }\n\n return description === undefined ? namespace : { ...namespace, description }\n }\n )\n\n return {\n namespaces,\n stageable:\n input.staging === undefined ? { pinned: [], listed: [] } : listedStageableNames(input.staging)\n }\n}\n\nconst namespaceLine = (namespace: CodeModeCatalogSummary['namespaces'][number]) => {\n const count = namespace.count === 1 ? '1 tool' : `${namespace.count} tools`\n\n const label =\n namespace.shown === namespace.count\n ? count\n : namespace.shown === 0\n ? `${count}, none listed`\n : `${count}, ${namespace.shown} listed`\n\n return `- \\`${namespace.name}\\` (${label})${namespace.description === undefined ? '' : `: ${namespace.description}`}`\n}\n\n/** The full catalog text of an instruction message. */\nexport const renderCodeModeCatalog = (summary: CodeModeCatalogSummary): string =>\n [\n '# Code mode catalog',\n 'Tools `codemode` scripts can call, by namespace; the latest catalog in the conversation replaces any earlier one. Call a listed tool as `await tools.<id>(args)`; find the others with `await searchTools(query, { namespace })` and read one with `await describeTool(name)` before calling it.',\n ['## Namespaces', ...summary.namespaces.map(namespaceLine)].join('\\n'),\n ...summary.namespaces.flatMap(namespace =>\n namespace.listing.length === 0 ? [] : [`### ${namespace.name}\\n${namespace.listing}`]\n ),\n ...(hasStageableNames(summary.stageable) ? [stageableSection(summary.stageable)] : [])\n ].join('\\n\\n')\n\n/**\n * The host instruction of the code mode catalog: its state is the encoded summary, and its render\n * the full catalog (every change renders it whole, see `RunInstruction.render`) or a removal notice.\n */\nexport const codeModeCatalogInstruction = (input: {\n readonly tools: ReadonlyArray<NestedTool>\n readonly staging?: CodeModeStagingDescription\n readonly inlineBudget?: number\n}): RunInstruction => {\n const summary = summarizeCodeModeCatalog(input)\n\n return {\n key: codeModeCatalogInstructionKey,\n state:\n summary.namespaces.length === 0\n ? undefined\n : Option.getOrUndefined(encodeCatalogSummary(summary)),\n render: current => {\n const decoded = current === undefined ? Option.none() : decodeCatalogSummary(current)\n\n return Option.isNone(decoded)\n ? 'Code mode tools are no longer available: do not call previously listed code mode tools.'\n : renderCodeModeCatalog(decoded.value)\n }\n }\n}\n\n/**\n * The code mode description when the catalog is delivered as an instruction: invariant across\n * catalog changes (only staging availability adds the `stage()` line).\n */\nexport const renderCodeModeInstructedDescription = (input: {\n readonly store?: boolean\n readonly staging?: CodeModeStagingDescription\n}): string =>\n [\n intro,\n [\n 'Globals:',\n ...globalLines(input.store === true),\n ...(input.staging === undefined ? [] : [stageLine(input.staging.reviewToolName)])\n ].join('\\n'),\n 'The tools scripts can call are in the \"Code mode catalog\" (namespaces, tool counts and listed tools; the latest one applies). Find the others with `await searchTools(query, { namespace? })` and read one with `await describeTool(name)` before calling it.'\n ].join('\\n\\n')\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"catalog.mjs","names":[],"sources":["../src/catalog.ts"],"sourcesContent":["import { Option, Predicate } from 'effect'\nimport * as Schema from 'effect/Schema'\nimport {\n renderDeclarations,\n renderToolOutputType,\n renderToolSample,\n schemaToType,\n toCodemodeIdentifier\n} from '@earendil-works/pi-codemode/declarations'\nimport { isDeferredTool, toolDiscovery } from '@yolk-sdk/agent/protocol'\nimport type { RunInstruction } from '@yolk-sdk/agent/loop'\nimport type { NestedTool } from '@yolk-sdk/agent/tools'\nimport type { CodeModeJsonSchema } from './executor.ts'\n\n/** How a nested tool reaches scripts: `all` tools are also direct model tools; `listed` and\n * `search` are the two discovery modes of `codemode`-only tools; `stage` marks a stageable tool\n * (approval-gated, ADR 0007): found by search, never callable, only passed to `stage()`.\n */\nexport type CodeModeToolExposure = 'all' | 'listed' | 'search' | 'pinned' | 'stage'\n\n/** One nested tool as scripts see it. */\nexport type CodeModeCatalogTool = {\n /** Raw tool name; scripts may call `tools[\"<name>\"](args)`. */\n readonly name: string\n /** Identifier for `tools.<identifier>(args)` (invalid identifier characters become `_`). */\n readonly identifier: string\n /**\n * How scripts call this tool, used to prefix its rejections: `tools.<identifier>`, or\n * `tools[\"<name>\"]` when an earlier tool already has the identifier (see `codeModeCallLabels`;\n * when the name is taken too, the tool is unreachable and the label only names it).\n */\n readonly callLabel: string\n /** The tool's `ToolModule.id`. */\n readonly namespace: string\n /** The module's `ToolModule.description`, when set. */\n readonly namespaceDescription?: string\n readonly description: string\n readonly inputSchema: CodeModeJsonSchema\n /** The declared output schema, or `{ type: 'string' }` for text results. */\n readonly outputSchema: CodeModeJsonSchema\n /** True when the tool declares an output schema (calls resolve to `structuredContent`). */\n readonly structured: boolean\n readonly exposure: CodeModeToolExposure\n}\n\nconst textOutputSchema: CodeModeJsonSchema = { type: 'string' }\n\n/**\n * The call label of each tool name, in order, as pi binds `tools`: each tool takes\n * `tools[<identifier>]` unless an earlier tool holds that key (first tool wins), then\n * `tools[<name>]` if still free. The label is `tools.<identifier>` for the tool that holds its\n * identifier, otherwise `tools[\"<name>\"]`. The executor guard and the host rejection prefix share\n * it, so both name a call the same way.\n */\nexport const codeModeCallLabels = (names: ReadonlyArray<string>): ReadonlyArray<string> => {\n const bound = new Set<string>()\n\n return names.map(name => {\n const identifier = toCodemodeIdentifier(name)\n const ownsIdentifier = !bound.has(identifier)\n\n bound.add(identifier)\n bound.add(name)\n\n return ownsIdentifier ? `tools.${identifier}` : `tools[${JSON.stringify(name)}]`\n })\n}\n\n/** Catalog of nested tools in resolution order. */\nexport const codeModeCatalog = (\n tools: ReadonlyArray<NestedTool>\n): ReadonlyArray<CodeModeCatalogTool> => {\n const labels = codeModeCallLabels(tools.map(({ def }) => def.name))\n\n return tools.map(({ def, moduleId, moduleDescription }, index) => {\n const tool: CodeModeCatalogTool = {\n name: def.name,\n identifier: toCodemodeIdentifier(def.name),\n callLabel: labels[index] ?? `tools[${JSON.stringify(def.name)}]`,\n namespace: moduleId,\n description: def.description,\n inputSchema: def.parameters,\n outputSchema: def.outputSchema ?? textOutputSchema,\n structured: def.outputSchema !== undefined,\n // A deferred tool's declaration is not in model context until activated: scripts find it\n // by search like a codemode-only `search` tool (ADR 0007).\n exposure: toolDiscovery(def) ?? (isDeferredTool(def) ? 'search' : 'all')\n }\n\n return moduleDescription === undefined\n ? tool\n : { ...tool, namespaceDescription: moduleDescription }\n })\n}\n\n/**\n * Catalog entries of the stageable tools (ADR 0007). Stageable tools are approval-gated, so scripts\n * can only `stage()` them whatever their `callableBy` (stage-only `codemode` ones are also never\n * declared to the model): searchable and describable, never callable (no `tools` binding), so\n * their call label is the `stage()` call that records them.\n */\nexport const codeModeStageOnlyCatalog = (\n stageable: ReadonlyArray<NestedTool>\n): ReadonlyArray<CodeModeCatalogTool> =>\n stageable.map(({ def, moduleId, moduleDescription }) => {\n const tool: CodeModeCatalogTool = {\n name: def.name,\n identifier: toCodemodeIdentifier(def.name),\n callLabel: `stage(${JSON.stringify(def.name)})`,\n namespace: moduleId,\n description: def.description,\n inputSchema: def.parameters,\n outputSchema: def.outputSchema ?? textOutputSchema,\n structured: def.outputSchema !== undefined,\n exposure: 'stage'\n }\n\n return moduleDescription === undefined\n ? tool\n : { ...tool, namespaceDescription: moduleDescription }\n })\n\n/** Default inline budget of the nested tool listing, in estimated tokens. */\nexport const defaultCodeModeInlineBudget = 3000\n\n/** Estimated tokens of a text: four characters per token, rounded up. */\nexport const estimateCodeModeTokens = (text: string): number => Math.ceil(text.length / 4)\n\nconst maxShortTypeChars = 60\n\nconst shortType = (schema: CodeModeJsonSchema): string => {\n const rendered = renderToolOutputType(schema)\n\n if (rendered.length <= maxShortTypeChars) return rendered\n\n if (!Predicate.isBoolean(schema)) {\n if (schema.type === 'array') return 'Array<unknown>'\n\n if (schema.type === 'object') return 'object'\n }\n\n return 'unknown'\n}\n\n// Declarations only read names, descriptions, and schemas; `execute` is never called.\nconst declarationTool = (tool: CodeModeCatalogTool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n outputSchema: tool.outputSchema,\n execute: () => undefined\n})\n\nconst directToolLine = (tool: CodeModeCatalogTool) =>\n `- \\`tools.${tool.identifier}(args)\\` takes the arguments of the \\`${tool.name}\\` tool and resolves to \\`${shortType(tool.outputSchema)}\\`.`\n\nconst declarationMembers = (tools: ReadonlyArray<CodeModeCatalogTool>) =>\n renderDeclarations({ tools: tools.map(declarationTool) })\n\ntype Candidate = {\n readonly tool: CodeModeCatalogTool\n readonly index: number\n readonly cost: number\n}\n\nconst candidateCost = (tool: CodeModeCatalogTool) =>\n estimateCodeModeTokens(declarationMembers([tool]))\n\nconst groupByNamespace = <A extends { readonly tool: CodeModeCatalogTool }>(\n items: ReadonlyArray<A>\n): ReadonlyMap<string, ReadonlyArray<A>> => {\n const groups = new Map<string, Array<A>>()\n\n for (const item of items) {\n const group = groups.get(item.tool.namespace)\n\n if (group === undefined) {\n groups.set(item.tool.namespace, [item])\n } else {\n group.push(item)\n }\n }\n\n return groups\n}\n\nexport type CodeModeListing = {\n /** Tools placed in the description, in catalog order: every `all` tool, and the `listed` tools\n * that fit the budget.\n */\n readonly listed: ReadonlyArray<CodeModeCatalogTool>\n /** Namespaces (catalog order) with callable tools the description does not list. */\n readonly unlistedNamespaces: ReadonlyArray<string>\n}\n\n/**\n * Chooses the tools the description lists. `all` tools are always placed, outside the budget\n * (the model already has their declarations), and so are `pinned` tools. `listed` tools fill\n * `budget` estimated tokens fairly across namespaces: each round, every namespace still in play\n * places its cheapest remaining tool; a namespace whose next tool does not fit drops out. `search`\n * tools are never candidates.\n */\nexport const selectCodeModeListing = (\n catalog: ReadonlyArray<CodeModeCatalogTool>,\n budget: number\n): CodeModeListing => {\n const candidates = catalog.flatMap((tool, index): ReadonlyArray<Candidate> =>\n tool.exposure === 'listed' ? [{ tool, index, cost: candidateCost(tool) }] : []\n )\n\n const queues = new Map(\n [...groupByNamespace(candidates)].map(([namespace, group]) => [\n namespace,\n [...group].sort((left, right) => left.cost - right.cost || left.index - right.index)\n ])\n )\n\n const placed = new Set(\n catalog.flatMap((tool, index) =>\n tool.exposure === 'all' || tool.exposure === 'pinned' ? [index] : []\n )\n )\n\n const inPlay = new Set(queues.keys())\n let remaining = budget\n\n while (inPlay.size > 0) {\n for (const [namespace, queue] of queues) {\n if (!inPlay.has(namespace)) continue\n\n const next = queue.shift()\n\n if (next === undefined || next.cost > remaining) {\n inPlay.delete(namespace)\n continue\n }\n\n placed.add(next.index)\n remaining -= next.cost\n }\n }\n\n const unlisted = new Set(\n catalog.flatMap((tool, index) => (placed.has(index) ? [] : [tool.namespace]))\n )\n\n return {\n listed: catalog.filter((_, index) => placed.has(index)),\n unlistedNamespaces: [...new Set(catalog.map(tool => tool.namespace))].filter(namespace =>\n unlisted.has(namespace)\n )\n }\n}\n\nconst intro = [\n 'Run a JavaScript script that calls tools and returns only what matters.',\n '`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.',\n '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).',\n 'Only the script output and its return value come back to you: filter and aggregate inside the script and return a small JSON value.'\n].join('\\n')\n\nconst stageLine = (reviewToolName: string) =>\n `- \\`await stage(name, args)\\`: record a call of a stageable tool for review instead of running it; resolves to \\`{ staged: true, key, index }\\`. Nothing runs until a person approves the plan through the \\`${reviewToolName}\\` tool, which the result tells you how to call. Once a script stages, it may only run read tools; a script that already ran a write tool cannot stage. \\`searchTools\\` marks approval-gated tools \\`stageOnly: true\\`: they have no \\`tools\\` binding, only \\`stage()\\` them.`\n\n/** Stageable tool names listed in the description; the rest are summarized with a count. */\nconst maxListedStageableTools = 20\n\n/**\n * Stageable tools the description names: `pinned` ones first, never `search` or deferred ones\n * (whose declaration is not in model context; scripts find them by search, ADR 0007).\n */\ntype StageableNames = {\n readonly pinned: ReadonlyArray<string>\n readonly listed: ReadonlyArray<string>\n}\n\nconst listedStageableNames = (staging: CodeModeStagingDescription): StageableNames => ({\n pinned: staging.tools.flatMap(({ def }) => (toolDiscovery(def) === 'pinned' ? [def.name] : [])),\n listed: staging.tools.flatMap(({ def }) => {\n const discovery = toolDiscovery(def)\n\n return discovery === 'search' || discovery === 'pinned' || isDeferredTool(def) ? [] : [def.name]\n })\n})\n\nconst hasStageableNames = (names: StageableNames) =>\n names.pinned.length > 0 || names.listed.length > 0\n\n/** `pinned` names are always shown; the cap applies to the others. */\nconst stageableSection = (names: StageableNames) => {\n const room = Math.max(0, maxListedStageableTools - names.pinned.length)\n const hidden = names.listed.length - room\n\n return [\n '## Stageable tools',\n 'Approval-gated tools a script cannot call through `tools`, only stage with `await stage(\"<name>\", args)` (arguments as for the tool of the same name):',\n ...[...names.pinned, ...names.listed.slice(0, room)].map(name => `- \\`${name}\\``),\n ...(hidden > 0 ? [`- … and ${hidden} more (find them with \\`searchTools\\`).`] : [])\n ].join('\\n')\n}\n\nconst globalLines = (store: boolean) => [\n '- `text(value)` and `console.log(...values)`: append text to the output.',\n '- `image(dataUrl)`: append a base64 image (a `data:` URL or `{ type: \"image\", data, mimeType }`).',\n '- `exit()`: end the script successfully.',\n '- `ALL_TOOLS`: `{ name, description }` of every callable tool.',\n '- `await searchTools(query, { limit?, namespace? })`: find tools by topic; resolves to `Array<{ name: string; description: string }>` (default limit 8).',\n '- `await describeTool(name)`: the description and TypeScript declaration of a tool, or `undefined`.',\n '- `await describeNamespace(name)`: `{ name, description?, tools: Array<{ name, description }> }` for a namespace, or `undefined`.',\n ...(store\n ? [\n '- `store(key, value)` and `load(key)`: keep small JSON values for later scripts; writes are saved only when the script succeeds.'\n ]\n : [])\n]\n\nconst namespaceSection = (namespace: string, tools: ReadonlyArray<CodeModeCatalogTool>) => {\n const declared = tools.filter(tool => tool.exposure !== 'all')\n const direct = tools.filter(tool => tool.exposure === 'all')\n\n const description = tools.find(\n tool => tool.namespaceDescription !== undefined\n )?.namespaceDescription\n\n return [\n `### ${namespace}`,\n ...(description === undefined ? [] : [description]),\n ...(declared.length > 0 ? ['```ts', declarationMembers(declared), '```'] : []),\n ...direct.map(directToolLine)\n ].join('\\n')\n}\n\n// Fixed text: never derived from `search` tools or from which tools did not fit the budget.\nconst unlistedToolsLine =\n 'More tools may be callable than are listed here: find them with `await searchTools(query, { namespace? })` and read one with `await describeTool(name)` or `await describeNamespace(name)` before calling it.'\n\n/** Staged tool plans as the description shows them (`NestedToolStagingDescription`). */\nexport type CodeModeStagingDescription = {\n readonly tools: ReadonlyArray<NestedTool>\n readonly reviewToolName: string\n}\n\nexport type CodeModeDescriptionInput = {\n readonly tools: ReadonlyArray<NestedTool>\n readonly inlineBudget?: number\n /** Mention `store()`/`load()` persistence. */\n readonly store?: boolean\n /** Document `stage()` and list the stageable tools that are neither `search` nor deferred. */\n readonly staging?: CodeModeStagingDescription\n}\n\n/**\n * The code mode tool description: intro, globals one per line, then nested tools grouped by\n * namespace, then one fixed line pointing to `searchTools`/`describeTool`/`describeNamespace`.\n * `all` tools get one line each outside the budget; `listed` tools are declared within the inline\n * budget; `search` tools never contribute, so adding or removing them (even whole namespaces of\n * them) leaves the text byte-identical. With `staging` (and stageable tools), `stage()` is listed\n * with the globals and the stageable tool names follow the nested tools; `search` and deferred\n * stageable tools are never named, so they leave the text byte-identical too once any stageable\n * tool exists.\n */\nexport const renderCodeModeDescription = (input: CodeModeDescriptionInput): string => {\n const catalog = codeModeCatalog(input.tools)\n\n const listing = selectCodeModeListing(catalog, input.inlineBudget ?? defaultCodeModeInlineBudget)\n\n const sections = [...groupByNamespace(listing.listed.map(tool => ({ tool })))].map(\n ([namespace, items]) =>\n namespaceSection(\n namespace,\n items.map(item => item.tool)\n )\n )\n\n const staging =\n input.staging !== undefined && input.staging.tools.length > 0 ? input.staging : undefined\n\n const stageableNames =\n staging === undefined ? { pinned: [], listed: [] } : listedStageableNames(staging)\n\n return [\n intro,\n [\n 'Globals:',\n ...globalLines(input.store === true),\n ...(staging === undefined ? [] : [stageLine(staging.reviewToolName)])\n ].join('\\n'),\n sections.length === 0\n ? 'Nested tools: none are listed here.'\n : ['## Nested tools by namespace', ...sections].join('\\n\\n'),\n ...(hasStageableNames(stageableNames) ? [stageableSection(stageableNames)] : []),\n unlistedToolsLine\n ].join('\\n\\n')\n}\n\n/**\n * `describeTool` text: the description and TypeScript declaration of one tool. A stage-only tool\n * has no `tools` binding, so it is described as the `stage()` call that records it.\n */\nexport const describeCodeModeTool = (tool: CodeModeCatalogTool): string =>\n tool.exposure === 'stage'\n ? [\n tool.description,\n `Stage-only (approval-gated): record a call with \\`await stage(${JSON.stringify(tool.name)}, args)\\`; it runs only after a person approves the plan.`,\n `args: ${schemaToType(tool.inputSchema)}`\n ].join('\\n\\n')\n : renderToolSample(declarationTool(tool))\n\n/**\n * Finds a tool by identifier or raw name. A stageable tool's exact raw name wins first: it has no\n * binding, so a callable tool sharing its identifier (`archive-resource` vs `archive_resource`)\n * must not answer for it; callable lookups keep identifier precedence, as their bindings do.\n */\nexport const findCodeModeTool = (\n catalog: ReadonlyArray<CodeModeCatalogTool>,\n name: string\n): CodeModeCatalogTool | undefined =>\n catalog.find(tool => tool.exposure === 'stage' && tool.name === name) ??\n catalog.find(tool => tool.identifier === name) ??\n catalog.find(tool => tool.name === name)\n\n/** The instruction key of the code mode catalog (`catalog: 'instructions'`, ADR 0007). */\nexport const codeModeCatalogInstructionKey = 'yolk.codemode.catalog'\n\nconst CodeModeCatalogNamespace = Schema.Struct({\n name: Schema.String,\n description: Schema.optional(Schema.String),\n /** Every tool scripts reach in the namespace: callable and stage-only. */\n count: Schema.Number,\n /** Tools the listing shows. */\n shown: Schema.Number,\n /** The rendered declarations and direct tool lines of the shown tools. */\n listing: Schema.String\n})\n\n/** The catalog an instruction message records as its state (JSON, never model-visible). */\nexport const CodeModeCatalogSummary = Schema.Struct({\n namespaces: Schema.Array(CodeModeCatalogNamespace),\n /** Stageable tool names the catalog lists: `pinned` ones, then the others (never `search` or\n * deferred ones). */\n stageable: Schema.Struct({\n pinned: Schema.Array(Schema.String),\n listed: Schema.Array(Schema.String)\n })\n})\n\nexport type CodeModeCatalogSummary = typeof CodeModeCatalogSummary.Type\n\nconst decodeCatalogSummary = Schema.decodeUnknownOption(CodeModeCatalogSummary)\n\nconst encodeCatalogSummary = Schema.encodeOption(CodeModeCatalogSummary)\n\nconst namespaceListing = (tools: ReadonlyArray<CodeModeCatalogTool>) => {\n const declared = tools.filter(tool => tool.exposure !== 'all')\n const direct = tools.filter(tool => tool.exposure === 'all')\n\n return [\n ...(declared.length > 0 ? ['```ts', declarationMembers(declared), '```'] : []),\n ...direct.map(directToolLine)\n ].join('\\n')\n}\n\n/**\n * The catalog of one resolution: every namespace with its tool count and description, and the\n * listing of the tools the inline budget (or `pinned`) places. `search` and stage-only tools are\n * counted, never listed.\n */\nexport const summarizeCodeModeCatalog = (input: {\n readonly tools: ReadonlyArray<NestedTool>\n readonly staging?: CodeModeStagingDescription\n readonly inlineBudget?: number\n}): CodeModeCatalogSummary => {\n const catalog = codeModeCatalog(input.tools)\n const stageOnly = input.staging === undefined ? [] : codeModeStageOnlyCatalog(input.staging.tools)\n const listing = selectCodeModeListing(catalog, input.inlineBudget ?? defaultCodeModeInlineBudget)\n const listedByNamespace = groupByNamespace(listing.listed.map(tool => ({ tool })))\n\n const namespaces = [...groupByNamespace([...catalog, ...stageOnly].map(tool => ({ tool })))].map(\n ([name, items]) => {\n const shown = (listedByNamespace.get(name) ?? []).map(item => item.tool)\n\n const description = items.find(item => item.tool.namespaceDescription !== undefined)?.tool\n .namespaceDescription\n\n const namespace = {\n name,\n count: items.length,\n shown: shown.length,\n listing: namespaceListing(shown)\n }\n\n return description === undefined ? namespace : { ...namespace, description }\n }\n )\n\n return {\n namespaces,\n stageable:\n input.staging === undefined ? { pinned: [], listed: [] } : listedStageableNames(input.staging)\n }\n}\n\nconst namespaceLine = (namespace: CodeModeCatalogSummary['namespaces'][number]) => {\n const count = namespace.count === 1 ? '1 tool' : `${namespace.count} tools`\n\n const label =\n namespace.shown === namespace.count\n ? count\n : namespace.shown === 0\n ? `${count}, none listed`\n : `${count}, ${namespace.shown} listed`\n\n return `- \\`${namespace.name}\\` (${label})${namespace.description === undefined ? '' : `: ${namespace.description}`}`\n}\n\n/** The full catalog text of an instruction message. */\nexport const renderCodeModeCatalog = (summary: CodeModeCatalogSummary): string =>\n [\n '# Code mode catalog',\n 'Tools `codemode` scripts can call, by namespace; the latest catalog in the conversation replaces any earlier one. Call a listed tool as `await tools.<id>(args)`; find the others with `await searchTools(query, { namespace })` and read one with `await describeTool(name)` before calling it.',\n ['## Namespaces', ...summary.namespaces.map(namespaceLine)].join('\\n'),\n ...summary.namespaces.flatMap(namespace =>\n namespace.listing.length === 0 ? [] : [`### ${namespace.name}\\n${namespace.listing}`]\n ),\n ...(hasStageableNames(summary.stageable) ? [stageableSection(summary.stageable)] : [])\n ].join('\\n\\n')\n\n/**\n * The host instruction of the code mode catalog: its state is the encoded summary, and its render\n * the full catalog (every change renders it whole, see `RunInstruction.render`) or a removal notice.\n */\nexport const codeModeCatalogInstruction = (input: {\n readonly tools: ReadonlyArray<NestedTool>\n readonly staging?: CodeModeStagingDescription\n readonly inlineBudget?: number\n}): RunInstruction => {\n const summary = summarizeCodeModeCatalog(input)\n\n return {\n key: codeModeCatalogInstructionKey,\n state:\n summary.namespaces.length === 0\n ? undefined\n : Option.getOrUndefined(encodeCatalogSummary(summary)),\n render: current => {\n const decoded = current === undefined ? Option.none() : decodeCatalogSummary(current)\n\n return Option.isNone(decoded)\n ? 'Code mode tools are no longer available: do not call previously listed code mode tools.'\n : renderCodeModeCatalog(decoded.value)\n }\n }\n}\n\n/**\n * The code mode description when the catalog is delivered as an instruction: invariant across\n * catalog changes (only staging availability adds the `stage()` line).\n */\nexport const renderCodeModeInstructedDescription = (input: {\n readonly store?: boolean\n readonly staging?: CodeModeStagingDescription\n}): string =>\n [\n intro,\n [\n 'Globals:',\n ...globalLines(input.store === true),\n ...(input.staging === undefined ? [] : [stageLine(input.staging.reviewToolName)])\n ].join('\\n'),\n 'The tools scripts can call are in the \"Code mode catalog\" (namespaces, tool counts and listed tools; the latest one applies). Find the others with `await searchTools(query, { namespace? })` and read one with `await describeTool(name)` before calling it.'\n ].join('\\n\\n')\n"],"mappings":"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"}
|
package/dist/tool.mjs
CHANGED
|
@@ -73,7 +73,7 @@ const SearchOptions = Schema.Struct({
|
|
|
73
73
|
});
|
|
74
74
|
const decodeSearchOptions = Schema.decodeUnknownOption(SearchOptions);
|
|
75
75
|
/** `searchTools`, `describeTool`, and `describeNamespace` over every nested tool and, while the
|
|
76
|
-
* script may stage, every
|
|
76
|
+
* script may stage, every stageable tool. */
|
|
77
77
|
const discoveryGlobals = (catalog) => [
|
|
78
78
|
{
|
|
79
79
|
name: "searchTools",
|
|
@@ -141,7 +141,7 @@ const stageGlobal = (plan, fork, stageable) => ({
|
|
|
141
141
|
});
|
|
142
142
|
}
|
|
143
143
|
});
|
|
144
|
-
/** A direct call of a
|
|
144
|
+
/** A direct call of a stageable tool rejects with a hint to stage it (ADR 0007). */
|
|
145
145
|
const stageOnlyRejections = (stageOnly) => stageOnly.flatMap((tool) => {
|
|
146
146
|
const message = `${tool.name} is approval-gated: record it with stage(${JSON.stringify(tool.name)}, args) instead of calling it.`;
|
|
147
147
|
return tool.identifier === tool.name ? [{
|
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 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.\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 return tool.structured && result.structuredContent !== undefined\n ? { ok: true, value: result.structuredContent }\n : { ok: true, value: text }\n}\n\ntype CallOutcome = {\n status: NestedToolCallStatus\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 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 stage-only 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 stage-only 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 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 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 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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"}
|
|
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 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.\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 return tool.structured && result.structuredContent !== undefined\n ? { ok: true, value: result.structuredContent }\n : { ok: true, value: text }\n}\n\ntype CallOutcome = {\n status: NestedToolCallStatus\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 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 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 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 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":";;;;;;;;;;;AAkFA,MAAa,mBAAmB;AAuBhC,MAAa,wBAAwB;CACnC,WAAW;CACX,kBAAkB,KAAK,OAAO;CAC9B,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,EAE/E,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,EACnB,QAAO,SAAQ,KAAK,SAAS,CAAC,EAC9B,KAAK,IAAI;;;;;;AAWlB,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,OAAO,KAAK,cAAc,OAAO,sBAAsB,KAAA,IACnD;EAAE,IAAI;EAAM,OAAO,OAAO;CAAkB,IAC5C;EAAE,IAAI;EAAM,OAAO;CAAK;AAC9B;AAgBA,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,GAAG;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,GAAG,IAAI,QACpD,UAAU,MAAM,EAAE,UAAU,qBAAqB,IAAI,IAAI,MAAM,IAAI,GAAG,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,EAAE,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,EAAE,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,EAAE,KACxB,OAAO,SAAQ,UACb,MAAM,MAAM,KAAK,EAAE,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,EAAE,KAAK,MAAM,QAAQ,KAAK,CAAC;EAC3E,MAAM,UAAU,OAAO,SAAS,QAAQ,MAAM,EAAS;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,EAAE,KAChF,MAAM,QAAQ,KAAK,CACrB;EAEA,MAAM,YAAY,OAAO,SAAS,QAAQ,WAAW,EAAS;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,EAAE,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,EAAE,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,EAAE,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,EAAE,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,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,EAAE,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,EAAE,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,QAAQ;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,YAAiC;GAC7D,IAAI,OAAO;GACX,MAAM,OAAO;GACb,MAAM,OAAO;GAEb,GAAI,OAAO,WAAW,EAAE,QAAQ,YAAY;EAC9C,EAAE;EAOF,MAAM,EAAE,aAAa,UAAU,2BALd,SAAS,OACxB,sBACA,2BAA2B,EAAE,UAAU,OAAO,eAAe,CAAC,CAGC,CAAC;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;EAEP,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,EAAE,KAAK,IAAI;CAEnB,MAAM,OAAO;EACX,oDAAoD,KAAK,KAAK,SAAS,KAAK,GAAG;EAC/E;EACA;CACF,EAAE,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"}
|
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.109",
|
|
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.0.0",
|
|
55
|
-
"@yolk-sdk/agent": "^0.1.0-canary.
|
|
55
|
+
"@yolk-sdk/agent": "^0.1.0-canary.109"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"build": "tsdown",
|
package/src/catalog.ts
CHANGED
|
@@ -13,8 +13,8 @@ import type { NestedTool } from '@yolk-sdk/agent/tools'
|
|
|
13
13
|
import type { CodeModeJsonSchema } from './executor.ts'
|
|
14
14
|
|
|
15
15
|
/** How a nested tool reaches scripts: `all` tools are also direct model tools; `listed` and
|
|
16
|
-
* `search` are the two discovery modes of `codemode`-only tools; `stage` marks a
|
|
17
|
-
* (ADR 0007): found by search, never callable, only passed to `stage()`.
|
|
16
|
+
* `search` are the two discovery modes of `codemode`-only tools; `stage` marks a stageable tool
|
|
17
|
+
* (approval-gated, ADR 0007): found by search, never callable, only passed to `stage()`.
|
|
18
18
|
*/
|
|
19
19
|
export type CodeModeToolExposure = 'all' | 'listed' | 'search' | 'pinned' | 'stage'
|
|
20
20
|
|
|
@@ -94,16 +94,15 @@ export const codeModeCatalog = (
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
/**
|
|
97
|
-
* Catalog entries of the
|
|
98
|
-
*
|
|
99
|
-
*
|
|
97
|
+
* Catalog entries of the stageable tools (ADR 0007). Stageable tools are approval-gated, so scripts
|
|
98
|
+
* can only `stage()` them whatever their `callableBy` (stage-only `codemode` ones are also never
|
|
99
|
+
* declared to the model): searchable and describable, never callable (no `tools` binding), so
|
|
100
|
+
* their call label is the `stage()` call that records them.
|
|
100
101
|
*/
|
|
101
102
|
export const codeModeStageOnlyCatalog = (
|
|
102
103
|
stageable: ReadonlyArray<NestedTool>
|
|
103
104
|
): ReadonlyArray<CodeModeCatalogTool> =>
|
|
104
|
-
stageable.
|
|
105
|
-
if (def.callableBy !== 'codemode') return []
|
|
106
|
-
|
|
105
|
+
stageable.map(({ def, moduleId, moduleDescription }) => {
|
|
107
106
|
const tool: CodeModeCatalogTool = {
|
|
108
107
|
name: def.name,
|
|
109
108
|
identifier: toCodemodeIdentifier(def.name),
|
|
@@ -116,9 +115,9 @@ export const codeModeStageOnlyCatalog = (
|
|
|
116
115
|
exposure: 'stage'
|
|
117
116
|
}
|
|
118
117
|
|
|
119
|
-
return
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
return moduleDescription === undefined
|
|
119
|
+
? tool
|
|
120
|
+
: { ...tool, namespaceDescription: moduleDescription }
|
|
122
121
|
})
|
|
123
122
|
|
|
124
123
|
/** Default inline budget of the nested tool listing, in estimated tokens. */
|
|
@@ -266,7 +265,10 @@ const stageLine = (reviewToolName: string) =>
|
|
|
266
265
|
/** Stageable tool names listed in the description; the rest are summarized with a count. */
|
|
267
266
|
const maxListedStageableTools = 20
|
|
268
267
|
|
|
269
|
-
/**
|
|
268
|
+
/**
|
|
269
|
+
* Stageable tools the description names: `pinned` ones first, never `search` or deferred ones
|
|
270
|
+
* (whose declaration is not in model context; scripts find them by search, ADR 0007).
|
|
271
|
+
*/
|
|
270
272
|
type StageableNames = {
|
|
271
273
|
readonly pinned: ReadonlyArray<string>
|
|
272
274
|
readonly listed: ReadonlyArray<string>
|
|
@@ -277,7 +279,7 @@ const listedStageableNames = (staging: CodeModeStagingDescription): StageableNam
|
|
|
277
279
|
listed: staging.tools.flatMap(({ def }) => {
|
|
278
280
|
const discovery = toolDiscovery(def)
|
|
279
281
|
|
|
280
|
-
return discovery === 'search' || discovery === 'pinned' ? [] : [def.name]
|
|
282
|
+
return discovery === 'search' || discovery === 'pinned' || isDeferredTool(def) ? [] : [def.name]
|
|
281
283
|
})
|
|
282
284
|
})
|
|
283
285
|
|
|
@@ -343,7 +345,7 @@ export type CodeModeDescriptionInput = {
|
|
|
343
345
|
readonly inlineBudget?: number
|
|
344
346
|
/** Mention `store()`/`load()` persistence. */
|
|
345
347
|
readonly store?: boolean
|
|
346
|
-
/** Document `stage()` and list the stageable tools that are
|
|
348
|
+
/** Document `stage()` and list the stageable tools that are neither `search` nor deferred. */
|
|
347
349
|
readonly staging?: CodeModeStagingDescription
|
|
348
350
|
}
|
|
349
351
|
|
|
@@ -353,8 +355,9 @@ export type CodeModeDescriptionInput = {
|
|
|
353
355
|
* `all` tools get one line each outside the budget; `listed` tools are declared within the inline
|
|
354
356
|
* budget; `search` tools never contribute, so adding or removing them (even whole namespaces of
|
|
355
357
|
* them) leaves the text byte-identical. With `staging` (and stageable tools), `stage()` is listed
|
|
356
|
-
* with the globals and the stageable tool names follow the nested tools;
|
|
357
|
-
* are never named, so they leave the text byte-identical too once any stageable
|
|
358
|
+
* with the globals and the stageable tool names follow the nested tools; `search` and deferred
|
|
359
|
+
* stageable tools are never named, so they leave the text byte-identical too once any stageable
|
|
360
|
+
* tool exists.
|
|
358
361
|
*/
|
|
359
362
|
export const renderCodeModeDescription = (input: CodeModeDescriptionInput): string => {
|
|
360
363
|
const catalog = codeModeCatalog(input.tools)
|
|
@@ -403,12 +406,18 @@ export const describeCodeModeTool = (tool: CodeModeCatalogTool): string =>
|
|
|
403
406
|
].join('\n\n')
|
|
404
407
|
: renderToolSample(declarationTool(tool))
|
|
405
408
|
|
|
406
|
-
/**
|
|
409
|
+
/**
|
|
410
|
+
* Finds a tool by identifier or raw name. A stageable tool's exact raw name wins first: it has no
|
|
411
|
+
* binding, so a callable tool sharing its identifier (`archive-resource` vs `archive_resource`)
|
|
412
|
+
* must not answer for it; callable lookups keep identifier precedence, as their bindings do.
|
|
413
|
+
*/
|
|
407
414
|
export const findCodeModeTool = (
|
|
408
415
|
catalog: ReadonlyArray<CodeModeCatalogTool>,
|
|
409
416
|
name: string
|
|
410
417
|
): CodeModeCatalogTool | undefined =>
|
|
411
|
-
catalog.find(tool => tool.
|
|
418
|
+
catalog.find(tool => tool.exposure === 'stage' && tool.name === name) ??
|
|
419
|
+
catalog.find(tool => tool.identifier === name) ??
|
|
420
|
+
catalog.find(tool => tool.name === name)
|
|
412
421
|
|
|
413
422
|
/** The instruction key of the code mode catalog (`catalog: 'instructions'`, ADR 0007). */
|
|
414
423
|
export const codeModeCatalogInstructionKey = 'yolk.codemode.catalog'
|
|
@@ -427,7 +436,8 @@ const CodeModeCatalogNamespace = Schema.Struct({
|
|
|
427
436
|
/** The catalog an instruction message records as its state (JSON, never model-visible). */
|
|
428
437
|
export const CodeModeCatalogSummary = Schema.Struct({
|
|
429
438
|
namespaces: Schema.Array(CodeModeCatalogNamespace),
|
|
430
|
-
/** Stageable tool names the catalog lists: `pinned` ones, then
|
|
439
|
+
/** Stageable tool names the catalog lists: `pinned` ones, then the others (never `search` or
|
|
440
|
+
* deferred ones). */
|
|
431
441
|
stageable: Schema.Struct({
|
|
432
442
|
pinned: Schema.Array(Schema.String),
|
|
433
443
|
listed: Schema.Array(Schema.String)
|
package/src/tool.ts
CHANGED
|
@@ -298,7 +298,7 @@ const SearchOptions = Schema.Struct({
|
|
|
298
298
|
const decodeSearchOptions = Schema.decodeUnknownOption(SearchOptions)
|
|
299
299
|
|
|
300
300
|
/** `searchTools`, `describeTool`, and `describeNamespace` over every nested tool and, while the
|
|
301
|
-
* script may stage, every
|
|
301
|
+
* script may stage, every stageable tool. */
|
|
302
302
|
const discoveryGlobals = (
|
|
303
303
|
catalog: ReadonlyArray<CodeModeCatalogTool>
|
|
304
304
|
): ReadonlyArray<CodeModeExecutorGlobal> => [
|
|
@@ -410,7 +410,7 @@ const stageGlobal = (
|
|
|
410
410
|
}
|
|
411
411
|
})
|
|
412
412
|
|
|
413
|
-
/** A direct call of a
|
|
413
|
+
/** A direct call of a stageable tool rejects with a hint to stage it (ADR 0007). */
|
|
414
414
|
const stageOnlyRejections = (stageOnly: ReadonlyArray<CodeModeCatalogTool>) =>
|
|
415
415
|
stageOnly.flatMap(tool => {
|
|
416
416
|
const message = `${tool.name} is approval-gated: record it with stage(${JSON.stringify(tool.name)}, args) instead of calling it.`
|