@opencode-ai/codemode 0.0.0-dev-17471
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 +168 -0
- package/dist/codemode.d.ts +148 -0
- package/dist/codemode.js +70 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/interpreter/errors.d.ts +9 -0
- package/dist/interpreter/errors.js +91 -0
- package/dist/interpreter/execute.d.ts +4 -0
- package/dist/interpreter/execute.js +178 -0
- package/dist/interpreter/iterator.d.ts +13 -0
- package/dist/interpreter/iterator.js +4 -0
- package/dist/interpreter/methods.d.ts +17 -0
- package/dist/interpreter/methods.js +1026 -0
- package/dist/interpreter/model.d.ts +151 -0
- package/dist/interpreter/model.js +186 -0
- package/dist/interpreter/promises.d.ts +29 -0
- package/dist/interpreter/promises.js +253 -0
- package/dist/interpreter/references.d.ts +6 -0
- package/dist/interpreter/references.js +114 -0
- package/dist/interpreter/runtime.d.ts +98 -0
- package/dist/interpreter/runtime.js +2351 -0
- package/dist/interpreter/scope.d.ts +15 -0
- package/dist/interpreter/scope.js +79 -0
- package/dist/interpreter/transpile.node.d.ts +5 -0
- package/dist/interpreter/transpile.node.js +19 -0
- package/dist/interpreter/transpile.workerd.d.ts +5 -0
- package/dist/interpreter/transpile.workerd.js +6 -0
- package/dist/openapi/index.d.ts +7 -0
- package/dist/openapi/index.js +101 -0
- package/dist/openapi/runtime.d.ts +4 -0
- package/dist/openapi/runtime.js +283 -0
- package/dist/openapi/spec.d.ts +20 -0
- package/dist/openapi/spec.js +588 -0
- package/dist/openapi/types.d.ts +122 -0
- package/dist/openapi/types.js +2 -0
- package/dist/stdlib/collections.d.ts +4 -0
- package/dist/stdlib/collections.js +57 -0
- package/dist/stdlib/console.d.ts +2 -0
- package/dist/stdlib/console.js +126 -0
- package/dist/stdlib/date.d.ts +7 -0
- package/dist/stdlib/date.js +186 -0
- package/dist/stdlib/json.d.ts +6 -0
- package/dist/stdlib/json.js +124 -0
- package/dist/stdlib/math.d.ts +12 -0
- package/dist/stdlib/math.js +157 -0
- package/dist/stdlib/number.d.ts +6 -0
- package/dist/stdlib/number.js +76 -0
- package/dist/stdlib/object.d.ts +7 -0
- package/dist/stdlib/object.js +100 -0
- package/dist/stdlib/promise.d.ts +2 -0
- package/dist/stdlib/promise.js +1 -0
- package/dist/stdlib/regexp.d.ts +11 -0
- package/dist/stdlib/regexp.js +106 -0
- package/dist/stdlib/string.d.ts +4 -0
- package/dist/stdlib/string.js +48 -0
- package/dist/stdlib/url.d.ts +12 -0
- package/dist/stdlib/url.js +84 -0
- package/dist/stdlib/value.d.ts +12 -0
- package/dist/stdlib/value.js +120 -0
- package/dist/tool-error.d.ts +11 -0
- package/dist/tool-error.js +9 -0
- package/dist/tool-runtime.d.ts +68 -0
- package/dist/tool-runtime.js +390 -0
- package/dist/tool-schema.d.ts +15 -0
- package/dist/tool-schema.js +213 -0
- package/dist/tool.d.ts +55 -0
- package/dist/tool.js +21 -0
- package/dist/tools.d.ts +4 -0
- package/dist/tools.js +1 -0
- package/dist/values.d.ts +31 -0
- package/dist/values.js +50 -0
- package/package.json +46 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { parse } from "acorn";
|
|
2
|
+
import { Cause, Effect, Scope } from "effect";
|
|
3
|
+
// #transpile: conditional import — full typescript on node/bun, an identity
|
|
4
|
+
// pass-through on workerd (the compiler is ~11 MiB and can't init there).
|
|
5
|
+
import { transpile } from "#transpile";
|
|
6
|
+
import { copyIn, copyOut, ToolRuntime } from "../tool-runtime.js";
|
|
7
|
+
import { normalizeError } from "./errors.js";
|
|
8
|
+
import { InterpreterRuntimeError, isRecord } from "./model.js";
|
|
9
|
+
import { PromiseRuntime } from "./promises.js";
|
|
10
|
+
import { Interpreter } from "./runtime.js";
|
|
11
|
+
export const executeWithLimits = (options, limits, searchIndex) => {
|
|
12
|
+
if (options.code.trim().length === 0) {
|
|
13
|
+
return Effect.succeed({
|
|
14
|
+
ok: false,
|
|
15
|
+
error: { kind: "ParseError", message: "Code cannot be empty." },
|
|
16
|
+
toolCalls: [],
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
// Allocate execution state inside suspension so reused Effects never share it.
|
|
20
|
+
return Effect.suspend(() => {
|
|
21
|
+
const tools = ToolRuntime.make((options.tools ?? {}), limits.maxToolCalls, searchIndex, {
|
|
22
|
+
onToolCallStart: options.onToolCallStart,
|
|
23
|
+
onToolCallEnd: options.onToolCallEnd,
|
|
24
|
+
});
|
|
25
|
+
const logs = [];
|
|
26
|
+
const logged = () => (logs.length > 0 ? { logs: [...logs] } : {});
|
|
27
|
+
// Set only after copy-out so timeouts cannot report invalid values as completed.
|
|
28
|
+
let returned;
|
|
29
|
+
const base = Effect.acquireUseRelease(Scope.make("parallel"), (scope) => Effect.gen(function* () {
|
|
30
|
+
const program = parseProgram(options.code);
|
|
31
|
+
const promises = new PromiseRuntime(scope);
|
|
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");
|
|
35
|
+
returned = { value: result, promises };
|
|
36
|
+
const warnings = yield* promises.interrupt();
|
|
37
|
+
return {
|
|
38
|
+
ok: true,
|
|
39
|
+
value: result,
|
|
40
|
+
...(warnings.length > 0 ? { warnings } : {}),
|
|
41
|
+
...logged(),
|
|
42
|
+
toolCalls: tools.calls,
|
|
43
|
+
};
|
|
44
|
+
}), (scope, exit) => Scope.close(scope, exit));
|
|
45
|
+
const timeoutMs = limits.timeoutMs;
|
|
46
|
+
const operation = timeoutMs === undefined
|
|
47
|
+
? base
|
|
48
|
+
: base.pipe(Effect.timeoutOrElse({
|
|
49
|
+
duration: timeoutMs,
|
|
50
|
+
orElse: () => Effect.sync(() => {
|
|
51
|
+
if (returned === undefined) {
|
|
52
|
+
return {
|
|
53
|
+
ok: false,
|
|
54
|
+
error: { kind: "TimeoutExceeded", message: `Execution timed out after ${timeoutMs}ms.` },
|
|
55
|
+
...logged(),
|
|
56
|
+
toolCalls: tools.calls,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// Keep the timeout warning first so truncation preserves it.
|
|
60
|
+
return {
|
|
61
|
+
ok: true,
|
|
62
|
+
value: returned.value,
|
|
63
|
+
warnings: [
|
|
64
|
+
{
|
|
65
|
+
kind: "TimeoutExceeded",
|
|
66
|
+
message: `The program returned, but background work was still running at the ${timeoutMs}ms timeout and was interrupted. Await all started promises.`,
|
|
67
|
+
},
|
|
68
|
+
...returned.promises.diagnostics(),
|
|
69
|
+
],
|
|
70
|
+
...logged(),
|
|
71
|
+
toolCalls: tools.calls,
|
|
72
|
+
};
|
|
73
|
+
}),
|
|
74
|
+
}));
|
|
75
|
+
return operation.pipe(Effect.catchCause((cause) => Cause.hasInterruptsOnly(cause)
|
|
76
|
+
? Effect.interrupt
|
|
77
|
+
: Effect.succeed({
|
|
78
|
+
ok: false,
|
|
79
|
+
error: normalizeError(Cause.squash(cause)),
|
|
80
|
+
...logged(),
|
|
81
|
+
toolCalls: tools.calls,
|
|
82
|
+
})), Effect.map((result) => limits.maxOutputBytes === undefined ? result : boundOutput(result, limits.maxOutputBytes)));
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
const parseProgram = (code) => {
|
|
86
|
+
const transpiled = transpile(`async function __codemode__() {\n${code}\n}`);
|
|
87
|
+
if (transpiled.error !== undefined) {
|
|
88
|
+
throw new InterpreterRuntimeError(`Failed to parse TypeScript: ${transpiled.error}`, undefined, "ParseError");
|
|
89
|
+
}
|
|
90
|
+
const bodyStart = transpiled.outputText.indexOf("{") + 1;
|
|
91
|
+
const bodyEnd = transpiled.outputText.lastIndexOf("}");
|
|
92
|
+
const executableCode = transpiled.outputText.slice(bodyStart, bodyEnd);
|
|
93
|
+
const parsed = parse(executableCode, {
|
|
94
|
+
ecmaVersion: "latest",
|
|
95
|
+
sourceType: "script",
|
|
96
|
+
allowReturnOutsideFunction: true,
|
|
97
|
+
allowAwaitOutsideFunction: true,
|
|
98
|
+
locations: true,
|
|
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;
|
|
104
|
+
};
|
|
105
|
+
const utf8ByteLength = (value) => new TextEncoder().encode(value).byteLength;
|
|
106
|
+
// Drop a replacement character produced by truncating inside a UTF-8 sequence.
|
|
107
|
+
const utf8Truncate = (value, maxBytes) => {
|
|
108
|
+
const bytes = new TextEncoder().encode(value);
|
|
109
|
+
if (bytes.byteLength <= maxBytes)
|
|
110
|
+
return value;
|
|
111
|
+
const text = new TextDecoder("utf-8").decode(bytes.slice(0, Math.max(0, maxBytes)));
|
|
112
|
+
return text.endsWith("\uFFFD") ? text.slice(0, -1) : text;
|
|
113
|
+
};
|
|
114
|
+
// Warnings have a separate budget so result data cannot starve diagnostics.
|
|
115
|
+
const boundOutput = (result, maxOutputBytes) => {
|
|
116
|
+
let truncated = false;
|
|
117
|
+
let value = null;
|
|
118
|
+
let valueBytes = 0;
|
|
119
|
+
if (result.ok) {
|
|
120
|
+
const serialized = JSON.stringify(result.value) ?? "null";
|
|
121
|
+
const bytes = utf8ByteLength(serialized);
|
|
122
|
+
if (bytes > maxOutputBytes) {
|
|
123
|
+
truncated = true;
|
|
124
|
+
value = `${utf8Truncate(serialized, maxOutputBytes)} [result truncated: ${bytes} bytes exceeds the ${maxOutputBytes}-byte output limit; return a smaller value]`;
|
|
125
|
+
valueBytes = maxOutputBytes;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
value = result.value;
|
|
129
|
+
valueBytes = bytes;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const warnings = result.ok ? (result.warnings ?? []) : [];
|
|
133
|
+
const keptWarnings = [];
|
|
134
|
+
let warningBytes = 0;
|
|
135
|
+
for (const warning of warnings) {
|
|
136
|
+
const bytes = utf8ByteLength(JSON.stringify(warning)) + 1;
|
|
137
|
+
if (warningBytes + bytes > maxOutputBytes)
|
|
138
|
+
break;
|
|
139
|
+
warningBytes += bytes;
|
|
140
|
+
keptWarnings.push(warning);
|
|
141
|
+
}
|
|
142
|
+
if (keptWarnings.length < warnings.length) {
|
|
143
|
+
truncated = true;
|
|
144
|
+
keptWarnings.push({
|
|
145
|
+
kind: "Truncated",
|
|
146
|
+
message: `${warnings.length - keptWarnings.length} additional warnings omitted by the output limit.`,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
const logs = result.logs ?? [];
|
|
150
|
+
const kept = [];
|
|
151
|
+
const logBudget = Math.max(0, maxOutputBytes - valueBytes);
|
|
152
|
+
let logBytes = 0;
|
|
153
|
+
for (const line of logs) {
|
|
154
|
+
const lineBytes = utf8ByteLength(line) + 1;
|
|
155
|
+
if (logBytes + lineBytes > logBudget)
|
|
156
|
+
break;
|
|
157
|
+
logBytes += lineBytes;
|
|
158
|
+
kept.push(line);
|
|
159
|
+
}
|
|
160
|
+
if (kept.length < logs.length) {
|
|
161
|
+
truncated = true;
|
|
162
|
+
kept.push(`[logs truncated: showing ${kept.length} of ${logs.length} lines]`);
|
|
163
|
+
}
|
|
164
|
+
if (!truncated)
|
|
165
|
+
return result;
|
|
166
|
+
const warningsPart = keptWarnings.length > 0 ? { warnings: keptWarnings } : {};
|
|
167
|
+
const logsPart = kept.length > 0 ? { logs: kept } : {};
|
|
168
|
+
return result.ok
|
|
169
|
+
? {
|
|
170
|
+
ok: true,
|
|
171
|
+
value,
|
|
172
|
+
...warningsPart,
|
|
173
|
+
...logsPart,
|
|
174
|
+
truncated: true,
|
|
175
|
+
toolCalls: result.toolCalls,
|
|
176
|
+
}
|
|
177
|
+
: { ok: false, error: result.error, ...logsPart, truncated: true, toolCalls: result.toolCalls };
|
|
178
|
+
};
|
|
@@ -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,17 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
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>);
|