@yolk-sdk/codemode 0.1.0-canary.108 → 0.1.0-canary.110

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 CHANGED
@@ -82,8 +82,10 @@ const program = Effect.gen(function* () {
82
82
  always declared, outside the budget, and deferred (`loading: 'deferred'`) `all` tools count as
83
83
  `search` tools. One fixed line tells scripts to
84
84
  find unlisted tools with `searchTools(query, { limit?, namespace? })` (BM25 over names,
85
- descriptions, namespaces, and module descriptions), `describeTool(name)`, and
86
- `describeNamespace(name)`.
85
+ descriptions, namespaces, and module descriptions) and call them in the next script: each hit
86
+ has a one-line `signature` with the argument and result types (`codeModeToolSignature`; past
87
+ 800 characters it is cut with a `describeTool` pointer). `describeTool(name)` gives the full documented declaration and
88
+ `describeNamespace(name)` a namespace's tools.
87
89
  - Results start with `Script completed` or `Script failed`, include the wall time, output, and the
88
90
  JSON return value, and are cut head and tail at `maxOutputChars`. Images beyond `maxImages` or
89
91
  `maxImageBytes` are dropped with a note. Failed scripts keep partial output and list the tool
@@ -144,8 +146,9 @@ to lower the cap.
144
146
 
145
147
  A stageable tool may be **stage-only** (`callableBy: 'codemode'`, usually with `discovery: 'search'`):
146
148
  it is never declared to the model, scripts find it with `searchTools()` (hits marked
147
- `stageOnly: true`) and read it with `describeTool()`, and the only thing they can do with it is
148
- `stage()` it. See [ADR 0007](https://github.com/magoz/yolk-sdk/blob/main/docs/adr/0007-tool-exposure-and-catalog.md).
149
+ `stageOnly: true`, with the `stage("<name>", args)` signature), and the only thing they can do with it is
150
+ `stage()` it. Model-callable stageable tools (`all`, deferred or not) are found the same way. See
151
+ [ADR 0007](https://github.com/magoz/yolk-sdk/blob/main/docs/adr/0007-tool-exposure-and-catalog.md).
149
152
 
150
153
  Applied plan calls run inside the review action: they bypass `beforeNestedCall` and `ToolExecutor`
151
154
  decorators. Wire the same per-call check as `makePlanReviewTool({ beforeCall })`. Review screens
@@ -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 stage-only tool
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 stage-only tools among the stageable ones (`callableBy: 'codemode'`,
42
- * ADR 0007): searchable and describable, never callable (no `tools` binding), so their call label
43
- * is the `stage()` call that records them.
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,25 +71,38 @@ 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 not stage-only `search` tools. */
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
  /**
77
78
  * The code mode tool description: intro, globals one per line, then nested tools grouped by
78
- * namespace, then one fixed line pointing to `searchTools`/`describeTool`/`describeNamespace`.
79
+ * namespace, then one fixed line pointing to `searchTools` and `describeNamespace`.
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; stage-only `search` tools
83
- * are never named, so they leave the text byte-identical too once any stageable tool exists.
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;
88
+ /** Longest `searchTools` signature, cut marker included (`describeTool` has the whole declaration). */
89
+ declare const maxCodeModeSearchSignatureChars = 800;
90
+ /**
91
+ * The call a `searchTools` hit shows, enough to call the tool without `describeTool`:
92
+ * `tools.<id>(args): Promise<result>`, or `stage("<name>", args)` for a stageable tool. Bounded:
93
+ * a long one ends with a pointer to `describeTool`.
94
+ */
95
+ declare const codeModeToolSignature: (tool: CodeModeCatalogTool) => string;
86
96
  /**
87
97
  * `describeTool` text: the description and TypeScript declaration of one tool. A stage-only tool
88
98
  * has no `tools` binding, so it is described as the `stage()` call that records it.
89
99
  */
90
100
  declare const describeCodeModeTool: (tool: CodeModeCatalogTool) => string;
91
- /** Finds a tool by identifier or raw name. */
101
+ /**
102
+ * Finds a tool by identifier or raw name. A stageable tool's exact raw name wins first: it has no
103
+ * binding, so a callable tool sharing its identifier (`archive-resource` vs `archive_resource`)
104
+ * must not answer for it; callable lookups keep identifier precedence, as their bindings do.
105
+ */
92
106
  declare const findCodeModeTool: (catalog: ReadonlyArray<CodeModeCatalogTool>, name: string) => CodeModeCatalogTool | undefined;
93
107
  /** The instruction key of the code mode catalog (`catalog: 'instructions'`, ADR 0007). */
94
108
  declare const codeModeCatalogInstructionKey = "yolk.codemode.catalog";
@@ -100,7 +114,9 @@ declare const CodeModeCatalogSummary: Schema.Struct<{
100
114
  readonly count: Schema.Number; /** Tools the listing shows. */
101
115
  readonly shown: Schema.Number; /** The rendered declarations and direct tool lines of the shown tools. */
102
116
  readonly listing: Schema.String;
103
- }>>; /** Stageable tool names the catalog lists: `pinned` ones, then `listed` ones (never `search`). */
117
+ }>>;
118
+ /** Stageable tool names the catalog lists: `pinned` ones, then the others (never `search` or
119
+ * deferred ones). */
104
120
  readonly stageable: Schema.Struct<{
105
121
  readonly pinned: Schema.$Array<Schema.String>;
106
122
  readonly listed: Schema.$Array<Schema.String>;
@@ -137,5 +153,5 @@ declare const renderCodeModeInstructedDescription: (input: {
137
153
  readonly staging?: CodeModeStagingDescription;
138
154
  }) => string;
139
155
  //#endregion
140
- export { CodeModeCatalogSummary, CodeModeCatalogTool, CodeModeDescriptionInput, CodeModeListing, CodeModeStagingDescription, CodeModeToolExposure, codeModeCallLabels, codeModeCatalog, codeModeCatalogInstruction, codeModeCatalogInstructionKey, codeModeStageOnlyCatalog, defaultCodeModeInlineBudget, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, renderCodeModeCatalog, renderCodeModeDescription, renderCodeModeInstructedDescription, selectCodeModeListing, summarizeCodeModeCatalog };
156
+ export { CodeModeCatalogSummary, CodeModeCatalogTool, CodeModeDescriptionInput, CodeModeListing, CodeModeStagingDescription, CodeModeToolExposure, codeModeCallLabels, codeModeCatalog, codeModeCatalogInstruction, codeModeCatalogInstructionKey, codeModeStageOnlyCatalog, codeModeToolSignature, defaultCodeModeInlineBudget, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, maxCodeModeSearchSignatureChars, renderCodeModeCatalog, renderCodeModeDescription, renderCodeModeInstructedDescription, selectCodeModeListing, summarizeCodeModeCatalog };
141
157
  //# sourceMappingURL=catalog.d.mts.map
@@ -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;;;;;AAAA,cA+Ba,wBAAA,GACX,SAAA,EAAW,aAAA,CAAc,UAAA,MACxB,aAAA,CAAc,mBAAA;;cAsBJ,2BAAA;;cAGA,sBAAA,GAA0B,IAAY;AAAA,KA4DvC,eAAA;EArHV;;;EAAA,SAyHS,MAAA,EAAQ,aAAA,CAAc,mBAAA,GAxHG;EAAA,SA0HzB,kBAAA,EAAoB,aAAA;AAAA;;;;;;;;cAUlB,qBAAA,GACX,OAAA,EAAS,aAAA,CAAc,mBAAA,GACvB,MAAA,aACC,eAAA;;KAiIS,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;WAEA,KAAA,YA5N6B;EAAA,SA8N7B,OAAA,GAAU,0BAAA;AAAA;;;AA3N8B;AA4DnD;;;;;;cA2Ka,yBAAA,GAA6B,KAA+B,EAAxB,wBAAwB;;;;;cAsC5D,oBAAA,GAAwB,IAAyB,EAAnB,mBAAmB;;cAUjD,gBAAA,GACX,OAAA,EAAS,aAAA,CAAc,mBAAA,GACvB,IAAA,aACC,mBAAA;AAxNyC;AAAA,cA4N/B,6BAAA;;cAcA,sBAAA,EAAsB,MAAA,CAAA,MAAA;EAAA;;0DA9KlC;IAAA,+BAjDU;IAAA,+BAAT;IAAA;OAiDD;EAAA;;;;;KAuLW,sBAAA,UAAgC,sBAAA,CAAuB,IAAI;;;;;AAnG9C;cAwHZ,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;;;;;cAexD,0BAAA,GAA8B,KAAA;EAAA,SAChC,KAAA,EAAO,aAAA,CAAc,UAAA;EAAA,SACrB,OAAA,GAAU,0BAAA;EAAA,SACV,YAAA;AAAA,MACP,cAAA;AAnL2C;AAY/C;;;AAZ+C,cA0MlC,mCAAA,GAAuC,KAAA;EAAA,SACzC,KAAA;EAAA,SACA,OAAA,GAAU,0BAA0B;AAAA"}
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;;cAmC5D,+BAAA;;;;AA5M+B;AAU5C;cAoOa,qBAAA,GAAyB,IAAyB,EAAnB,mBAAmB;;;;;cAalD,oBAAA,GAAwB,IAAyB,EAAnB,mBAAmB;;;;;;cAcjD,gBAAA,GACX,OAAA,EAAS,aAAA,CAAc,mBAAA,GACvB,IAAA,aACC,mBAAA;;cAMU,6BAAA;AAjIb;AAAA,cA+Ia,sBAAA,EAAsB,MAAA,CAAA,MAAA;EAAA;;0DA9IjB;IAAA,+BACP;IAAA,+BAAc;IAAA;;;;;;;;;KAuJb,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;AApKrE;;;;AAAA,cAmLa,0BAAA,GAA8B,KAAA;EAAA,SAChC,KAAA,EAAO,aAAA,CAAc,UAAA;EAAA,SACrB,OAAA,GAAU,0BAAA;EAAA,SACV,YAAA;AAAA,MACP,cAAA;AArJ2D;AAa/D;;;AAb+D,cA4KlD,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 stage-only tools among the stageable ones (`callableBy: 'codemode'`,
47
- * ADR 0007): searchable and describable, never callable (no `tools` binding), so their call label
48
- * is the `stage()` call that records them.
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.flatMap(({ def, moduleId, moduleDescription }) => {
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 [moduleDescription === void 0 ? tool : {
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;
@@ -164,10 +164,10 @@ const globalLines = (store) => [
164
164
  "- `image(dataUrl)`: append a base64 image (a `data:` URL or `{ type: \"image\", data, mimeType }`).",
165
165
  "- `exit()`: end the script successfully.",
166
166
  "- `ALL_TOOLS`: `{ name, description }` of every callable tool.",
167
- "- `await searchTools(query, { limit?, namespace? })`: find tools by topic; resolves to `Array<{ name: string; description: string }>` (default limit 8).",
168
- "- `await describeTool(name)`: the description and TypeScript declaration of a tool, or `undefined`.",
167
+ "- `await searchTools(query, { limit?, namespace? })`: find tools by topic; resolves to `Array<{ name: string; description: string; signature: string }>` (default limit 8). `signature` is the call with its argument and result types: enough to call the tool in your next script.",
168
+ "- `await describeTool(name)`: the full description and documented TypeScript declaration of a tool, or `undefined`; needed only when a signature is cut or unclear.",
169
169
  "- `await describeNamespace(name)`: `{ name, description?, tools: Array<{ name, description }> }` for a namespace, or `undefined`.",
170
- ...store ? ["- `store(key, value)` and `load(key)`: keep small JSON values for later scripts; writes are saved only when the script succeeds."] : []
170
+ ...store ? ["- `store(key, value)` and `load(key)`: keep JSON values (up to 256 KiB each) for later scripts; writes are saved only when the script succeeds. When fetched data is large, store it and return a summary, then filter it with `load()` in a later script instead of calling the tools again."] : []
171
171
  ];
172
172
  const namespaceSection = (namespace, tools) => {
173
173
  const declared = tools.filter((tool) => tool.exposure !== "all");
@@ -184,15 +184,16 @@ const namespaceSection = (namespace, tools) => {
184
184
  ...direct.map(directToolLine)
185
185
  ].join("\n");
186
186
  };
187
- const unlistedToolsLine = "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.";
187
+ const unlistedToolsLine = "More tools may be callable than are listed here: find them with `await searchTools(query, { namespace? })` (each hit has its call signature) or `await describeNamespace(name)`, then call them in your next script.";
188
188
  /**
189
189
  * The code mode tool description: intro, globals one per line, then nested tools grouped by
190
- * namespace, then one fixed line pointing to `searchTools`/`describeTool`/`describeNamespace`.
190
+ * namespace, then one fixed line pointing to `searchTools` and `describeNamespace`.
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; stage-only `search` tools
195
- * are never named, so they leave the text byte-identical too once any stageable tool exists.
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)));
@@ -213,6 +214,28 @@ const renderCodeModeDescription = (input) => {
213
214
  unlistedToolsLine
214
215
  ].join("\n\n");
215
216
  };
217
+ /** Longest `searchTools` signature, cut marker included (`describeTool` has the whole declaration). */
218
+ const maxCodeModeSearchSignatureChars = 800;
219
+ const signatureCutMarker = "… (describeTool for the full declaration)";
220
+ const compactText = (rendered) => rendered.split("\n").map((line) => line.trim()).filter((line) => !line.startsWith("//")).join(" ");
221
+ const compactResultType = (schema) => {
222
+ const rendered = compactText(renderToolOutputType(schema));
223
+ return rendered.length <= maxShortTypeChars ? rendered : shortType(schema);
224
+ };
225
+ const cutSignature = (signature) => {
226
+ const kept = signature.slice(0, 759);
227
+ const last = kept.charCodeAt(kept.length - 1);
228
+ return `${last >= 55296 && last <= 56319 ? kept.slice(0, -1) : kept}${signatureCutMarker}`;
229
+ };
230
+ /**
231
+ * The call a `searchTools` hit shows, enough to call the tool without `describeTool`:
232
+ * `tools.<id>(args): Promise<result>`, or `stage("<name>", args)` for a stageable tool. Bounded:
233
+ * a long one ends with a pointer to `describeTool`.
234
+ */
235
+ const codeModeToolSignature = (tool) => {
236
+ const signature = tool.exposure === "stage" ? `stage(${JSON.stringify(tool.name)}, ${compactText(schemaToType(tool.inputSchema))})` : `${tool.callLabel}(${compactText(schemaToType(tool.inputSchema))}): Promise<${compactResultType(tool.outputSchema)}>`;
237
+ return signature.length <= 800 ? signature : cutSignature(signature);
238
+ };
216
239
  /**
217
240
  * `describeTool` text: the description and TypeScript declaration of one tool. A stage-only tool
218
241
  * has no `tools` binding, so it is described as the `stage()` call that records it.
@@ -222,8 +245,12 @@ const describeCodeModeTool = (tool) => tool.exposure === "stage" ? [
222
245
  `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
246
  `args: ${schemaToType(tool.inputSchema)}`
224
247
  ].join("\n\n") : renderToolSample(declarationTool(tool));
225
- /** Finds a tool by identifier or raw name. */
226
- const findCodeModeTool = (catalog, name) => catalog.find((tool) => tool.identifier === name) ?? catalog.find((tool) => tool.name === name);
248
+ /**
249
+ * Finds a tool by identifier or raw name. A stageable tool's exact raw name wins first: it has no
250
+ * binding, so a callable tool sharing its identifier (`archive-resource` vs `archive_resource`)
251
+ * must not answer for it; callable lookups keep identifier precedence, as their bindings do.
252
+ */
253
+ 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
254
  /** The instruction key of the code mode catalog (`catalog: 'instructions'`, ADR 0007). */
228
255
  const codeModeCatalogInstructionKey = "yolk.codemode.catalog";
229
256
  const CodeModeCatalogNamespace = Schema.Struct({
@@ -239,7 +266,8 @@ const CodeModeCatalogNamespace = Schema.Struct({
239
266
  /** The catalog an instruction message records as its state (JSON, never model-visible). */
240
267
  const CodeModeCatalogSummary = Schema.Struct({
241
268
  namespaces: Schema.Array(CodeModeCatalogNamespace),
242
- /** Stageable tool names the catalog lists: `pinned` ones, then `listed` ones (never `search`). */
269
+ /** Stageable tool names the catalog lists: `pinned` ones, then the others (never `search` or
270
+ * deferred ones). */
243
271
  stageable: Schema.Struct({
244
272
  pinned: Schema.Array(Schema.String),
245
273
  listed: Schema.Array(Schema.String)
@@ -294,7 +322,7 @@ const namespaceLine = (namespace) => {
294
322
  /** The full catalog text of an instruction message. */
295
323
  const renderCodeModeCatalog = (summary) => [
296
324
  "# Code mode catalog",
297
- "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.",
325
+ "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 })` (each hit has its call signature) and call them in your next script.",
298
326
  ["## Namespaces", ...summary.namespaces.map(namespaceLine)].join("\n"),
299
327
  ...summary.namespaces.flatMap((namespace) => namespace.listing.length === 0 ? [] : [`### ${namespace.name}\n${namespace.listing}`]),
300
328
  ...hasStageableNames(summary.stageable) ? [stageableSection(summary.stageable)] : []
@@ -325,9 +353,9 @@ const renderCodeModeInstructedDescription = (input) => [
325
353
  ...globalLines(input.store === true),
326
354
  ...input.staging === void 0 ? [] : [stageLine(input.staging.reviewToolName)]
327
355
  ].join("\n"),
328
- "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."
356
+ "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? })` (each hit has its call signature) and call them in your next script."
329
357
  ].join("\n\n");
330
358
  //#endregion
331
- export { CodeModeCatalogSummary, codeModeCallLabels, codeModeCatalog, codeModeCatalogInstruction, codeModeCatalogInstructionKey, codeModeStageOnlyCatalog, defaultCodeModeInlineBudget, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, renderCodeModeCatalog, renderCodeModeDescription, renderCodeModeInstructedDescription, selectCodeModeListing, summarizeCodeModeCatalog };
359
+ export { CodeModeCatalogSummary, codeModeCallLabels, codeModeCatalog, codeModeCatalogInstruction, codeModeCatalogInstructionKey, codeModeStageOnlyCatalog, codeModeToolSignature, defaultCodeModeInlineBudget, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, maxCodeModeSearchSignatureChars, renderCodeModeCatalog, renderCodeModeDescription, renderCodeModeInstructedDescription, selectCodeModeListing, summarizeCodeModeCatalog };
332
360
 
333
361
  //# sourceMappingURL=catalog.mjs.map
@@ -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; signature: string }>` (default limit 8). `signature` is the call with its argument and result types: enough to call the tool in your next script.',\n '- `await describeTool(name)`: the full description and documented TypeScript declaration of a tool, or `undefined`; needed only when a signature is cut or unclear.',\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 JSON values (up to 256 KiB each) for later scripts; writes are saved only when the script succeeds. When fetched data is large, store it and return a summary, then filter it with `load()` in a later script instead of calling the tools again.'\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? })` (each hit has its call signature) or `await describeNamespace(name)`, then call them in your next script.'\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` and `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/** Longest `searchTools` signature, cut marker included (`describeTool` has the whole declaration). */\nexport const maxCodeModeSearchSignatureChars = 800\n\nconst signatureCutMarker = '… (describeTool for the full declaration)'\n\n// A rendered type on one line, without its description comments (`describeTool` keeps them). pi\n// puts every description line on its own `//` line and JSON-quotes keys and literals, so no other\n// line starts with `//`.\nconst compactText = (rendered: string) =>\n rendered\n .split('\\n')\n .map(line => line.trim())\n .filter(line => !line.startsWith('//'))\n .join(' ')\n\nconst compactResultType = (schema: CodeModeJsonSchema) => {\n const rendered = compactText(renderToolOutputType(schema))\n\n return rendered.length <= maxShortTypeChars ? rendered : shortType(schema)\n}\n\n// Cuts at a code point boundary: never leaves half of a surrogate pair.\nconst cutSignature = (signature: string) => {\n const end = maxCodeModeSearchSignatureChars - signatureCutMarker.length\n const kept = signature.slice(0, end)\n const last = kept.charCodeAt(kept.length - 1)\n\n return `${last >= 0xd800 && last <= 0xdbff ? kept.slice(0, -1) : kept}${signatureCutMarker}`\n}\n\n/**\n * The call a `searchTools` hit shows, enough to call the tool without `describeTool`:\n * `tools.<id>(args): Promise<result>`, or `stage(\"<name>\", args)` for a stageable tool. Bounded:\n * a long one ends with a pointer to `describeTool`.\n */\nexport const codeModeToolSignature = (tool: CodeModeCatalogTool): string => {\n const signature =\n tool.exposure === 'stage'\n ? `stage(${JSON.stringify(tool.name)}, ${compactText(schemaToType(tool.inputSchema))})`\n : `${tool.callLabel}(${compactText(schemaToType(tool.inputSchema))}): Promise<${compactResultType(tool.outputSchema)}>`\n\n return signature.length <= maxCodeModeSearchSignatureChars ? signature : cutSignature(signature)\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 })` (each hit has its call signature) and call them in your next script.',\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? })` (each hit has its call signature) and call them in your next script.'\n ].join('\\n\\n')\n"],"mappings":";;;;;AA6CA,MAAM,mBAAuC,EAAE,MAAM,SAAS;;;;;;;;AAS9D,MAAa,sBAAsB,UAAwD;CACzF,MAAM,wBAAQ,IAAI,IAAY;CAE9B,OAAO,MAAM,KAAI,SAAQ;EACvB,MAAM,aAAa,qBAAqB,IAAI;EAC5C,MAAM,iBAAiB,CAAC,MAAM,IAAI,UAAU;EAE5C,MAAM,IAAI,UAAU;EACpB,MAAM,IAAI,IAAI;EAEd,OAAO,iBAAiB,SAAS,eAAe,SAAS,KAAK,UAAU,IAAI,EAAE;CAChF,CAAC;AACH;;AAGA,MAAa,mBACX,UACuC;CACvC,MAAM,SAAS,mBAAmB,MAAM,KAAK,EAAE,UAAU,IAAI,IAAI,CAAC;CAElE,OAAO,MAAM,KAAK,EAAE,KAAK,UAAU,qBAAqB,UAAU;EAChE,MAAM,OAA4B;GAChC,MAAM,IAAI;GACV,YAAY,qBAAqB,IAAI,IAAI;GACzC,WAAW,OAAO,UAAU,SAAS,KAAK,UAAU,IAAI,IAAI,EAAE;GAC9D,WAAW;GACX,aAAa,IAAI;GACjB,aAAa,IAAI;GACjB,cAAc,IAAI,gBAAgB;GAClC,YAAY,IAAI,iBAAiB,KAAA;GAGjC,UAAU,cAAc,GAAG,MAAM,eAAe,GAAG,IAAI,WAAW;EACpE;EAEA,OAAO,sBAAsB,KAAA,IACzB,OACA;GAAE,GAAG;GAAM,sBAAsB;EAAkB;CACzD,CAAC;AACH;;;;;;;AAQA,MAAa,4BACX,cAEA,UAAU,KAAK,EAAE,KAAK,UAAU,wBAAwB;CACtD,MAAM,OAA4B;EAChC,MAAM,IAAI;EACV,YAAY,qBAAqB,IAAI,IAAI;EACzC,WAAW,SAAS,KAAK,UAAU,IAAI,IAAI,EAAE;EAC7C,WAAW;EACX,aAAa,IAAI;EACjB,aAAa,IAAI;EACjB,cAAc,IAAI,gBAAgB;EAClC,YAAY,IAAI,iBAAiB,KAAA;EACjC,UAAU;CACZ;CAEA,OAAO,sBAAsB,KAAA,IACzB,OACA;EAAE,GAAG;EAAM,sBAAsB;CAAkB;AACzD,CAAC;;AAGH,MAAa,8BAA8B;;AAG3C,MAAa,0BAA0B,SAAyB,KAAK,KAAK,KAAK,SAAS,CAAC;AAEzF,MAAM,oBAAoB;AAE1B,MAAM,aAAa,WAAuC;CACxD,MAAM,WAAW,qBAAqB,MAAM;CAE5C,IAAI,SAAS,UAAU,mBAAmB,OAAO;CAEjD,IAAI,CAAC,UAAU,UAAU,MAAM,GAAG;EAChC,IAAI,OAAO,SAAS,SAAS,OAAO;EAEpC,IAAI,OAAO,SAAS,UAAU,OAAO;CACvC;CAEA,OAAO;AACT;AAGA,MAAM,mBAAmB,UAA+B;CACtD,MAAM,KAAK;CACX,aAAa,KAAK;CAClB,aAAa,KAAK;CAClB,cAAc,KAAK;CACnB,eAAe,KAAA;AACjB;AAEA,MAAM,kBAAkB,SACtB,aAAa,KAAK,WAAW,wCAAwC,KAAK,KAAK,4BAA4B,UAAU,KAAK,YAAY,EAAE;AAE1I,MAAM,sBAAsB,UAC1B,mBAAmB,EAAE,OAAO,MAAM,IAAI,eAAe,EAAE,CAAC;AAQ1D,MAAM,iBAAiB,SACrB,uBAAuB,mBAAmB,CAAC,IAAI,CAAC,CAAC;AAEnD,MAAM,oBACJ,UAC0C;CAC1C,MAAM,yBAAS,IAAI,IAAsB;CAEzC,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,QAAQ,OAAO,IAAI,KAAK,KAAK,SAAS;EAE5C,IAAI,UAAU,KAAA,GACZ,OAAO,IAAI,KAAK,KAAK,WAAW,CAAC,IAAI,CAAC;OAEtC,MAAM,KAAK,IAAI;CAEnB;CAEA,OAAO;AACT;;;;;;;;AAkBA,MAAa,yBACX,SACA,WACoB;CACpB,MAAM,aAAa,QAAQ,SAAS,MAAM,UACxC,KAAK,aAAa,WAAW,CAAC;EAAE;EAAM;EAAO,MAAM,cAAc,IAAI;CAAE,CAAC,IAAI,CAAC,CAC/E;CAEA,MAAM,SAAS,IAAI,IACjB,CAAC,GAAG,iBAAiB,UAAU,CAAC,EAAE,KAAK,CAAC,WAAW,WAAW,CAC5D,WACA,CAAC,GAAG,KAAK,EAAE,MAAM,MAAM,UAAU,KAAK,OAAO,MAAM,QAAQ,KAAK,QAAQ,MAAM,KAAK,CACrF,CAAC,CACH;CAEA,MAAM,SAAS,IAAI,IACjB,QAAQ,SAAS,MAAM,UACrB,KAAK,aAAa,SAAS,KAAK,aAAa,WAAW,CAAC,KAAK,IAAI,CAAC,CACrE,CACF;CAEA,MAAM,SAAS,IAAI,IAAI,OAAO,KAAK,CAAC;CACpC,IAAI,YAAY;CAEhB,OAAO,OAAO,OAAO,GACnB,KAAK,MAAM,CAAC,WAAW,UAAU,QAAQ;EACvC,IAAI,CAAC,OAAO,IAAI,SAAS,GAAG;EAE5B,MAAM,OAAO,MAAM,MAAM;EAEzB,IAAI,SAAS,KAAA,KAAa,KAAK,OAAO,WAAW;GAC/C,OAAO,OAAO,SAAS;GACvB;EACF;EAEA,OAAO,IAAI,KAAK,KAAK;EACrB,aAAa,KAAK;CACpB;CAGF,MAAM,WAAW,IAAI,IACnB,QAAQ,SAAS,MAAM,UAAW,OAAO,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,SAAS,CAAE,CAC9E;CAEA,OAAO;EACL,QAAQ,QAAQ,QAAQ,GAAG,UAAU,OAAO,IAAI,KAAK,CAAC;EACtD,oBAAoB,CAAC,GAAG,IAAI,IAAI,QAAQ,KAAI,SAAQ,KAAK,SAAS,CAAC,CAAC,EAAE,QAAO,cAC3E,SAAS,IAAI,SAAS,CACxB;CACF;AACF;AAEA,MAAM,QAAQ;CACZ;CACA;CACA;CACA;AACF,EAAE,KAAK,IAAI;AAEX,MAAM,aAAa,mBACjB,gNAAgN,eAAe;;AAGjO,MAAM,0BAA0B;AAWhC,MAAM,wBAAwB,aAAyD;CACrF,QAAQ,QAAQ,MAAM,SAAS,EAAE,UAAW,cAAc,GAAG,MAAM,WAAW,CAAC,IAAI,IAAI,IAAI,CAAC,CAAE;CAC9F,QAAQ,QAAQ,MAAM,SAAS,EAAE,UAAU;EACzC,MAAM,YAAY,cAAc,GAAG;EAEnC,OAAO,cAAc,YAAY,cAAc,YAAY,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI;CACjG,CAAC;AACH;AAEA,MAAM,qBAAqB,UACzB,MAAM,OAAO,SAAS,KAAK,MAAM,OAAO,SAAS;;AAGnD,MAAM,oBAAoB,UAA0B;CAClD,MAAM,OAAO,KAAK,IAAI,GAAG,0BAA0B,MAAM,OAAO,MAAM;CACtE,MAAM,SAAS,MAAM,OAAO,SAAS;CAErC,OAAO;EACL;EACA;EACA,GAAG,CAAC,GAAG,MAAM,QAAQ,GAAG,MAAM,OAAO,MAAM,GAAG,IAAI,CAAC,EAAE,KAAI,SAAQ,OAAO,KAAK,GAAG;EAChF,GAAI,SAAS,IAAI,CAAC,WAAW,OAAO,wCAAwC,IAAI,CAAC;CACnF,EAAE,KAAK,IAAI;AACb;AAEA,MAAM,eAAe,UAAmB;CACtC;CACA;CACA;CACA;CACA;CACA;CACA;CACA,GAAI,QACA,CACE,+RACF,IACA,CAAC;AACP;AAEA,MAAM,oBAAoB,WAAmB,UAA8C;CACzF,MAAM,WAAW,MAAM,QAAO,SAAQ,KAAK,aAAa,KAAK;CAC7D,MAAM,SAAS,MAAM,QAAO,SAAQ,KAAK,aAAa,KAAK;CAE3D,MAAM,cAAc,MAAM,MACxB,SAAQ,KAAK,yBAAyB,KAAA,CACxC,GAAG;CAEH,OAAO;EACL,OAAO;EACP,GAAI,gBAAgB,KAAA,IAAY,CAAC,IAAI,CAAC,WAAW;EACjD,GAAI,SAAS,SAAS,IAAI;GAAC;GAAS,mBAAmB,QAAQ;GAAG;EAAK,IAAI,CAAC;EAC5E,GAAG,OAAO,IAAI,cAAc;CAC9B,EAAE,KAAK,IAAI;AACb;AAGA,MAAM,oBACJ;;;;;;;;;;;AA2BF,MAAa,6BAA6B,UAA4C;CAKpF,MAAM,WAAW,CAAC,GAAG,iBAFL,sBAFA,gBAAgB,MAAM,KAEM,GAAG,MAAM,gBAAA,GAET,EAAE,OAAO,KAAI,UAAS,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,KAC5E,CAAC,WAAW,WACX,iBACE,WACA,MAAM,KAAI,SAAQ,KAAK,IAAI,CAC7B,CACJ;CAEA,MAAM,UACJ,MAAM,YAAY,KAAA,KAAa,MAAM,QAAQ,MAAM,SAAS,IAAI,MAAM,UAAU,KAAA;CAElF,MAAM,iBACJ,YAAY,KAAA,IAAY;EAAE,QAAQ,CAAC;EAAG,QAAQ,CAAC;CAAE,IAAI,qBAAqB,OAAO;CAEnF,OAAO;EACL;EACA;GACE;GACA,GAAG,YAAY,MAAM,UAAU,IAAI;GACnC,GAAI,YAAY,KAAA,IAAY,CAAC,IAAI,CAAC,UAAU,QAAQ,cAAc,CAAC;EACrE,EAAE,KAAK,IAAI;EACX,SAAS,WAAW,IAChB,wCACA,CAAC,gCAAgC,GAAG,QAAQ,EAAE,KAAK,MAAM;EAC7D,GAAI,kBAAkB,cAAc,IAAI,CAAC,iBAAiB,cAAc,CAAC,IAAI,CAAC;EAC9E;CACF,EAAE,KAAK,MAAM;AACf;;AAGA,MAAa,kCAAkC;AAE/C,MAAM,qBAAqB;AAK3B,MAAM,eAAe,aACnB,SACG,MAAM,IAAI,EACV,KAAI,SAAQ,KAAK,KAAK,CAAC,EACvB,QAAO,SAAQ,CAAC,KAAK,WAAW,IAAI,CAAC,EACrC,KAAK,GAAG;AAEb,MAAM,qBAAqB,WAA+B;CACxD,MAAM,WAAW,YAAY,qBAAqB,MAAM,CAAC;CAEzD,OAAO,SAAS,UAAU,oBAAoB,WAAW,UAAU,MAAM;AAC3E;AAGA,MAAM,gBAAgB,cAAsB;CAE1C,MAAM,OAAO,UAAU,MAAM,GAAG,GAAG;CACnC,MAAM,OAAO,KAAK,WAAW,KAAK,SAAS,CAAC;CAE5C,OAAO,GAAG,QAAQ,SAAU,QAAQ,QAAS,KAAK,MAAM,GAAG,EAAE,IAAI,OAAO;AAC1E;;;;;;AAOA,MAAa,yBAAyB,SAAsC;CAC1E,MAAM,YACJ,KAAK,aAAa,UACd,SAAS,KAAK,UAAU,KAAK,IAAI,EAAE,IAAI,YAAY,aAAa,KAAK,WAAW,CAAC,EAAE,KACnF,GAAG,KAAK,UAAU,GAAG,YAAY,aAAa,KAAK,WAAW,CAAC,EAAE,aAAa,kBAAkB,KAAK,YAAY,EAAE;CAEzH,OAAO,UAAU,UAAA,MAA4C,YAAY,aAAa,SAAS;AACjG;;;;;AAMA,MAAa,wBAAwB,SACnC,KAAK,aAAa,UACd;CACE,KAAK;CACL,iEAAiE,KAAK,UAAU,KAAK,IAAI,EAAE;CAC3F,SAAS,aAAa,KAAK,WAAW;AACxC,EAAE,KAAK,MAAM,IACb,iBAAiB,gBAAgB,IAAI,CAAC;;;;;;AAO5C,MAAa,oBACX,SACA,SAEA,QAAQ,MAAK,SAAQ,KAAK,aAAa,WAAW,KAAK,SAAS,IAAI,KACpE,QAAQ,MAAK,SAAQ,KAAK,eAAe,IAAI,KAC7C,QAAQ,MAAK,SAAQ,KAAK,SAAS,IAAI;;AAGzC,MAAa,gCAAgC;AAE7C,MAAM,2BAA2B,OAAO,OAAO;CAC7C,MAAM,OAAO;CACb,aAAa,OAAO,SAAS,OAAO,MAAM;;CAE1C,OAAO,OAAO;;CAEd,OAAO,OAAO;;CAEd,SAAS,OAAO;AAClB,CAAC;;AAGD,MAAa,yBAAyB,OAAO,OAAO;CAClD,YAAY,OAAO,MAAM,wBAAwB;;;CAGjD,WAAW,OAAO,OAAO;EACvB,QAAQ,OAAO,MAAM,OAAO,MAAM;EAClC,QAAQ,OAAO,MAAM,OAAO,MAAM;CACpC,CAAC;AACH,CAAC;AAID,MAAM,uBAAuB,OAAO,oBAAoB,sBAAsB;AAE9E,MAAM,uBAAuB,OAAO,aAAa,sBAAsB;AAEvE,MAAM,oBAAoB,UAA8C;CACtE,MAAM,WAAW,MAAM,QAAO,SAAQ,KAAK,aAAa,KAAK;CAC7D,MAAM,SAAS,MAAM,QAAO,SAAQ,KAAK,aAAa,KAAK;CAE3D,OAAO,CACL,GAAI,SAAS,SAAS,IAAI;EAAC;EAAS,mBAAmB,QAAQ;EAAG;CAAK,IAAI,CAAC,GAC5E,GAAG,OAAO,IAAI,cAAc,CAC9B,EAAE,KAAK,IAAI;AACb;;;;;;AAOA,MAAa,4BAA4B,UAIX;CAC5B,MAAM,UAAU,gBAAgB,MAAM,KAAK;CAC3C,MAAM,YAAY,MAAM,YAAY,KAAA,IAAY,CAAC,IAAI,yBAAyB,MAAM,QAAQ,KAAK;CAEjG,MAAM,oBAAoB,iBADV,sBAAsB,SAAS,MAAM,gBAAA,GACJ,EAAE,OAAO,KAAI,UAAS,EAAE,KAAK,EAAE,CAAC;CAoBjF,OAAO;EACL,YAnBiB,CAAC,GAAG,iBAAiB,CAAC,GAAG,SAAS,GAAG,SAAS,EAAE,KAAI,UAAS,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,KAC1F,CAAC,MAAM,WAAW;GACjB,MAAM,SAAS,kBAAkB,IAAI,IAAI,KAAK,CAAC,GAAG,KAAI,SAAQ,KAAK,IAAI;GAEvE,MAAM,cAAc,MAAM,MAAK,SAAQ,KAAK,KAAK,yBAAyB,KAAA,CAAS,GAAG,KACnF;GAEH,MAAM,YAAY;IAChB;IACA,OAAO,MAAM;IACb,OAAO,MAAM;IACb,SAAS,iBAAiB,KAAK;GACjC;GAEA,OAAO,gBAAgB,KAAA,IAAY,YAAY;IAAE,GAAG;IAAW;GAAY;EAC7E,CAIS;EACT,WACE,MAAM,YAAY,KAAA,IAAY;GAAE,QAAQ,CAAC;GAAG,QAAQ,CAAC;EAAE,IAAI,qBAAqB,MAAM,OAAO;CACjG;AACF;AAEA,MAAM,iBAAiB,cAA4D;CACjF,MAAM,QAAQ,UAAU,UAAU,IAAI,WAAW,GAAG,UAAU,MAAM;CAEpE,MAAM,QACJ,UAAU,UAAU,UAAU,QAC1B,QACA,UAAU,UAAU,IAClB,GAAG,MAAM,iBACT,GAAG,MAAM,IAAI,UAAU,MAAM;CAErC,OAAO,OAAO,UAAU,KAAK,MAAM,MAAM,GAAG,UAAU,gBAAgB,KAAA,IAAY,KAAK,KAAK,UAAU;AACxG;;AAGA,MAAa,yBAAyB,YACpC;CACE;CACA;CACA,CAAC,iBAAiB,GAAG,QAAQ,WAAW,IAAI,aAAa,CAAC,EAAE,KAAK,IAAI;CACrE,GAAG,QAAQ,WAAW,SAAQ,cAC5B,UAAU,QAAQ,WAAW,IAAI,CAAC,IAAI,CAAC,OAAO,UAAU,KAAK,IAAI,UAAU,SAAS,CACtF;CACA,GAAI,kBAAkB,QAAQ,SAAS,IAAI,CAAC,iBAAiB,QAAQ,SAAS,CAAC,IAAI,CAAC;AACtF,EAAE,KAAK,MAAM;;;;;AAMf,MAAa,8BAA8B,UAIrB;CACpB,MAAM,UAAU,yBAAyB,KAAK;CAE9C,OAAO;EACL,KAAK;EACL,OACE,QAAQ,WAAW,WAAW,IAC1B,KAAA,IACA,OAAO,eAAe,qBAAqB,OAAO,CAAC;EACzD,SAAQ,YAAW;GACjB,MAAM,UAAU,YAAY,KAAA,IAAY,OAAO,KAAK,IAAI,qBAAqB,OAAO;GAEpF,OAAO,OAAO,OAAO,OAAO,IACxB,4FACA,sBAAsB,QAAQ,KAAK;EACzC;CACF;AACF;;;;;AAMA,MAAa,uCAAuC,UAIlD;CACE;CACA;EACE;EACA,GAAG,YAAY,MAAM,UAAU,IAAI;EACnC,GAAI,MAAM,YAAY,KAAA,IAAY,CAAC,IAAI,CAAC,UAAU,MAAM,QAAQ,cAAc,CAAC;CACjF,EAAE,KAAK,IAAI;CACX;AACF,EAAE,KAAK,MAAM"}
package/dist/index.d.mts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { CodeModeError, CodeModeErrorKind, CodeModeExecuteOptions, CodeModeExecutionResult, CodeModeExecutor, CodeModeExecutorGlobal, CodeModeExecutorTool, CodeModeJsonSchema, CodeModeOutputItem, CodeModeStore, CodeModeStoreWrites, CodeModeToolContext } from "./executor.mjs";
2
- import { CodeModeCatalogSummary, CodeModeCatalogTool, CodeModeDescriptionInput, CodeModeListing, CodeModeStagingDescription, CodeModeToolExposure, codeModeCatalog, codeModeCatalogInstruction, codeModeCatalogInstructionKey, codeModeStageOnlyCatalog, defaultCodeModeInlineBudget, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, renderCodeModeCatalog, renderCodeModeDescription, renderCodeModeInstructedDescription, selectCodeModeListing, summarizeCodeModeCatalog } from "./catalog.mjs";
2
+ import { CodeModeCatalogSummary, CodeModeCatalogTool, CodeModeDescriptionInput, CodeModeListing, CodeModeStagingDescription, CodeModeToolExposure, codeModeCatalog, codeModeCatalogInstruction, codeModeCatalogInstructionKey, codeModeStageOnlyCatalog, codeModeToolSignature, defaultCodeModeInlineBudget, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, maxCodeModeSearchSignatureChars, renderCodeModeCatalog, renderCodeModeDescription, renderCodeModeInstructedDescription, selectCodeModeListing, summarizeCodeModeCatalog } from "./catalog.mjs";
3
3
  import { ClassifierConcurrencyLimiter, ClassifierToolParams, MakeClassifierToolOptions, classifierToolName, defaultClassifierProcessLimiter, defaultClassifierProcessMaxConcurrency, defaultClassifierToolMaxConcurrency, makeClassifierConcurrencyLimiter, makeClassifierTool } from "./classifier-tool.mjs";
4
4
  import { CodeModeSearchHit, CodeModeSearchOptions, codeModeSearchTokens, defaultCodeModeSearchLimit, searchCodeModeTools } from "./search.mjs";
5
5
  import { CodeModeCallSummary, CodeModeResultSegment, boundCodeModeSegments, codeModeResultSegments, codeModeSegmentsContent, defaultCodeModeMaxImageBytes, defaultCodeModeMaxImages, summarizeCodeModeCalls } from "./output.mjs";
6
6
  import { CodeModeInterruptedCall, CodeModeInterruptedCallStatus, CodeModeInterruptedCalls, CodeModeStagedPlan, CodeModeStructuredContent, CodeModeToolResultEntry, codeModeStoreFromToolResults, maxCodeModeStoreTotalChars, maxCodeModeStoreValueChars } from "./store.mjs";
7
7
  import { CodeModeAfterNestedCallInput, CodeModeLimits, CodeModeNestedCallOutcome, CodeModeStagingOptions, MakeCodeModeToolOptions, codeModeDeadlineMarginMs, codeModeMinimumTimeoutMs, codeModeToolName, defaultCodeModeLimits, makeCodeModeTool } from "./tool.mjs";
8
- export { type ClassifierConcurrencyLimiter, ClassifierToolParams, type CodeModeAfterNestedCallInput, type CodeModeCallSummary, CodeModeCatalogSummary, type CodeModeCatalogTool, type CodeModeDescriptionInput, type CodeModeError, type CodeModeErrorKind, type CodeModeExecuteOptions, type CodeModeExecutionResult, type CodeModeExecutor, type CodeModeExecutorGlobal, type CodeModeExecutorTool, type CodeModeInterruptedCall, type CodeModeInterruptedCallStatus, type CodeModeInterruptedCalls, type CodeModeJsonSchema, type CodeModeLimits, type CodeModeListing, type CodeModeNestedCallOutcome, type CodeModeOutputItem, type CodeModeResultSegment, type CodeModeSearchHit, type CodeModeSearchOptions, type CodeModeStagedPlan, type CodeModeStagingDescription, type CodeModeStagingOptions, type CodeModeStore, type CodeModeStoreWrites, type CodeModeStructuredContent, type CodeModeToolContext, type CodeModeToolExposure, type CodeModeToolResultEntry, type MakeClassifierToolOptions, type MakeCodeModeToolOptions, boundCodeModeSegments, classifierToolName, codeModeCatalog, codeModeCatalogInstruction, codeModeCatalogInstructionKey, codeModeDeadlineMarginMs, codeModeMinimumTimeoutMs, codeModeResultSegments, codeModeSearchTokens, codeModeSegmentsContent, codeModeStageOnlyCatalog, codeModeStoreFromToolResults, codeModeToolName, defaultClassifierProcessLimiter, defaultClassifierProcessMaxConcurrency, defaultClassifierToolMaxConcurrency, defaultCodeModeInlineBudget, defaultCodeModeLimits, defaultCodeModeMaxImageBytes, defaultCodeModeMaxImages, defaultCodeModeSearchLimit, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, makeClassifierConcurrencyLimiter, makeClassifierTool, makeCodeModeTool, maxCodeModeStoreTotalChars, maxCodeModeStoreValueChars, renderCodeModeCatalog, renderCodeModeDescription, renderCodeModeInstructedDescription, searchCodeModeTools, selectCodeModeListing, summarizeCodeModeCalls, summarizeCodeModeCatalog };
8
+ export { type ClassifierConcurrencyLimiter, ClassifierToolParams, type CodeModeAfterNestedCallInput, type CodeModeCallSummary, CodeModeCatalogSummary, type CodeModeCatalogTool, type CodeModeDescriptionInput, type CodeModeError, type CodeModeErrorKind, type CodeModeExecuteOptions, type CodeModeExecutionResult, type CodeModeExecutor, type CodeModeExecutorGlobal, type CodeModeExecutorTool, type CodeModeInterruptedCall, type CodeModeInterruptedCallStatus, type CodeModeInterruptedCalls, type CodeModeJsonSchema, type CodeModeLimits, type CodeModeListing, type CodeModeNestedCallOutcome, type CodeModeOutputItem, type CodeModeResultSegment, type CodeModeSearchHit, type CodeModeSearchOptions, type CodeModeStagedPlan, type CodeModeStagingDescription, type CodeModeStagingOptions, type CodeModeStore, type CodeModeStoreWrites, type CodeModeStructuredContent, type CodeModeToolContext, type CodeModeToolExposure, type CodeModeToolResultEntry, type MakeClassifierToolOptions, type MakeCodeModeToolOptions, boundCodeModeSegments, classifierToolName, codeModeCatalog, codeModeCatalogInstruction, codeModeCatalogInstructionKey, codeModeDeadlineMarginMs, codeModeMinimumTimeoutMs, codeModeResultSegments, codeModeSearchTokens, codeModeSegmentsContent, codeModeStageOnlyCatalog, codeModeStoreFromToolResults, codeModeToolName, codeModeToolSignature, defaultClassifierProcessLimiter, defaultClassifierProcessMaxConcurrency, defaultClassifierToolMaxConcurrency, defaultCodeModeInlineBudget, defaultCodeModeLimits, defaultCodeModeMaxImageBytes, defaultCodeModeMaxImages, defaultCodeModeSearchLimit, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, makeClassifierConcurrencyLimiter, makeClassifierTool, makeCodeModeTool, maxCodeModeSearchSignatureChars, maxCodeModeStoreTotalChars, maxCodeModeStoreValueChars, renderCodeModeCatalog, renderCodeModeDescription, renderCodeModeInstructedDescription, searchCodeModeTools, selectCodeModeListing, summarizeCodeModeCalls, summarizeCodeModeCatalog };
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { CodeModeCatalogSummary, codeModeCatalog, codeModeCatalogInstruction, codeModeCatalogInstructionKey, codeModeStageOnlyCatalog, defaultCodeModeInlineBudget, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, renderCodeModeCatalog, renderCodeModeDescription, renderCodeModeInstructedDescription, selectCodeModeListing, summarizeCodeModeCatalog } from "./catalog.mjs";
1
+ import { CodeModeCatalogSummary, codeModeCatalog, codeModeCatalogInstruction, codeModeCatalogInstructionKey, codeModeStageOnlyCatalog, codeModeToolSignature, defaultCodeModeInlineBudget, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, maxCodeModeSearchSignatureChars, renderCodeModeCatalog, renderCodeModeDescription, renderCodeModeInstructedDescription, selectCodeModeListing, summarizeCodeModeCatalog } from "./catalog.mjs";
2
2
  import { ClassifierToolParams, classifierToolName, defaultClassifierProcessLimiter, defaultClassifierProcessMaxConcurrency, defaultClassifierToolMaxConcurrency, makeClassifierConcurrencyLimiter, makeClassifierTool } from "./classifier-tool.mjs";
3
3
  import { codeModeSearchTokens, defaultCodeModeSearchLimit, searchCodeModeTools } from "./search.mjs";
4
4
  import { boundCodeModeSegments, codeModeResultSegments, codeModeSegmentsContent, defaultCodeModeMaxImageBytes, defaultCodeModeMaxImages, summarizeCodeModeCalls } from "./output.mjs";
5
5
  import { codeModeDeadlineMarginMs, codeModeMinimumTimeoutMs, codeModeToolName, defaultCodeModeLimits, makeCodeModeTool } from "./tool.mjs";
6
6
  import { codeModeStoreFromToolResults, maxCodeModeStoreTotalChars, maxCodeModeStoreValueChars } from "./store.mjs";
7
- export { ClassifierToolParams, CodeModeCatalogSummary, boundCodeModeSegments, classifierToolName, codeModeCatalog, codeModeCatalogInstruction, codeModeCatalogInstructionKey, codeModeDeadlineMarginMs, codeModeMinimumTimeoutMs, codeModeResultSegments, codeModeSearchTokens, codeModeSegmentsContent, codeModeStageOnlyCatalog, codeModeStoreFromToolResults, codeModeToolName, defaultClassifierProcessLimiter, defaultClassifierProcessMaxConcurrency, defaultClassifierToolMaxConcurrency, defaultCodeModeInlineBudget, defaultCodeModeLimits, defaultCodeModeMaxImageBytes, defaultCodeModeMaxImages, defaultCodeModeSearchLimit, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, makeClassifierConcurrencyLimiter, makeClassifierTool, makeCodeModeTool, maxCodeModeStoreTotalChars, maxCodeModeStoreValueChars, renderCodeModeCatalog, renderCodeModeDescription, renderCodeModeInstructedDescription, searchCodeModeTools, selectCodeModeListing, summarizeCodeModeCalls, summarizeCodeModeCatalog };
7
+ export { ClassifierToolParams, CodeModeCatalogSummary, boundCodeModeSegments, classifierToolName, codeModeCatalog, codeModeCatalogInstruction, codeModeCatalogInstructionKey, codeModeDeadlineMarginMs, codeModeMinimumTimeoutMs, codeModeResultSegments, codeModeSearchTokens, codeModeSegmentsContent, codeModeStageOnlyCatalog, codeModeStoreFromToolResults, codeModeToolName, codeModeToolSignature, defaultClassifierProcessLimiter, defaultClassifierProcessMaxConcurrency, defaultClassifierToolMaxConcurrency, defaultCodeModeInlineBudget, defaultCodeModeLimits, defaultCodeModeMaxImageBytes, defaultCodeModeMaxImages, defaultCodeModeSearchLimit, describeCodeModeTool, estimateCodeModeTokens, findCodeModeTool, makeClassifierConcurrencyLimiter, makeClassifierTool, makeCodeModeTool, maxCodeModeSearchSignatureChars, maxCodeModeStoreTotalChars, maxCodeModeStoreValueChars, renderCodeModeCatalog, renderCodeModeDescription, renderCodeModeInstructedDescription, searchCodeModeTools, selectCodeModeListing, summarizeCodeModeCalls, summarizeCodeModeCatalog };
package/dist/search.d.mts CHANGED
@@ -12,7 +12,8 @@ type CodeModeSearchHit = {
12
12
  * scripts pass to `stage(name, args)`.
13
13
  */
14
14
  readonly name: string;
15
- readonly description: string; /** A stage-only tool (ADR 0007): no `tools` binding, only `stage()` it. */
15
+ readonly description: string; /** The call with its argument and result types (`codeModeToolSignature`), bounded. */
16
+ readonly signature: string; /** A stage-only tool (ADR 0007): no `tools` binding, only `stage()` it. */
16
17
  readonly stageOnly?: true;
17
18
  };
18
19
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.mts","names":[],"sources":["../src/search.ts"],"mappings":";;;;cAIa,0BAAA;AAAA,KAED,qBAAA;EAAA,SACD,KAAA;EAAA,SACA,SAAS;AAAA;AAAA,KAGR,iBAAA;EALA;;;EAAA,SASD,IAAA;EAAA,SACA,WAAA,UALC;EAAA,SAOD,SAAA;AAAA;;;;;;cAQE,mBAAA,GACX,OAAA,EAAS,aAAA,CAAc,mBAAA,GACvB,KAAA,UACA,OAAA,GAAS,qBAAA,KACR,aAAA,CAAc,iBAAA;AAJjB;AAAA,cAgCa,oBAAA,GAAoB,IAAA,aAAA,aAAA"}
1
+ {"version":3,"file":"search.d.mts","names":[],"sources":["../src/search.ts"],"mappings":";;;;cAIa,0BAAA;AAAA,KAED,qBAAA;EAAA,SACD,KAAA;EAAA,SACA,SAAS;AAAA;AAAA,KAGR,iBAAA;EALA;;;EAAA,SASD,IAAA;EAAA,SACA,WAAA,UALC;EAAA,SAOD,SAAA;WAEA,SAAA;AAAA;;;;;AAAS;cAQP,mBAAA,GACX,OAAA,EAAS,aAAA,CAAc,mBAAA,GACvB,KAAA,UACA,OAAA,GAAS,qBAAA,KACR,aAAA,CAAc,iBAAA;;cAqCJ,oBAAA,GAAoB,IAAA,aAAA,aAAA"}
package/dist/search.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { codeModeToolSignature } from "./catalog.mjs";
1
2
  import { rankToolSearchDocuments, toolSearchTokens } from "@yolk-sdk/agent/tools";
2
3
  //#region src/search.ts
3
4
  /** Default number of `searchTools` results. */
@@ -12,10 +13,12 @@ const searchCodeModeTools = (catalog, query, options = {}) => {
12
13
  const hit = (tool) => tool.exposure === "stage" ? {
13
14
  name: tool.name,
14
15
  description: tool.description,
16
+ signature: codeModeToolSignature(tool),
15
17
  stageOnly: true
16
18
  } : {
17
19
  name: tool.identifier,
18
- description: tool.description
20
+ description: tool.description,
21
+ signature: codeModeToolSignature(tool)
19
22
  };
20
23
  return rankToolSearchDocuments(scoped.map((tool) => ({
21
24
  value: tool,
@@ -1 +1 @@
1
- {"version":3,"file":"search.mjs","names":[],"sources":["../src/search.ts"],"sourcesContent":["import { rankToolSearchDocuments, toolSearchTokens } from '@yolk-sdk/agent/tools'\nimport type { CodeModeCatalogTool } from './catalog.ts'\n\n/** Default number of `searchTools` results. */\nexport const defaultCodeModeSearchLimit = 8\n\nexport type CodeModeSearchOptions = {\n readonly limit?: number\n readonly namespace?: string\n}\n\nexport type CodeModeSearchHit = {\n /** The identifier scripts call as `tools.<name>(args)`, or for a stage-only tool the name\n * scripts pass to `stage(name, args)`.\n */\n readonly name: string\n readonly description: string\n /** A stage-only tool (ADR 0007): no `tools` binding, only `stage()` it. */\n readonly stageOnly?: true\n}\n\n/**\n * BM25 (the shared `rankToolSearchDocuments`) over each tool's identifier, raw name, description,\n * namespace, and namespace description. Ties keep catalog order. A query without words lists the\n * (namespace-filtered) tools in catalog order.\n */\nexport const searchCodeModeTools = (\n catalog: ReadonlyArray<CodeModeCatalogTool>,\n query: string,\n options: CodeModeSearchOptions = {}\n): ReadonlyArray<CodeModeSearchHit> => {\n const scoped =\n options.namespace === undefined\n ? catalog\n : catalog.filter(tool => tool.namespace === options.namespace)\n\n const hit = (tool: CodeModeCatalogTool): CodeModeSearchHit =>\n tool.exposure === 'stage'\n ? { name: tool.name, description: tool.description, stageOnly: true }\n : { name: tool.identifier, description: tool.description }\n\n return rankToolSearchDocuments(\n scoped.map(tool => ({\n value: tool,\n text: [\n tool.identifier,\n tool.name,\n tool.description,\n tool.namespace,\n tool.namespaceDescription ?? ''\n ].join(' ')\n })),\n query,\n options.limit ?? defaultCodeModeSearchLimit\n ).map(hit)\n}\n\n/** Lowercase word tokens of code mode search (the shared `toolSearchTokens`). */\nexport const codeModeSearchTokens = toolSearchTokens\n"],"mappings":";;;AAIA,MAAa,6BAA6B;;;;;;AAsB1C,MAAa,uBACX,SACA,OACA,UAAiC,CAAC,MACG;CACrC,MAAM,SACJ,QAAQ,cAAc,KAAA,IAClB,UACA,QAAQ,QAAO,SAAQ,KAAK,cAAc,QAAQ,SAAS;CAEjE,MAAM,OAAO,SACX,KAAK,aAAa,UACd;EAAE,MAAM,KAAK;EAAM,aAAa,KAAK;EAAa,WAAW;CAAK,IAClE;EAAE,MAAM,KAAK;EAAY,aAAa,KAAK;CAAY;CAE7D,OAAO,wBACL,OAAO,KAAI,UAAS;EAClB,OAAO;EACP,MAAM;GACJ,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK,wBAAwB;EAC/B,EAAE,KAAK,GAAG;CACZ,EAAE,GACF,OACA,QAAQ,SAAA,CACV,EAAE,IAAI,GAAG;AACX;;AAGA,MAAa,uBAAuB"}
1
+ {"version":3,"file":"search.mjs","names":[],"sources":["../src/search.ts"],"sourcesContent":["import { rankToolSearchDocuments, toolSearchTokens } from '@yolk-sdk/agent/tools'\nimport { codeModeToolSignature, type CodeModeCatalogTool } from './catalog.ts'\n\n/** Default number of `searchTools` results. */\nexport const defaultCodeModeSearchLimit = 8\n\nexport type CodeModeSearchOptions = {\n readonly limit?: number\n readonly namespace?: string\n}\n\nexport type CodeModeSearchHit = {\n /** The identifier scripts call as `tools.<name>(args)`, or for a stage-only tool the name\n * scripts pass to `stage(name, args)`.\n */\n readonly name: string\n readonly description: string\n /** The call with its argument and result types (`codeModeToolSignature`), bounded. */\n readonly signature: string\n /** A stage-only tool (ADR 0007): no `tools` binding, only `stage()` it. */\n readonly stageOnly?: true\n}\n\n/**\n * BM25 (the shared `rankToolSearchDocuments`) over each tool's identifier, raw name, description,\n * namespace, and namespace description. Ties keep catalog order. A query without words lists the\n * (namespace-filtered) tools in catalog order.\n */\nexport const searchCodeModeTools = (\n catalog: ReadonlyArray<CodeModeCatalogTool>,\n query: string,\n options: CodeModeSearchOptions = {}\n): ReadonlyArray<CodeModeSearchHit> => {\n const scoped =\n options.namespace === undefined\n ? catalog\n : catalog.filter(tool => tool.namespace === options.namespace)\n\n const hit = (tool: CodeModeCatalogTool): CodeModeSearchHit =>\n tool.exposure === 'stage'\n ? {\n name: tool.name,\n description: tool.description,\n signature: codeModeToolSignature(tool),\n stageOnly: true\n }\n : {\n name: tool.identifier,\n description: tool.description,\n signature: codeModeToolSignature(tool)\n }\n\n return rankToolSearchDocuments(\n scoped.map(tool => ({\n value: tool,\n text: [\n tool.identifier,\n tool.name,\n tool.description,\n tool.namespace,\n tool.namespaceDescription ?? ''\n ].join(' ')\n })),\n query,\n options.limit ?? defaultCodeModeSearchLimit\n ).map(hit)\n}\n\n/** Lowercase word tokens of code mode search (the shared `toolSearchTokens`). */\nexport const codeModeSearchTokens = toolSearchTokens\n"],"mappings":";;;;AAIA,MAAa,6BAA6B;;;;;;AAwB1C,MAAa,uBACX,SACA,OACA,UAAiC,CAAC,MACG;CACrC,MAAM,SACJ,QAAQ,cAAc,KAAA,IAClB,UACA,QAAQ,QAAO,SAAQ,KAAK,cAAc,QAAQ,SAAS;CAEjE,MAAM,OAAO,SACX,KAAK,aAAa,UACd;EACE,MAAM,KAAK;EACX,aAAa,KAAK;EAClB,WAAW,sBAAsB,IAAI;EACrC,WAAW;CACb,IACA;EACE,MAAM,KAAK;EACX,aAAa,KAAK;EAClB,WAAW,sBAAsB,IAAI;CACvC;CAEN,OAAO,wBACL,OAAO,KAAI,UAAS;EAClB,OAAO;EACP,MAAM;GACJ,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK,wBAAwB;EAC/B,EAAE,KAAK,GAAG;CACZ,EAAE,GACF,OACA,QAAQ,SAAA,CACV,EAAE,IAAI,GAAG;AACX;;AAGA,MAAa,uBAAuB"}
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 stage-only tool. */
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 stage-only tool rejects with a hint to stage it (ADR 0007). */
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":";;;;;;;;;;;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"}
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":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yolk-sdk/codemode",
3
- "version": "0.1.0-canary.108",
3
+ "version": "0.1.0-canary.110",
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.108"
55
+ "@yolk-sdk/agent": "^0.1.0-canary.110"
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 stage-only tool
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 stage-only tools among the stageable ones (`callableBy: 'codemode'`,
98
- * ADR 0007): searchable and describable, never callable (no `tools` binding), so their call label
99
- * is the `stage()` call that records them.
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.flatMap(({ def, moduleId, moduleDescription }) => {
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
- moduleDescription === undefined ? tool : { ...tool, namespaceDescription: moduleDescription }
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
- /** Stageable tools the description names: `pinned` ones first, never stage-only `search` ones. */
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
 
@@ -302,12 +304,12 @@ const globalLines = (store: boolean) => [
302
304
  '- `image(dataUrl)`: append a base64 image (a `data:` URL or `{ type: "image", data, mimeType }`).',
303
305
  '- `exit()`: end the script successfully.',
304
306
  '- `ALL_TOOLS`: `{ name, description }` of every callable tool.',
305
- '- `await searchTools(query, { limit?, namespace? })`: find tools by topic; resolves to `Array<{ name: string; description: string }>` (default limit 8).',
306
- '- `await describeTool(name)`: the description and TypeScript declaration of a tool, or `undefined`.',
307
+ '- `await searchTools(query, { limit?, namespace? })`: find tools by topic; resolves to `Array<{ name: string; description: string; signature: string }>` (default limit 8). `signature` is the call with its argument and result types: enough to call the tool in your next script.',
308
+ '- `await describeTool(name)`: the full description and documented TypeScript declaration of a tool, or `undefined`; needed only when a signature is cut or unclear.',
307
309
  '- `await describeNamespace(name)`: `{ name, description?, tools: Array<{ name, description }> }` for a namespace, or `undefined`.',
308
310
  ...(store
309
311
  ? [
310
- '- `store(key, value)` and `load(key)`: keep small JSON values for later scripts; writes are saved only when the script succeeds.'
312
+ '- `store(key, value)` and `load(key)`: keep JSON values (up to 256 KiB each) for later scripts; writes are saved only when the script succeeds. When fetched data is large, store it and return a summary, then filter it with `load()` in a later script instead of calling the tools again.'
311
313
  ]
312
314
  : [])
313
315
  ]
@@ -330,7 +332,7 @@ const namespaceSection = (namespace: string, tools: ReadonlyArray<CodeModeCatalo
330
332
 
331
333
  // Fixed text: never derived from `search` tools or from which tools did not fit the budget.
332
334
  const unlistedToolsLine =
333
- '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.'
335
+ 'More tools may be callable than are listed here: find them with `await searchTools(query, { namespace? })` (each hit has its call signature) or `await describeNamespace(name)`, then call them in your next script.'
334
336
 
335
337
  /** Staged tool plans as the description shows them (`NestedToolStagingDescription`). */
336
338
  export type CodeModeStagingDescription = {
@@ -343,18 +345,19 @@ 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 not stage-only `search` tools. */
348
+ /** Document `stage()` and list the stageable tools that are neither `search` nor deferred. */
347
349
  readonly staging?: CodeModeStagingDescription
348
350
  }
349
351
 
350
352
  /**
351
353
  * The code mode tool description: intro, globals one per line, then nested tools grouped by
352
- * namespace, then one fixed line pointing to `searchTools`/`describeTool`/`describeNamespace`.
354
+ * namespace, then one fixed line pointing to `searchTools` and `describeNamespace`.
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; stage-only `search` tools
357
- * are never named, so they leave the text byte-identical too once any stageable tool exists.
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)
@@ -390,6 +393,50 @@ export const renderCodeModeDescription = (input: CodeModeDescriptionInput): stri
390
393
  ].join('\n\n')
391
394
  }
392
395
 
396
+ /** Longest `searchTools` signature, cut marker included (`describeTool` has the whole declaration). */
397
+ export const maxCodeModeSearchSignatureChars = 800
398
+
399
+ const signatureCutMarker = '… (describeTool for the full declaration)'
400
+
401
+ // A rendered type on one line, without its description comments (`describeTool` keeps them). pi
402
+ // puts every description line on its own `//` line and JSON-quotes keys and literals, so no other
403
+ // line starts with `//`.
404
+ const compactText = (rendered: string) =>
405
+ rendered
406
+ .split('\n')
407
+ .map(line => line.trim())
408
+ .filter(line => !line.startsWith('//'))
409
+ .join(' ')
410
+
411
+ const compactResultType = (schema: CodeModeJsonSchema) => {
412
+ const rendered = compactText(renderToolOutputType(schema))
413
+
414
+ return rendered.length <= maxShortTypeChars ? rendered : shortType(schema)
415
+ }
416
+
417
+ // Cuts at a code point boundary: never leaves half of a surrogate pair.
418
+ const cutSignature = (signature: string) => {
419
+ const end = maxCodeModeSearchSignatureChars - signatureCutMarker.length
420
+ const kept = signature.slice(0, end)
421
+ const last = kept.charCodeAt(kept.length - 1)
422
+
423
+ return `${last >= 0xd800 && last <= 0xdbff ? kept.slice(0, -1) : kept}${signatureCutMarker}`
424
+ }
425
+
426
+ /**
427
+ * The call a `searchTools` hit shows, enough to call the tool without `describeTool`:
428
+ * `tools.<id>(args): Promise<result>`, or `stage("<name>", args)` for a stageable tool. Bounded:
429
+ * a long one ends with a pointer to `describeTool`.
430
+ */
431
+ export const codeModeToolSignature = (tool: CodeModeCatalogTool): string => {
432
+ const signature =
433
+ tool.exposure === 'stage'
434
+ ? `stage(${JSON.stringify(tool.name)}, ${compactText(schemaToType(tool.inputSchema))})`
435
+ : `${tool.callLabel}(${compactText(schemaToType(tool.inputSchema))}): Promise<${compactResultType(tool.outputSchema)}>`
436
+
437
+ return signature.length <= maxCodeModeSearchSignatureChars ? signature : cutSignature(signature)
438
+ }
439
+
393
440
  /**
394
441
  * `describeTool` text: the description and TypeScript declaration of one tool. A stage-only tool
395
442
  * has no `tools` binding, so it is described as the `stage()` call that records it.
@@ -403,12 +450,18 @@ export const describeCodeModeTool = (tool: CodeModeCatalogTool): string =>
403
450
  ].join('\n\n')
404
451
  : renderToolSample(declarationTool(tool))
405
452
 
406
- /** Finds a tool by identifier or raw name. */
453
+ /**
454
+ * Finds a tool by identifier or raw name. A stageable tool's exact raw name wins first: it has no
455
+ * binding, so a callable tool sharing its identifier (`archive-resource` vs `archive_resource`)
456
+ * must not answer for it; callable lookups keep identifier precedence, as their bindings do.
457
+ */
407
458
  export const findCodeModeTool = (
408
459
  catalog: ReadonlyArray<CodeModeCatalogTool>,
409
460
  name: string
410
461
  ): CodeModeCatalogTool | undefined =>
411
- catalog.find(tool => tool.identifier === name) ?? catalog.find(tool => tool.name === name)
462
+ catalog.find(tool => tool.exposure === 'stage' && tool.name === name) ??
463
+ catalog.find(tool => tool.identifier === name) ??
464
+ catalog.find(tool => tool.name === name)
412
465
 
413
466
  /** The instruction key of the code mode catalog (`catalog: 'instructions'`, ADR 0007). */
414
467
  export const codeModeCatalogInstructionKey = 'yolk.codemode.catalog'
@@ -427,7 +480,8 @@ const CodeModeCatalogNamespace = Schema.Struct({
427
480
  /** The catalog an instruction message records as its state (JSON, never model-visible). */
428
481
  export const CodeModeCatalogSummary = Schema.Struct({
429
482
  namespaces: Schema.Array(CodeModeCatalogNamespace),
430
- /** Stageable tool names the catalog lists: `pinned` ones, then `listed` ones (never `search`). */
483
+ /** Stageable tool names the catalog lists: `pinned` ones, then the others (never `search` or
484
+ * deferred ones). */
431
485
  stageable: Schema.Struct({
432
486
  pinned: Schema.Array(Schema.String),
433
487
  listed: Schema.Array(Schema.String)
@@ -507,7 +561,7 @@ const namespaceLine = (namespace: CodeModeCatalogSummary['namespaces'][number])
507
561
  export const renderCodeModeCatalog = (summary: CodeModeCatalogSummary): string =>
508
562
  [
509
563
  '# Code mode catalog',
510
- '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.',
564
+ '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 })` (each hit has its call signature) and call them in your next script.',
511
565
  ['## Namespaces', ...summary.namespaces.map(namespaceLine)].join('\n'),
512
566
  ...summary.namespaces.flatMap(namespace =>
513
567
  namespace.listing.length === 0 ? [] : [`### ${namespace.name}\n${namespace.listing}`]
@@ -557,5 +611,5 @@ export const renderCodeModeInstructedDescription = (input: {
557
611
  ...globalLines(input.store === true),
558
612
  ...(input.staging === undefined ? [] : [stageLine(input.staging.reviewToolName)])
559
613
  ].join('\n'),
560
- '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.'
614
+ '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? })` (each hit has its call signature) and call them in your next script.'
561
615
  ].join('\n\n')
package/src/index.ts CHANGED
@@ -19,10 +19,12 @@ export {
19
19
  codeModeCatalogInstructionKey,
20
20
  CodeModeCatalogSummary,
21
21
  codeModeStageOnlyCatalog,
22
+ codeModeToolSignature,
22
23
  defaultCodeModeInlineBudget,
23
24
  describeCodeModeTool,
24
25
  estimateCodeModeTokens,
25
26
  findCodeModeTool,
27
+ maxCodeModeSearchSignatureChars,
26
28
  renderCodeModeCatalog,
27
29
  renderCodeModeDescription,
28
30
  renderCodeModeInstructedDescription,
package/src/search.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { rankToolSearchDocuments, toolSearchTokens } from '@yolk-sdk/agent/tools'
2
- import type { CodeModeCatalogTool } from './catalog.ts'
2
+ import { codeModeToolSignature, type CodeModeCatalogTool } from './catalog.ts'
3
3
 
4
4
  /** Default number of `searchTools` results. */
5
5
  export const defaultCodeModeSearchLimit = 8
@@ -15,6 +15,8 @@ export type CodeModeSearchHit = {
15
15
  */
16
16
  readonly name: string
17
17
  readonly description: string
18
+ /** The call with its argument and result types (`codeModeToolSignature`), bounded. */
19
+ readonly signature: string
18
20
  /** A stage-only tool (ADR 0007): no `tools` binding, only `stage()` it. */
19
21
  readonly stageOnly?: true
20
22
  }
@@ -36,8 +38,17 @@ export const searchCodeModeTools = (
36
38
 
37
39
  const hit = (tool: CodeModeCatalogTool): CodeModeSearchHit =>
38
40
  tool.exposure === 'stage'
39
- ? { name: tool.name, description: tool.description, stageOnly: true }
40
- : { name: tool.identifier, description: tool.description }
41
+ ? {
42
+ name: tool.name,
43
+ description: tool.description,
44
+ signature: codeModeToolSignature(tool),
45
+ stageOnly: true
46
+ }
47
+ : {
48
+ name: tool.identifier,
49
+ description: tool.description,
50
+ signature: codeModeToolSignature(tool)
51
+ }
41
52
 
42
53
  return rankToolSearchDocuments(
43
54
  scoped.map(tool => ({
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 stage-only tool. */
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 stage-only tool rejects with a hint to stage it (ADR 0007). */
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.`