@opencode/codemode 0.0.0-dev-19678 → 0.0.0-dev-19682

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/codemode.js CHANGED
@@ -71,7 +71,9 @@ export const make = (options = {}) => {
71
71
  }
72
72
  }
73
73
  return {
74
- catalog: prepared.catalog,
74
+ get catalog() {
75
+ return prepared.catalog;
76
+ },
75
77
  execute: (code) => executeProgram(code, prepared, limits, options.hooks ?? {}, (ctx) => extensionGlobals(ctx, extensions)),
76
78
  };
77
79
  };
@@ -58,7 +58,7 @@ type ToolNode<R> = {
58
58
  namespace?: Namespace<R>;
59
59
  readonly children: Map<string, ToolNode<R>>;
60
60
  };
61
- /** Tools indexed once per runtime: the lookup trie plus the model-facing catalog and search index. */
61
+ /** Tools indexed once per runtime, with discovery materialized on demand. */
62
62
  export type Prepared<R = never> = {
63
63
  readonly root: ToolNode<R>;
64
64
  readonly catalog: ReadonlyArray<ToolDescription>;
@@ -80,13 +80,22 @@ const flattenTools = (node, path = [], namespaces = []) => {
80
80
  ...Array.from(node.children).flatMap(([name, child]) => flattenTools(child, [...path, name], next)),
81
81
  ];
82
82
  };
83
- const describeTool = (visible) => ({
84
- path: visible.path,
85
- description: visible.tool.description,
86
- signature: isEmptyInput(visible.tool)
87
- ? `${toolExpression(visible.path)}(): Promise<${outputTypeScript(visible.tool, true)}>`
88
- : `${toolExpression(visible.path)}(input: ${inputTypeScript(visible.tool, true)}): Promise<${outputTypeScript(visible.tool, true)}>`,
89
- });
83
+ const describeTool = (visible) => {
84
+ let signature;
85
+ return {
86
+ path: visible.path,
87
+ description: visible.tool.description,
88
+ get signature() {
89
+ // Search ranks paths and descriptions first; only returned matches need their schemas rendered.
90
+ // Joining the final fragments avoids retaining the rendering's intermediate string ropes in JSC.
91
+ return (signature ??= [
92
+ toolExpression(visible.path),
93
+ isEmptyInput(visible.tool) ? "()" : `(input: ${inputTypeScript(visible.tool, true)})`,
94
+ `: Promise<${outputTypeScript(visible.tool, true)}>`,
95
+ ].join(""));
96
+ },
97
+ };
98
+ };
90
99
  const tokenize = (query) => query
91
100
  .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
92
101
  .toLowerCase()
@@ -165,12 +174,20 @@ const toSearchEntry = (visible) => ({
165
174
  });
166
175
  export const prepare = (tools) => {
167
176
  const root = toolTrie(tools);
168
- // Discovery bytes are durable instructions, so order only after canonical-path collisions settle.
169
- const visible = flattenTools(root).sort((left, right) => compareText(left.path, right.path));
177
+ let searchIndex;
178
+ let catalog;
170
179
  return {
171
180
  root,
172
- catalog: visible.map(describeTool),
173
- searchIndex: visible.map(toSearchEntry),
181
+ get catalog() {
182
+ return (catalog ??= this.searchIndex.map((entry) => entry.description));
183
+ },
184
+ get searchIndex() {
185
+ // Executing known tools only needs the trie. Render discovery when it is actually read,
186
+ // ordering after canonical-path collisions settle so instruction bytes stay deterministic.
187
+ return (searchIndex ??= flattenTools(root)
188
+ .sort((left, right) => compareText(left.path, right.path))
189
+ .map(toSearchEntry));
190
+ },
174
191
  };
175
192
  };
176
193
  const lookup = (root, segments) => segments.reduce((node, segment) => node?.children.get(segment), root);
@@ -209,7 +226,6 @@ export class ToolRuntimeError extends Error {
209
226
  export const make = (prepared, maxToolCalls, hooks = {}) => {
210
227
  const calls = [];
211
228
  const root = prepared.root;
212
- const searchTool = makeSearchTool(prepared.searchIndex);
213
229
  const recordCall = (call) => {
214
230
  if (maxToolCalls !== undefined && calls.length >= maxToolCalls) {
215
231
  throw new ToolRuntimeError("ToolCallLimitExceeded", `Execution exceeded its tool-call limit of ${maxToolCalls}.`);
@@ -247,12 +263,12 @@ export const make = (prepared, maxToolCalls, hooks = {}) => {
247
263
  calls,
248
264
  hooks,
249
265
  keys: (path) => namespaceKeys(root, path),
250
- search: (args) => Effect.suspend(() => executeTool("search", searchTool, args)),
266
+ search: (args) => Effect.suspend(() => executeTool("search", makeSearchTool(prepared.searchIndex), args)),
251
267
  execute: (path, args) => Effect.suspend(() => {
252
268
  const segments = canonicalSegments(path);
253
269
  // Models often write `tools.search(...)` for the bare `search(...)`; honor it unless a tool owns that path.
254
270
  if (segments.length === 1 && segments[0] === "search" && lookup(root, segments) === undefined)
255
- return executeTool("search", searchTool, args);
271
+ return executeTool("search", makeSearchTool(prepared.searchIndex), args);
256
272
  return executeTool(segments.join("."), resolve(root, path), args);
257
273
  }),
258
274
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@opencode/codemode",
4
- "version": "0.0.0-dev-19678",
4
+ "version": "0.0.0-dev-19682",
5
5
  "description": "Effect-native confined code execution over schema-described tools",
6
6
  "type": "module",
7
7
  "license": "MIT",