@opencode/codemode 0.0.0-beta-19507 → 0.0.0-dev-19274

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.
Files changed (65) hide show
  1. package/README.md +0 -6
  2. package/dist/codemode.d.ts +12 -9
  3. package/dist/codemode.js +9 -5
  4. package/dist/index.d.ts +0 -1
  5. package/dist/index.js +0 -1
  6. package/dist/interpreter/errors.d.ts +6 -4
  7. package/dist/interpreter/errors.js +10 -25
  8. package/dist/interpreter/execute.d.ts +3 -4
  9. package/dist/interpreter/execute.js +18 -11
  10. package/dist/interpreter/iterator.d.ts +13 -0
  11. package/dist/interpreter/iterator.js +4 -0
  12. package/dist/interpreter/methods.d.ts +16 -3
  13. package/dist/interpreter/methods.js +290 -101
  14. package/dist/interpreter/model.d.ts +79 -10
  15. package/dist/interpreter/model.js +102 -2
  16. package/dist/interpreter/promises.d.ts +13 -15
  17. package/dist/interpreter/promises.js +52 -70
  18. package/dist/interpreter/references.d.ts +0 -1
  19. package/dist/interpreter/references.js +77 -57
  20. package/dist/interpreter/runtime.d.ts +95 -16
  21. package/dist/interpreter/runtime.js +960 -549
  22. package/dist/openapi/spec.js +6 -3
  23. package/dist/stdlib/collections.d.ts +1 -6
  24. package/dist/stdlib/collections.js +1 -117
  25. package/dist/stdlib/console.d.ts +2 -3
  26. package/dist/stdlib/console.js +28 -39
  27. package/dist/stdlib/date.d.ts +4 -5
  28. package/dist/stdlib/date.js +12 -34
  29. package/dist/stdlib/json.d.ts +6 -3
  30. package/dist/stdlib/json.js +63 -40
  31. package/dist/stdlib/math.d.ts +7 -3
  32. package/dist/stdlib/math.js +153 -85
  33. package/dist/stdlib/number.d.ts +4 -2
  34. package/dist/stdlib/number.js +37 -30
  35. package/dist/stdlib/object.d.ts +6 -6
  36. package/dist/stdlib/object.js +87 -84
  37. package/dist/stdlib/promise.d.ts +2 -0
  38. package/dist/stdlib/promise.js +1 -0
  39. package/dist/stdlib/regexp.d.ts +7 -6
  40. package/dist/stdlib/regexp.js +34 -48
  41. package/dist/stdlib/string.d.ts +3 -1
  42. package/dist/stdlib/string.js +17 -20
  43. package/dist/stdlib/url.d.ts +6 -10
  44. package/dist/stdlib/url.js +25 -102
  45. package/dist/stdlib/value.d.ts +7 -8
  46. package/dist/stdlib/value.js +56 -56
  47. package/dist/tool-runtime.d.ts +15 -16
  48. package/dist/tool-runtime.js +150 -13
  49. package/dist/values.d.ts +16 -22
  50. package/dist/values.js +17 -23
  51. package/package.json +1 -1
  52. package/dist/data.d.ts +0 -25
  53. package/dist/data.js +0 -153
  54. package/dist/interpreter/globals.d.ts +0 -13
  55. package/dist/interpreter/globals.js +0 -63
  56. package/dist/interpreter/host.d.ts +0 -41
  57. package/dist/interpreter/host.js +0 -44
  58. package/dist/interpreter/objects.d.ts +0 -37
  59. package/dist/interpreter/objects.js +0 -151
  60. package/dist/interpreter/runner.d.ts +0 -24
  61. package/dist/interpreter/runner.js +0 -45
  62. package/dist/stdlib/array.d.ts +0 -3
  63. package/dist/stdlib/array.js +0 -68
  64. package/dist/stdlib/web.d.ts +0 -4
  65. package/dist/stdlib/web.js +0 -20
@@ -1,10 +1,10 @@
1
1
  import { Cause, Effect, Exit, Formatter, Schema } from "effect";
2
- import { fromData, toData, ToolRuntimeError } from "./data.js";
3
2
  import { toolError } from "./tool-error.js";
4
3
  import { decodeInput as decodeToolInput, decodeOutput as decodeToolOutput, identifierSegment, inputProperties, inputTypeScript, isEmptyInput, outputTypeScript, } from "./tool-schema.js";
5
4
  import { isNamespace } from "./namespace.js";
6
5
  import { isTool } from "./tool.js";
