@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
package/README.md CHANGED
@@ -91,12 +91,6 @@ runtime.execute(source) // Effect<CodeMode.Result, never, ToolServices>
91
91
  The Effect environment is inferred from the supplied tools. `onToolCallStart` observes admitted calls with decoded
92
92
  input; `onToolCallEnd` observes settled outcomes and duration. Both hooks return Effects and must not fail.
93
93
 
94
- ### `Values`
95
-
96
- `Values` exports the runtime's non-JSON value classes: `Values.URL`, `Values.URLSearchParams`, `Values.Date`,
97
- `Values.RegExp`, `Values.Map`, `Values.Set`, and `Values.Promise`. The interpreter recognizes these by class; a
98
- program's `new URL(...)` is a `Values.URL` wrapping the host `URL`. `Values.isValue` narrows to the data-like kinds.
99
-
100
94
  ### OpenAPI tools
101
95
 
102
96
  `OpenAPI.fromSpec` converts an OpenAPI 3.x document into one tool per supported operation. Dotted `operationId` values
@@ -25,20 +25,23 @@ export type ResolvedExecutionLimits = {
25
25
  readonly maxToolCalls: number | undefined;
26
26
  readonly maxOutputBytes: number | undefined;
27
27
  };
28
- /** Configuration shared by `CodeMode.make` and `CodeMode.execute`. */
29
- export type Options<Provided extends Record<string, unknown> = {}> = ToolRuntime.ToolCallHooks<Services<Provided>> & {
30
- /** Explicit tools exposed to the program as `tools`. */
31
- tools?: Provided & Tools<Services<Provided>>;
32
- /** Resource limits enforced on each execution. */
33
- limits?: ExecutionLimits;
34
- };
35
28
  /** Options for one CodeMode execution. */