7
- export const compareText = (left, right) => (left < right ? -1 : left > right ? 1 : 0);
6
+ import { CodeModeDate, CodeModeMap, CodeModePromise, CodeModeRegExp, CodeModeSet, CodeModeURL, CodeModeURLSearchParams, } from "./values.js";
7
+ const compareText = (left, right) => (left < right ? -1 : left > right ? 1 : 0);
8
8
  const defaultSearchLimit = 10;
9
9
  const PositiveInt = Schema.Int.check(Schema.isGreaterThan(0));
10
10
  const NonNegativeInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
@@ -35,6 +35,143 @@ export class ToolReference {
35
35
  this.path = path;
36
36
  }
37
37
  }
38
+ const MAX_VALUE_DEPTH = 32;
39
+ export class ToolRuntimeError extends Error {
40
+ kind;
41
+ suggestions;
42
+ constructor(kind, message, suggestions = []) {
43
+ super(message);
44
+ this.kind = kind;
45
+ this.suggestions = suggestions;
46
+ this.name = "ToolRuntimeError";
47
+ }
48
+ }
49
+ const blockedMemberNames = new Set(["__proto__", "constructor", "prototype"]);
50
+ export const isBlockedMember = (name) => blockedMemberNames.has(name);
51
+ // Checkpoint mode preserves CodeMode values; boundary mode JSON-normalizes them.
52
+ export const copyIn = (value, label, preserveCodeModeValues = false) => copyBounded(value, label, 0, new Set(), preserveCodeModeValues);
53
+ const copyBounded = (value, label, depth, seen, preserveCodeModeValues) => {
54
+ if (depth > MAX_VALUE_DEPTH) {
55
+ throw new ToolRuntimeError("InvalidDataValue", `${label} exceeds the maximum value depth of ${MAX_VALUE_DEPTH}.`);
56
+ }
57
+ if (value === null ||
58
+ value === undefined ||
59
+ typeof value === "string" ||
60
+ typeof value === "boolean" ||
61
+ typeof value === "number") {
62
+ return value;
63
+ }
64
+ if (typeof value !== "object") {
65
+ throw new ToolRuntimeError("InvalidDataValue", `${label} must contain data only.`);
66
+ }
67
+ if (value instanceof CodeModePromise) {
68
+ throw new ToolRuntimeError("InvalidDataValue", `${label} contains an un-awaited Promise; await tool calls (e.g. \`const result = await tools.ns.tool(...)\`) before using their results.`);
69
+ }
70
+ if (preserveCodeModeValues) {
71
+ if (value instanceof CodeModeDate ||
72
+ value instanceof CodeModeRegExp ||
73
+ value instanceof CodeModeMap ||
74
+ value instanceof CodeModeSet ||
75
+ value instanceof CodeModeURL ||
76
+ value instanceof CodeModeURLSearchParams) {
77
+ return value;
78
+ }
79
+ if (value instanceof Date)
80
+ return new CodeModeDate(value.getTime());
81
+ if (value instanceof RegExp)
82
+ return new CodeModeRegExp(value.source, value.flags);
83
+ if (value instanceof Map) {
84
+ const wrapped = new CodeModeMap();
85
+ for (const [key, item] of value.entries()) {
86
+ wrapped.map.set(copyBounded(key, label, depth + 1, seen, true), copyBounded(item, label, depth + 1, seen, true));
87
+ }
88
+ return wrapped;
89
+ }
90
+ if (value instanceof Set) {
91
+ const wrapped = new CodeModeSet();
92
+ for (const item of value.values())
93
+ wrapped.set.add(copyBounded(item, label, depth + 1, seen, true));
94
+ return wrapped;
95
+ }
96
+ if (value instanceof URL)
97
+ return new CodeModeURL(new URL(value.href));
98
+ if (value instanceof URLSearchParams)
99
+ return new CodeModeURLSearchParams(new URLSearchParams(value));
100
+ }
101
+ if (value instanceof CodeModeDate) {
102
+ return Number.isFinite(value.time) ? new Date(value.time).toISOString() : null;
103
+ }
104
+ if (value instanceof Date) {
105
+ return Number.isFinite(value.getTime()) ? value.toISOString() : null;
106
+ }
107
+ if (value instanceof CodeModeURL)
108
+ return value.url.href;
109
+ if (value instanceof URL)
110
+ return value.href;
111
+ if (value instanceof CodeModeRegExp ||
112
+ value instanceof CodeModeMap ||
113
+ value instanceof CodeModeSet ||
114
+ value instanceof CodeModeURLSearchParams ||
115
+ value instanceof RegExp ||
116
+ value instanceof Map ||
117
+ value instanceof Set ||
118
+ value instanceof URLSearchParams) {
119
+ return Object.create(null);
120
+ }
121
+ if (seen.has(value)) {
122
+ throw new ToolRuntimeError("InvalidDataValue", `${label} contains a circular value.`);
123
+ }
124
+ seen.add(value);
125
+ if (Array.isArray(value)) {
126
+ const copied = value.map((item) => copyBounded(item, label, depth + 1, seen, preserveCodeModeValues));
127
+ if (preserveCodeModeValues) {
128
+ // Checkpoint copies retain array metadata that boundary copies omit.
129
+ for (const [key, item] of Object.entries(value)) {
130
+ if (Object.hasOwn(copied, key))
131
+ continue;
132
+ if (isBlockedMember(key)) {
133
+ throw new ToolRuntimeError("InvalidDataValue", `${label} contains blocked property '${key}'.`);
134
+ }
135
+ Reflect.set(copied, key, copyBounded(item, label, depth + 1, seen, true));
136
+ }
137
+ }
138
+ seen.delete(value);
139
+ return copied;
140
+ }
141
+ const prototype = Object.getPrototypeOf(value);
142
+ if (prototype !== Object.prototype && prototype !== null) {
143
+ throw new ToolRuntimeError("InvalidDataValue", `${label} must contain plain objects only.`);
144
+ }
145
+ const copied = Object.create(null);
146
+ for (const [key, item] of Object.entries(value)) {
147
+ if (isBlockedMember(key)) {
148
+ throw new ToolRuntimeError("InvalidDataValue", `${label} contains blocked property '${key}'.`);
149
+ }
150
+ copied[key] = copyBounded(item, label, depth + 1, seen, preserveCodeModeValues);
151
+ }
152
+ seen.delete(value);
153
+ return copied;
154
+ };
155
+ export const copyOut = (value, mode) => {
156
+ if (value === undefined && mode === "nullify")
157
+ return null;
158
+ if (typeof value === "number" && !Number.isFinite(value)) {
159
+ return null;
160
+ }
161
+ if (Array.isArray(value)) {
162
+ // Array.from densifies holes so sparse arrays normalize at the boundary like JSON does.
163
+ return Array.from(value, (item) => {
164
+ const copied = copyOut(item, mode);
165
+ return copied === undefined && mode === "json" ? null : copied;
166
+ });
167
+ }
168
+ if (value !== null && typeof value === "object" && !(value instanceof ToolReference)) {
169
+ return Object.fromEntries(Object.entries(value)
170
+ .map(([key, item]) => [key, copyOut(item, mode)])
171
+ .filter(([, item]) => !(item === undefined && mode === "json")));
172
+ }
173
+ return value;
174
+ };
38
175
  const toolTrie = (tools) => {
39
176
  const root = { children: new Map() };
40
177
  const insert = (node, group) => {
@@ -75,6 +212,8 @@ const describeTool = (visible) => ({
75
212
  ? `${toolExpression(visible.path)}(): Promise<${outputTypeScript(visible.tool, true)}>`
76
213
  : `${toolExpression(visible.path)}(input: ${inputTypeScript(visible.tool, true)}): Promise<${outputTypeScript(visible.tool, true)}>`,
77
214
  });
215
+ // Discovery bytes are durable instructions, so order only after canonical-path collisions settle.
216
+ const visibleTools = (tools) => flattenTools(toolTrie(tools)).sort((left, right) => compareText(left.path, right.path));
78
217
  const tokenize = (query) => query
79
218
  .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
80
219
  .toLowerCase()
@@ -151,12 +290,10 @@ const toSearchEntry = (visible) => ({
151
290
  .join("\n")
152
291
  .toLowerCase(),
153
292
  });
293
+ export const searchIndex = (tools) => visibleTools(tools).map(toSearchEntry);
154
294
  export const prepare = (tools) => {
155
- const root = toolTrie(tools);
156
- // Discovery bytes are durable instructions, so order only after canonical-path collisions settle.
157
- const visible = flattenTools(root).sort((left, right) => compareText(left.path, right.path));
295
+ const visible = visibleTools(tools);
158
296
  return {
159
- root,
160
297
  catalog: visible.map(describeTool),
161
298
  searchIndex: visible.map(toSearchEntry),
162
299
  };
@@ -183,11 +320,10 @@ const resolve = (root, path) => {
183
320
  }
184
321
  return node.tool;
185
322
  };
186
- /** Per-execution call state over tools prepared once for the runtime. */
187
- export const make = (prepared, maxToolCalls, hooks) => {
323
+ export const make = (tools, maxToolCalls, searchIndex, hooks) => {
188
324
  const calls = [];
189
- const root = prepared.root;
190
- const searchTool = makeSearchTool(prepared.searchIndex);
325
+ const root = toolTrie(tools);
326
+ const searchTool = makeSearchTool(searchIndex);
191
327
  const observeEnd = (effect, call) => {
192
328
  const onEnd = hooks?.onToolCallEnd;
193
329
  if (onEnd === undefined)
@@ -234,18 +370,19 @@ export const make = (prepared, maxToolCalls, hooks) => {
234
370
  .join("\n")));
235
371
  }));
236
372
  return yield* Effect.try({
237
- try: () => fromData(decodeToolOutput(tool, raw), `Result from tool '${name}'`),
373
+ try: () => copyIn(decodeToolOutput(tool, raw), `Result from tool '${name}'`),
238
374
  catch: (cause) => new ToolRuntimeError("InvalidToolOutput", `Invalid output from tool '${name}': ${cause}`),
239
375
  });
240
376
  }), call);
241
377
  });
242
378
  return {
379
+ root: new ToolReference([]),
243
380
  calls,
244
381
  keys: (path) => namespaceKeys(root, path),
245
- search: (args) => Effect.suspend(() => executeTool("search", searchTool, args.map((arg) => toData(arg, "Arguments for tool 'search'")))),
382
+ search: (args) => Effect.suspend(() => executeTool("search", searchTool, args.map((arg) => copyOut(copyIn(arg, "Arguments for tool 'search'"), "json")))),
246
383
  execute: (path, args) => Effect.gen(function* () {
247
384
  const name = canonicalSegments(path).join(".");
248
- const externalArgs = args.map((arg) => toData(arg, `Arguments for tool '${name}'`));
385
+ const externalArgs = args.map((arg) => copyOut(copyIn(arg, `Arguments for tool '${name}'`), "json"));
249
386
  const tool = resolve(root, path);
250
387
  return yield* executeTool(name, tool, externalArgs);
251
388
  }),
package/dist/values.d.ts CHANGED
@@ -1,37 +1,31 @@
1
- export * as Values from "./values.js";
2
1
  import type { Fiber } from "effect";
3
- /**
4
- * Runtime values the interpreter recognizes by class. Each wraps the host value it stands for,
5
- * so hosts construct these to hand a value to a program and receive them back unchanged.
6
- */
7
- export declare class Promise {
2
+ export declare class CodeModePromise {
8
3
  readonly fiber: Fiber.Fiber<unknown, unknown>;
9
4
  constructor(fiber: Fiber.Fiber<unknown, unknown>);
10
5
  }
11
- export declare class Date {
6
+ export declare class CodeModeDate {
12
7
  time: number;
13
8
  constructor(time: number);
14
9
  }
15
- export declare class RegExp {
16
- readonly regex: globalThis.RegExp;
10
+ export declare class CodeModeRegExp {
11
+ readonly regex: RegExp;
17
12
  constructor(pattern: string, flags: string);
18
13
  get lastIndex(): unknown;
19
14
  set lastIndex(value: unknown);
20
15
  }
21
- export declare class Map {
22
- readonly map: globalThis.Map<unknown, unknown>;
16
+ export declare class CodeModeMap {
17
+ readonly map: Map<unknown, unknown>;
23
18
  }
24
- export declare class Set {
25
- readonly set: globalThis.Set<unknown>;
19
+ export declare class CodeModeSet {
20
+ readonly set: Set<unknown>;
26
21
  }
27
- export declare class URLSearchParams {
28
- readonly params: globalThis.URLSearchParams;
29
- constructor(params: globalThis.URLSearchParams);
22
+ export declare class CodeModeURLSearchParams {
23
+ readonly params: URLSearchParams;
24
+ constructor(params: URLSearchParams);
30
25
  }
31
- export declare class URL {
32
- readonly url: globalThis.URL;
33
- readonly searchParams: URLSearchParams;
34
- constructor(url: globalThis.URL);
26
+ export declare class CodeModeURL {
27
+ readonly url: URL;
28
+ readonly searchParams: CodeModeURLSearchParams;
29
+ constructor(url: URL);
35
30
  }
36
- /** Data-like runtime values; excludes Promise, which never crosses a boundary. */
37
- export declare const isValue: (value: unknown) => value is Date | RegExp | Map | Set | URL | URLSearchParams;
31
+ export declare const isCodeModeValue: (value: unknown) => value is CodeModeDate | CodeModeRegExp | CodeModeMap | CodeModeSet | CodeModeURL | CodeModeURLSearchParams;
package/dist/values.js CHANGED
@@ -1,24 +1,19 @@
1
- export * as Values from "./values.js";
2
- /**
3
- * Runtime values the interpreter recognizes by class. Each wraps the host value it stands for,
4
- * so hosts construct these to hand a value to a program and receive them back unchanged.
5
- */
6
- export class Promise {
1
+ export class CodeModePromise {
7
2
  fiber;
8
3
  constructor(fiber) {
9
4
  this.fiber = fiber;
10
5
  }
11
6
  }
12
- export class Date {
7
+ export class CodeModeDate {
13
8
  time;
14
9
  constructor(time) {
15
10
  this.time = time;
16
11
  }
17
12
  }
18
- export class RegExp {
13
+ export class CodeModeRegExp {
19
14
  regex;
20
15
  constructor(pattern, flags) {
21
- this.regex = new globalThis.RegExp(pattern, flags);
16
+ this.regex = new RegExp(pattern, flags);
22
17
  }
23
18
  get lastIndex() {
24
19
  return Reflect.get(this.regex, "lastIndex");
@@ -27,30 +22,29 @@ export class RegExp {
27
22
  Reflect.set(this.regex, "lastIndex", value);
28
23
  }
29
24
  }
30
- export class Map {
31
- map = new globalThis.Map();
25
+ export class CodeModeMap {
26
+ map = new Map();
32
27
  }
33
- export class Set {
34
- set = new globalThis.Set();
28
+ export class CodeModeSet {
29
+ set = new Set();
35
30
  }
36
- export class URLSearchParams {
31
+ export class CodeModeURLSearchParams {
37
32
  params;
38
33
  constructor(params) {
39
34
  this.params = params;
40
35
  }
41
36
  }
42
- export class URL {
37
+ export class CodeModeURL {
43
38
  url;
44
39
  searchParams;
45
40
  constructor(url) {
46
41
  this.url = url;
47
- this.searchParams = new URLSearchParams(url.searchParams);
42
+ this.searchParams = new CodeModeURLSearchParams(url.searchParams);
48
43
  }
49
44
  }
50
- /** Data-like runtime values; excludes Promise, which never crosses a boundary. */
51
- export const isValue = (value) => value instanceof Date ||
52
- value instanceof RegExp ||
53
- value instanceof Map ||
54
- value instanceof Set ||
55
- value instanceof URL ||
56
- value instanceof URLSearchParams;
45
+ export const isCodeModeValue = (value) => value instanceof CodeModeDate ||
46
+ value instanceof CodeModeRegExp ||
47
+ value instanceof CodeModeMap ||
48
+ value instanceof CodeModeSet ||
49
+ value instanceof CodeModeURL ||
50
+ value instanceof CodeModeURLSearchParams;
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-beta-19507",
4
+ "version": "0.0.0-dev-19274",
5
5
  "description": "Effect-native confined code execution over schema-described tools",
6
6
  "type": "module",
7
7
  "license": "MIT",
package/dist/data.d.ts DELETED
@@ -1,25 +0,0 @@
1
- export * as Data from "./data.js";
2
- import type { DiagnosticKind } from "./codemode.js";
3
- export declare class ToolRuntimeError extends Error {
4
- readonly kind: Extract<DiagnosticKind, "UnknownTool" | "InvalidToolInput" | "InvalidToolOutput" | "InvalidDataValue" | "ToolCallLimitExceeded">;
5
- readonly suggestions: ReadonlyArray<string>;
6
- constructor(kind: Extract<DiagnosticKind, "UnknownTool" | "InvalidToolInput" | "InvalidToolOutput" | "InvalidDataValue" | "ToolCallLimitExceeded">, message: string, suggestions?: ReadonlyArray<string>);
7
- }
8
- /**
9
- * Brings a host-produced value into the program: program and runtime values pass through, their
10
- * host counterparts (Date, RegExp, Map, Set, URL, URLSearchParams) are wrapped, and host objects
11
- * and arrays are copied.
12
- */
13
- export declare const toProgram: (value: unknown, label: string) => unknown;
14
- /**
15
- * Brings host data into the program: Date and URL become strings, other host collections become
16
- * empty objects, and objects become program copies. Used for tool results and parsed JSON.
17
- */
18
- export declare const fromData: (value: unknown, label: string) => unknown;
19
- /**
20
- * Takes a program value out as plain JSON: runtime values serialize like `JSON.stringify` would,
21
- * non-finite numbers become null, and array holes become null. `undefined` object properties are
22
- * dropped ("json") or become null ("result", for program results where the consumer must never see
23
- * undefined); a bare `undefined` follows the same rule.
24
- */
25
- export declare const toData: (value: unknown, label: string, undefinedAs?: "json" | "result") => unknown;
package/dist/data.js DELETED
@@ -1,153 +0,0 @@
1
- export * as Data from "./data.js";
2
- import { ownEntries, parseArrayIndex, ProgramArray, ProgramFunction, ProgramObject, set, } from "./interpreter/objects.js";
3
- import { Values } from "./values.js";
4
- const MAX_VALUE_DEPTH = 32;
5
- export class ToolRuntimeError extends Error {
6
- kind;
7
- suggestions;
8
- constructor(kind, message, suggestions = []) {
9
- super(message);
10
- this.kind = kind;
11
- this.suggestions = suggestions;
12
- this.name = "ToolRuntimeError";
13
- }
14
- }
15
- /**
16
- * Brings a host-produced value into the program: program and runtime values pass through, their
17
- * host counterparts (Date, RegExp, Map, Set, URL, URLSearchParams) are wrapped, and host objects
18
- * and arrays are copied.
19
- */
20
- export const toProgram = (value, label) => copy(value, label, "program", 0, new Set());
21
- /**
22
- * Brings host data into the program: Date and URL become strings, other host collections become
23
- * empty objects, and objects become program copies. Used for tool results and parsed JSON.
24
- */
25
- export const fromData = (value, label) => copy(value, label, "data", 0, new Set());
26
- /**
27
- * Takes a program value out as plain JSON: runtime values serialize like `JSON.stringify` would,
28
- * non-finite numbers become null, and array holes become null. `undefined` object properties are
29
- * dropped ("json") or become null ("result", for program results where the consumer must never see
30
- * undefined); a bare `undefined` follows the same rule.
31
- */
32
- export const toData = (value, label, undefinedAs = "json") => copy(value, label, undefinedAs, 0, new Set());
33
- const copy = (value, label, mode, depth, seen) => {
34
- if (depth > MAX_VALUE_DEPTH) {
35
- throw new ToolRuntimeError("InvalidDataValue", `${label} exceeds the maximum value depth of ${MAX_VALUE_DEPTH}.`);
36
- }
37
- if (value === undefined)
38
- return mode === "result" ? null : undefined;
39
- if (typeof value === "number")
40
- return (mode === "json" || mode === "result") && !Number.isFinite(value) ? null : value;
41
- if (value === null || typeof value === "string" || typeof value === "boolean")
42
- return value;
43
- if (typeof value !== "object") {
44
- throw new ToolRuntimeError("InvalidDataValue", `${label} must contain data only.`);
45
- }
46
- if (value instanceof Values.Promise) {
47
- throw new ToolRuntimeError("InvalidDataValue", `${label} contains an un-awaited Promise; await tool calls (e.g. \`const result = await tools.ns.tool(...)\`) before using their results.`);
48
- }
49
- if (value instanceof ProgramFunction && mode !== "program") {
50
- throw new ToolRuntimeError("InvalidDataValue", `${label} must contain data only.`);
51
- }
52
- const plain = mode === "program" || mode === "data";
53
- if (mode === "program") {
54
- if (value instanceof ProgramObject || Values.isValue(value))
55
- return value;
56
- if (value instanceof Date)
57
- return new Values.Date(value.getTime());
58
- if (value instanceof RegExp)
59
- return new Values.RegExp(value.source, value.flags);
60
- if (value instanceof Map) {
61
- const wrapped = new Values.Map();
62
- for (const [key, item] of value.entries()) {
63
- wrapped.map.set(copy(key, label, mode, depth + 1, seen), copy(item, label, mode, depth + 1, seen));
64
- }
65
- return wrapped;
66
- }
67
- if (value instanceof Set) {
68
- const wrapped = new Values.Set();
69
- for (const item of value.values())
70
- wrapped.set.add(copy(item, label, mode, depth + 1, seen));
71
- return wrapped;
72
- }
73
- if (value instanceof URL)
74
- return new Values.URL(new URL(value.href));
75
- if (value instanceof URLSearchParams)
76
- return new Values.URLSearchParams(new URLSearchParams(value));
77
- }
78
- if (value instanceof Values.Date)
79
- return Number.isFinite(value.time) ? new Date(value.time).toISOString() : null;
80
- if (value instanceof Date)
81
- return Number.isFinite(value.getTime()) ? value.toISOString() : null;
82
- if (value instanceof Values.URL)
83
- return value.url.href;
84
- if (value instanceof URL)
85
- return value.href;
86
- // Remaining runtime values and their host counterparts serialize as empty objects, like JSON.stringify.
87
- if (Values.isValue(value) ||
88
- value instanceof RegExp ||
89
- value instanceof Map ||
90
- value instanceof Set ||
91
- value instanceof URLSearchParams) {
92
- return plain ? new ProgramObject() : {};
93
- }
94
- if (seen.has(value)) {
95
- throw new ToolRuntimeError("InvalidDataValue", `${label} contains a circular value.`);
96
- }
97
- seen.add(value);
98
- if (value instanceof ProgramArray) {
99
- const copied = Array.from(value.items, (item) => copy(item, label, mode, depth + 1, seen) ?? null);
100
- seen.delete(value);
101
- return copied;
102
- }
103
- if (value instanceof ProgramObject) {
104
- const copied = {};
105
- for (const [key, item] of ownEntries(value)) {
106
- const next = copy(item, label, mode, depth + 1, seen);
107
- if (next === undefined && mode === "json")
108
- continue;
109
- define(copied, key, next);
110
- }
111
- seen.delete(value);
112
- return copied;
113
- }
114
- if (Array.isArray(value)) {
115
- if (plain) {
116
- const copied = new ProgramArray(value.map((item) => copy(item, label, mode, depth + 1, seen)));
117
- for (const [key, item] of Object.entries(value)) {
118
- if (parseArrayIndex(key) === undefined)
119
- set(copied, key, copy(item, label, mode, depth + 1, seen));
120
- }
121
- seen.delete(value);
122
- return copied;
123
- }
124
- const copied = Array.from(value, (item) => copy(item, label, mode, depth + 1, seen) ?? null);
125
- seen.delete(value);
126
- return copied;
127
- }
128
- const prototype = Object.getPrototypeOf(value);
129
- if (prototype !== Object.prototype && prototype !== null) {
130
- throw new ToolRuntimeError("InvalidDataValue", `${label} must contain plain objects only.`);
131
- }
132
- if (plain) {
133
- const copied = new ProgramObject();
134
- for (const [key, item] of Object.entries(value))
135
- set(copied, key, copy(item, label, mode, depth + 1, seen));
136
- seen.delete(value);
137
- return copied;
138
- }
139
- const copied = {};
140
- for (const [key, item] of Object.entries(value)) {
141
- const next = copy(item, label, mode, depth + 1, seen);
142
- if (next === undefined && mode === "json")
143
- continue;
144
- define(copied, key, next);
145
- }
146
- seen.delete(value);
147
- return copied;
148
- };
149
- // Own data property regardless of the target's prototype, so a "__proto__" key on a host object
150
- // never reaches the Object.prototype setter.
151
- const define = (target, key, value) => {
152
- Object.defineProperty(target, key, { value, enumerable: true, writable: true, configurable: true });
153
- };
@@ -1,13 +0,0 @@
1
- import { Effect } from "effect";
2
- import { type PromiseRuntime } from "./promises.js";
3
- import type { Runner } from "./runner.js";
4
- /** What the built-in globals need from the interpreter that owns them. */
5
- export type Host<R> = {
6
- readonly runner: Runner<R>;
7
- readonly promises: PromiseRuntime<R>;
8
- readonly search: (args: Array<unknown>) => Effect.Effect<unknown, unknown, R>;
9
- readonly toolKeys: (path: ReadonlyArray<string>) => ReadonlyArray<string>;
10
- readonly logs: Array<string>;
11
- };
12
- /** The immutable global bindings of every program, in declaration order. */
13
- export declare const globals: <R>(host: Host<R>) => ReadonlyArray<readonly [string, unknown]>;
@@ -1,63 +0,0 @@
1
- import { Effect } from "effect";
2
- import { arrayGlobal } from "../stdlib/array.js";
3
- import { mapGlobal, setGlobal } from "../stdlib/collections.js";
4
- import { consoleGlobal } from "../stdlib/console.js";
5
- import { dateGlobal } from "../stdlib/date.js";
6
- import { jsonGlobal } from "../stdlib/json.js";
7
- import { mathGlobal } from "../stdlib/math.js";
8
- import { numberGlobal } from "../stdlib/number.js";
9
- import { objectGlobal } from "../stdlib/object.js";
10
- import { regexpGlobal } from "../stdlib/regexp.js";
11
- import { stringGlobal } from "../stdlib/string.js";
12
- import { uriGlobal, urlGlobal, urlSearchParamsGlobal } from "../stdlib/url.js";
13
- import { coercion, errorConstructors } from "../stdlib/value.js";
14
- import { atobGlobal, btoaGlobal, cryptoGlobal } from "../stdlib/web.js";
15
- import { ToolReference } from "../tool-runtime.js";
16
- import { errorGlobal } from "./errors.js";
17
- import { HostFunction } from "./host.js";
18
- import { AsyncIteratorSymbol, InterpreterRuntimeError, IteratorSymbol } from "./model.js";
19
- import { promiseGlobal } from "./promises.js";
20
- const symbolGlobal = new HostFunction({
21
- name: "Symbol",
22
- call: (_, node) => Effect.sync(() => {
23
- throw new InterpreterRuntimeError("Symbol is not callable; only Symbol.asyncIterator and Symbol.iterator are available.", node).as("TypeError");
24
- }),
25
- callback: false,
26
- members: { asyncIterator: AsyncIteratorSymbol, iterator: IteratorSymbol },
27
- });
28
- /** The immutable global bindings of every program, in declaration order. */
29
- export const globals = (host) => [
30
- ["tools", new ToolReference([])],
31
- ["search", new HostFunction({ name: "search", call: (args) => host.search(args), callback: false })],
32
- ["undefined", undefined],
33
- ["NaN", NaN],
34
- ["Infinity", Infinity],
35
- ["Object", objectGlobal(host.runner, host.toolKeys)],
36
- ["Array", arrayGlobal(host.runner)],
37
- ["Math", mathGlobal(host.runner)],
38
- ["JSON", jsonGlobal(host.runner)],
39
- ["console", consoleGlobal(host.logs)],
40
- ["Promise", promiseGlobal(host.runner, host.promises)],
41
- ["Symbol", symbolGlobal],
42
- ["Number", numberGlobal],
43
- ["String", stringGlobal],
44
- ["Boolean", coercion("Boolean", { instanceOf: () => false })],
45
- ["parseInt", coercion("parseInt")],
46
- ["parseFloat", coercion("parseFloat")],
47
- ["isFinite", coercion("isFinite")],
48
- ["isNaN", coercion("isNaN")],
49
- ["Date", dateGlobal(host.runner)],
50
- ["RegExp", regexpGlobal],
51
- ["Map", mapGlobal(host.runner)],
52
- ["Set", setGlobal(host.runner)],
53
- ["URL", urlGlobal],
54
- ["URLSearchParams", urlSearchParamsGlobal(host.runner)],
55
- ["encodeURI", uriGlobal("encodeURI")],
56
- ["encodeURIComponent", uriGlobal("encodeURIComponent")],
57
- ["decodeURI", uriGlobal("decodeURI")],
58
- ["decodeURIComponent", uriGlobal("decodeURIComponent")],
59
- ["atob", atobGlobal],
60
- ["btoa", btoaGlobal],
61
- ["crypto", cryptoGlobal],
62
- ...[...errorConstructors].map((name) => [name, errorGlobal(name, host.runner)]),
63
- ];
@@ -1,41 +0,0 @@
1
- import { Effect } from "effect";
2
- import { type AstNode } from "./model.js";
3
- export type HostCall<R> = (args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
4
- type HostMember = (key: PropertyKey, node: AstNode) => unknown;
5
- type HostFunctionOptions<R> = {
6
- readonly name: string;
7
- readonly call: HostCall<R>;
8
- /** `new name(...)`; without it `new` is unsupported syntax. */
9
- readonly construct?: HostCall<R>;
10
- /** Static members read through `name.key`; unknown keys read as `undefined` unless the function decides otherwise. */
11
- readonly members?: Record<string, unknown> | HostMember;
12
- /** `value instanceof name`; without it the operator rejects this right-hand side. */
13
- readonly instanceOf?: (value: unknown) => boolean;
14
- /** Whether callback sites (array methods, replacers, promise reactions) admit this function. Defaults to true. */
15
- readonly callback?: boolean;
16
- };
17
- /** A host-implemented function value. `typeof` is "function". */
18
- export declare class HostFunction<R = never> {
19
- readonly name: string;
20
- readonly call: HostCall<R>;
21
- readonly construct: HostCall<R> | undefined;
22
- readonly member: HostMember;
23
- readonly instanceOf: ((value: unknown) => boolean) | undefined;
24
- readonly callback: boolean;
25
- constructor(options: HostFunctionOptions<R>);
26
- }
27
- /** A host-implemented object of static members. `typeof` is "object" and it is not callable. */
28
- export declare class HostNamespace {
29
- readonly name: string;
30
- readonly member: HostMember;
31
- constructor(name: string, members: Record<string, unknown> | HostMember);
32
- }
33
- export type SyncOptions = Omit<HostFunctionOptions<never>, "name" | "call">;
34
- type SyncImpl = (args: Array<unknown>, node: AstNode) => unknown;
35
- /** Lifts a synchronous implementation, which may throw `InterpreterRuntimeError`, into a host call. */
36
- export declare const syncCall: (impl: SyncImpl) => HostCall<never>;
37
- /** A synchronous host function. */
38
- export declare const sync: (name: string, impl: SyncImpl, options?: SyncOptions) => HostFunction<never>;
39
- /** The `call` of a constructor that JS requires to be invoked with `new`. */
40
- export declare const requiresNew: (name: string) => HostCall<never>;
41
- export {};