36
- export type ExecuteOptions<Provided extends Record<string, unknown> = {}> = Options<Provided> & {
29
+ export type ExecuteOptions<Provided extends Record<string, unknown> = {}> = {
37
30
  /** Source for one program in the supported JavaScript subset. */
38
31
  code: string;
32
+ /** Explicit tools exposed to the program as `tools`. */
33
+ tools?: Provided & Tools<Services<Provided>>;
34
+ /** Per-execution overrides for the default resource limits. */
35
+ limits?: ExecutionLimits;
36
+ /** Observes decoded tool input immediately before tool execution. */
37
+ onToolCallStart?: (call: ToolRuntime.ToolCallStarted) => Effect.Effect<void, never, Services<Provided>>;
38
+ /** Observes each admitted tool call as it succeeds, fails, or is interrupted. */
39
+ onToolCallEnd?: (call: ToolRuntime.ToolCallEnded) => Effect.Effect<void, never, Services<Provided>>;
39
40
  };
40
41
  /** A JSON value that can cross the confined interpreter boundary. */
41
42
  export type DataValue = Schema.Json;
43
+ /** Configuration shared by `CodeMode.make` and `CodeMode.execute`. */
44
+ export type Options<Provided extends Record<string, unknown> = {}> = Omit<ExecuteOptions<Provided>, "code">;
42
45
  /** Schema for a host tool input containing CodeMode source. */
43
46
  export declare const Input: Schema.Struct<{
44
47
  readonly code: Schema.String;
@@ -136,7 +139,7 @@ export declare const Result: Schema.Union<readonly [Schema.Struct<{
136
139
  export type Result = typeof Result.Type;
137
140
  /** Reusable confined runtime over explicit tools. */
138
141
  export type Runtime<R = never> = {
139
- readonly catalog: ReadonlyArray<ToolDescription>;
142
+ readonly catalog: () => ReadonlyArray<ToolDescription>;
140
143
  readonly execute: (code: string) => Effect.Effect<Result, never, R>;
141
144
  };
142
145
  /** Executes one Effect-native CodeMode program without constructing a reusable runtime. */
package/dist/codemode.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Effect, Schema } from "effect";
2
- import { executeProgram } from "./interpreter/execute.js";
2
+ import { executeWithLimits } from "./interpreter/execute.js";
3
3
  import { ToolRuntime } from "./tool-runtime.js";
4
4
  /** Signature-construction helpers for host-owned catalog instructions. */
5
5
  export { searchSignature, toolExpression } from "./tool-runtime.js";
@@ -54,13 +54,17 @@ const resolveExecutionLimits = (limits) => ({
54
54
  maxOutputBytes: validateLimit("maxOutputBytes", limits?.maxOutputBytes, 0),
55
55
  });
56
56
  /** Executes one Effect-native CodeMode program without constructing a reusable runtime. */
57
- export const execute = (options) => make(options).execute(options.code);
57
+ export const execute = (options) => {
58
+ const tools = (options.tools ?? {});
59
+ return executeWithLimits(options, resolveExecutionLimits(options.limits), ToolRuntime.searchIndex(tools));
60
+ };
58
61
  /** Creates an Effect-native runtime over explicit, schema-described tools. */
59
62
  export const make = (options = {}) => {
60
- const prepared = ToolRuntime.prepare((options.tools ?? {}));
63
+ const tools = (options.tools ?? {});
61
64
  const limits = resolveExecutionLimits(options.limits);
65
+ const prepared = ToolRuntime.prepare(tools);
62
66
  return {
63
- catalog: prepared.catalog,
64
- execute: (code) => executeProgram(code, prepared, limits, options),
67
+ catalog: () => prepared.catalog,
68
+ execute: (code) => executeWithLimits({ ...options, code }, limits, prepared.searchIndex),
65
69
  };
66
70
  };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,5 @@ export * as CodeMode from "./codemode.js";
2
2
  export * as Namespace from "./namespace.js";
3
3
  export * as Tool from "./tool.js";
4
4
  export * as OpenAPI from "./openapi/index.js";
5
- export { Values } from "./values.js";
6
5
  export { searchSignature, toolExpression } from "./codemode.js";
7
6
  export { ToolError, toolError } from "./tool-error.js";
package/dist/index.js CHANGED
@@ -2,6 +2,5 @@ export * as CodeMode from "./codemode.js";
2
2
  export * as Namespace from "./namespace.js";
3
3
  export * as Tool from "./tool.js";
4
4
  export * as OpenAPI from "./openapi/index.js";
5
- export { Values } from "./values.js";
6
5
  export { searchSignature, toolExpression } from "./codemode.js";
7
6
  export { ToolError, toolError } from "./tool-error.js";
@@ -1,7 +1,9 @@
1
+ import { Effect } from "effect";
1
2
  import type { Diagnostic } from "../codemode.js";
2
- import { HostFunction } from "./host.js";
3
- import { type Runner } from "./runner.js";
3
+ import { type SafeObject } from "../tool-runtime.js";
4
+ import { type AstNode } from "./model.js";
5
+ import { type SyncIteratorRunner } from "./iterator.js";
4
6
  export declare const normalizeError: (error: unknown) => Diagnostic;
5
7
  export declare const caughtErrorValue: (thrown: unknown) => unknown;
6
- /** An error constructor such as `Error` or `TypeError`; callable with or without `new`, like JS. */
7
- export declare const errorGlobal: <R>(name: string, runner: Runner<R>) => HostFunction<R>;
8
+ export declare const constructErrorValue: (name: string, args: Array<unknown>) => SafeObject;
9
+ export declare const constructAggregateErrorValue: <R>(runner: SyncIteratorRunner<R>, args: Array<unknown>, node: AstNode) => Effect.Effect<SafeObject, unknown, R>;
@@ -1,12 +1,10 @@
1
1
  import { Effect } from "effect";
2
2
  import { ToolError } from "../tool-error.js";
3
- import { toData, ToolRuntimeError } from "../data.js";
3
+ import { copyOut, ToolRuntimeError } from "../tool-runtime.js";
4
4
  import { formatLocation, InterpreterRuntimeError, ProgramThrow, sourceLocation } from "./model.js";
5
5
  import { containsRuntimeReference } from "./references.js";
6
- import { HostFunction } from "./host.js";
7
- import { get, ProgramError, ProgramObject } from "./objects.js";
8
- import {} from "./runner.js";
9
- import { coerceToString, createAggregateErrorValue, createErrorValue, errorBrandName, errorConstructors, } from "../stdlib/value.js";
6
+ import {} from "./iterator.js";
7
+ import { coerceToString, createAggregateErrorValue, createErrorValue, errorConstructors } from "../stdlib/value.js";
10
8
  export const normalizeError = (error) => {
11
9
  if (error instanceof InterpreterRuntimeError) {
12
10
  return {
@@ -36,12 +34,14 @@ export const normalizeError = (error) => {
36
34
  else if (typeof value === "string") {
37
35
  message = value;
38
36
  }
39
- else if (value instanceof ProgramObject && typeof get(value, "message") === "string") {
40
- message = get(value, "message");
37
+ else if (value !== null &&
38
+ typeof value === "object" &&
39
+ typeof value.message === "string") {
40
+ message = value.message;
41
41
  }
42
42
  else {
43
43
  try {
44
- message = JSON.stringify(toData(value, "Thrown value")) ?? String(value);
44
+ message = JSON.stringify(copyOut(value, "json")) ?? String(value);
45
45
  }
46
46
  catch {
47
47
  message = String(value);
@@ -74,8 +74,8 @@ export const caughtErrorValue = (thrown) => {
74
74
  const name = thrown instanceof Error && errorConstructors.has(thrown.name) ? thrown.name : "Error";
75
75
  return createErrorValue(name, normalizeError(thrown).message);
76
76
  };
77
- const constructErrorValue = (name, args) => createErrorValue(name, args[0] === undefined ? "" : coerceToString(args[0]));
78
- const constructAggregateErrorValue = (runner, args, node) => Effect.gen(function* () {
77
+ export const constructErrorValue = (name, args) => createErrorValue(name, args[0] === undefined ? "" : coerceToString(args[0]));
78
+ export const constructAggregateErrorValue = (runner, args, node) => Effect.gen(function* () {
79
79
  const cursor = yield* runner.syncIterator(args[0], node);
80
80
  if (cursor === undefined) {
81
81
  throw new InterpreterRuntimeError("new AggregateError(...) expects a synchronous iterable of errors.", node).as("TypeError");
@@ -89,18 +89,3 @@ const constructAggregateErrorValue = (runner, args, node) => Effect.gen(function
89
89
  errors.push(step.value);
90
90
  }
91
91
  });
92
- /** An error constructor such as `Error` or `TypeError`; callable with or without `new`, like JS. */
93
- export const errorGlobal = (name, runner) => {
94
- const construct = (args, node) => name === "AggregateError"
95
- ? constructAggregateErrorValue(runner, args, node)
96
- : Effect.sync(() => constructErrorValue(name, args));
97
- return new HostFunction({
98
- name,
99
- call: construct,
100
- construct,
101
- instanceOf: (value) => {
102
- const brand = errorBrandName(value);
103
- return brand !== undefined && (name === "Error" || brand === name);
104
- },
105
- });
106
- };
@@ -1,5 +1,4 @@
1
1
  import { Effect } from "effect";
2
- import type { ResolvedExecutionLimits, Result } from "../codemode.js";
3
- import { ToolRuntime } from "../tool-runtime.js";
4
- import type { Host } from "./globals.js";
5
- export declare const executeProgram: <R>(code: string, prepared: ToolRuntime.Prepared<R>, limits: ResolvedExecutionLimits, hooks: ToolRuntime.ToolCallHooks<R>, extraGlobals?: (host: Host<R>) => ReadonlyArray<readonly [string, unknown]>) => Effect.Effect<Result, never, R>;
2
+ import type { ExecuteOptions, ResolvedExecutionLimits, Result } from "../codemode.js";
3
+ import { ToolRuntime, type Services } from "../tool-runtime.js";
4
+ export declare const executeWithLimits: <const Provided extends Record<string, unknown>>(options: ExecuteOptions<Provided>, limits: ResolvedExecutionLimits, searchIndex: ToolRuntime.DiscoveryPlan["searchIndex"]) => Effect.Effect<Result, never, Services<Provided>>;
@@ -3,14 +3,13 @@ import { Cause, Effect, Scope } from "effect";
3
3
  // #transpile: conditional import — full typescript on node/bun, an identity
4
4
  // pass-through on workerd (the compiler is ~11 MiB and can't init there).
5
5
  import { transpile } from "#transpile";
6
- import { toData } from "../data.js";
7
- import { ToolRuntime } from "../tool-runtime.js";
6
+ import { copyIn, copyOut, ToolRuntime } from "../tool-runtime.js";
8
7
  import { normalizeError } from "./errors.js";
9
- import { InterpreterRuntimeError } from "./model.js";
8
+ import { InterpreterRuntimeError, isRecord } from "./model.js";
10
9
  import { PromiseRuntime } from "./promises.js";
11
- import { Runtime } from "./runtime.js";
12
- export const executeProgram = (code, prepared, limits, hooks, extraGlobals) => {
13
- if (code.trim().length === 0) {
10
+ import { Interpreter } from "./runtime.js";
11
+ export const executeWithLimits = (options, limits, searchIndex) => {
12
+ if (options.code.trim().length === 0) {
14
13
  return Effect.succeed({
15
14
  ok: false,
16
15
  error: { kind: "ParseError", message: "Code cannot be empty." },
@@ -19,16 +18,20 @@ export const executeProgram = (code, prepared, limits, hooks, extraGlobals) => {
19
18
  }
20
19
  // Allocate execution state inside suspension so reused Effects never share it.
21
20
  return Effect.suspend(() => {
22
- const tools = ToolRuntime.make(prepared, limits.maxToolCalls, hooks);
21
+ const tools = ToolRuntime.make((options.tools ?? {}), limits.maxToolCalls, searchIndex, {
22
+ onToolCallStart: options.onToolCallStart,
23
+ onToolCallEnd: options.onToolCallEnd,
24
+ });
23
25
  const logs = [];
24
26
  const logged = () => (logs.length > 0 ? { logs: [...logs] } : {});
25
27
  // Set only after copy-out so timeouts cannot report invalid values as completed.
26
28
  let returned;
27
29
  const base = Effect.acquireUseRelease(Scope.make("parallel"), (scope) => Effect.gen(function* () {
28
- const program = parseProgram(code);
30
+ const program = parseProgram(options.code);
29
31
  const promises = new PromiseRuntime(scope);
30
- const value = yield* new Runtime(tools.execute, tools.search, tools.keys, promises, logs, extraGlobals).run(program);
31
- const result = toData(value, "Execution result", "result");
32
+ const interpreter = new Interpreter(tools.execute, tools.search, tools.keys, promises, logs);
33
+ const value = yield* interpreter.run(program);
34
+ const result = copyOut(copyIn(value, "Execution result"), "nullify");
32
35
  returned = { value: result, promises };
33
36
  const warnings = yield* promises.interrupt();
34
37
  return {
@@ -87,13 +90,17 @@ const parseProgram = (code) => {
87
90
  const bodyStart = transpiled.outputText.indexOf("{") + 1;
88
91
  const bodyEnd = transpiled.outputText.lastIndexOf("}");
89
92
  const executableCode = transpiled.outputText.slice(bodyStart, bodyEnd);
90
- return parse(executableCode, {
93
+ const parsed = parse(executableCode, {
91
94
  ecmaVersion: "latest",
92
95
  sourceType: "script",
93
96
  allowReturnOutsideFunction: true,
94
97
  allowAwaitOutsideFunction: true,
95
98
  locations: true,
96
99
  });
100
+ if (!isRecord(parsed) || parsed.type !== "Program" || !Array.isArray(parsed.body)) {
101
+ throw new InterpreterRuntimeError("Failed to parse script as a Program node.");
102
+ }
103
+ return parsed;
97
104
  };
98
105
  const utf8ByteLength = (value) => new TextEncoder().encode(value).byteLength;
99
106
  // Drop a replacement character produced by truncating inside a UTF-8 sequence.
@@ -0,0 +1,13 @@
1
+ import { Effect } from "effect";
2
+ import type { AstNode } from "./model.js";
3
+ export type IteratorCursor<R> = {
4
+ readonly next: Effect.Effect<{
5
+ readonly done: boolean;
6
+ readonly value: unknown;
7
+ }, unknown, R>;
8
+ readonly close: Effect.Effect<void, unknown, R>;
9
+ };
10
+ export type SyncIteratorRunner<R> = {
11
+ readonly syncIterator: (value: unknown, node: AstNode) => Effect.Effect<IteratorCursor<R> | undefined, unknown, R>;
12
+ };
13
+ export declare const preserveConsumerError: <A, R>(cursor: IteratorCursor<R>, effect: Effect.Effect<A, unknown, R>) => Effect.Effect<A, unknown, R>;
@@ -0,0 +1,4 @@
1
+ import { Effect, Exit } from "effect";
2
+ export const preserveConsumerError = (cursor, effect) => Effect.flatMap(Effect.exit(effect), (exit) => Exit.isSuccess(exit)
3
+ ? Effect.succeed(exit.value)
4
+ : Effect.andThen(Effect.exit(cursor.close), Effect.failCause(exit.cause)));
@@ -1,4 +1,17 @@
1
1
  import { Effect } from "effect";
2
- import { type AstNode, IntrinsicReference } from "./model.js";
3
- import { type Runner } from "./runner.js";
4
- export declare const invokeIntrinsic: <R>(runner: Runner<R>, ref: IntrinsicReference, args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
2
+ import { type AstNode, CodeModeFunction, CoercionFunction, ErrorConstructorReference, GlobalMethodReference, GlobalNamespace, IntrinsicReference, JsonMethodReference, PromiseCapabilityFunction, PromiseNamespace, UriFunction } from "./model.js";
3
+ import { CodeModePromise } from "../values.js";
4
+ import { type SyncIteratorRunner } from "./iterator.js";
5
+ export type CallbackRunner<R> = {
6
+ readonly invokeFunction: (fn: CodeModeFunction, args: Array<unknown>) => Effect.Effect<unknown, unknown, R>;
7
+ readonly invokeCallable: (callable: unknown, args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
8
+ readonly settlePromise: (promise: CodeModePromise) => Effect.Effect<unknown, unknown, never>;
9
+ };
10
+ export type SupportedCallback = CodeModeFunction | CoercionFunction | UriFunction | PromiseCapabilityFunction | GlobalMethodReference | JsonMethodReference | IntrinsicReference | ErrorConstructorReference | GlobalNamespace | PromiseNamespace;
11
+ export declare const isSupportedCallback: (value: unknown) => value is SupportedCallback;
12
+ export declare const invokeIntrinsic: <R>(runner: CallbackRunner<R>, ref: IntrinsicReference, args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
13
+ export declare const invokeGlobalMethod: (ref: GlobalMethodReference, args: Array<unknown>, node: AstNode) => unknown;
14
+ export declare const arrayStatics: Set<string>;
15
+ export declare const invokeArrayFrom: <R>(runner: CallbackRunner<R> & SyncIteratorRunner<R>, args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
16
+ export declare const invokeGroupBy: <R>(runner: CallbackRunner<R> & SyncIteratorRunner<R>, namespace: "Map" | "Object", args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
17
+ export declare const applyCollectionCallback: <R>(runner: CallbackRunner<R>, callback: unknown, name: string, node: AstNode) => ((args: Array<unknown>) => Effect.Effect<unknown, unknown, R>);