|
|
@@ -19,8 +19,7 @@ import { ToolError } from "./tool-error.js"
|
|
|
import { isSandboxValue, SandboxDate, SandboxMap, SandboxPromise, SandboxRegExp, SandboxSet } from "./values.js"
|
|
|
|
|
|
/** A tool call admitted during an execution. */
|
|
|
-export type { ToolCall, ToolCallStarted, ToolDescription } from "./tool-runtime.js"
|
|
|
-export { ToolError, toolError } from "./tool-error.js"
|
|
|
+export type { ToolCall, ToolCallEnded, ToolCallHooks, ToolCallStarted, ToolDescription } from "./tool-runtime.js"
|
|
|
|
|
|
/** Resource budgets enforced independently during each CodeMode program execution. */
|
|
|
export type ExecutionLimits = {
|
|
|
@@ -74,50 +73,20 @@ export type ExecuteOptions<Tools extends Record<string, unknown> = {}> = {
|
|
|
onToolCallEnd?: (call: ToolRuntime.ToolCallEnded) => Effect.Effect<void, never, Services<Tools>>
|
|
|
}
|
|
|
|
|
|
-/** A normalized program diagnostic safe to return across an agent tool boundary. */
|
|
|
-export type Diagnostic = {
|
|
|
- readonly kind: DiagnosticKind
|
|
|
- readonly message: string
|
|
|
- readonly location?: { readonly line: number; readonly column: number }
|
|
|
- readonly suggestions?: ReadonlyArray<string>
|
|
|
-}
|
|
|
-
|
|
|
/** A JSON value that can cross the confined interpreter boundary. */
|
|
|
export type DataValue = Schema.Json
|
|
|
|
|
|
-/** Successful execution after the result has crossed the plain-data boundary. */
|
|
|
-export type ExecuteSuccess = {
|
|
|
- readonly ok: true
|
|
|
- readonly value: DataValue
|
|
|
- readonly logs?: ReadonlyArray<string>
|
|
|
- /** Present when the value or logs were truncated to fit `maxOutputBytes`. */
|
|
|
- readonly truncated?: boolean
|
|
|
- readonly toolCalls: ReadonlyArray<ToolCall>
|
|
|
-}
|
|
|
-
|
|
|
-/** Failed execution with calls admitted before the diagnostic was produced. */
|
|
|
-export type ExecuteFailure = {
|
|
|
- readonly ok: false
|
|
|
- readonly error: Diagnostic
|
|
|
- readonly logs?: ReadonlyArray<string>
|
|
|
- /** Present when the logs were truncated to fit `maxOutputBytes`. */
|
|
|
- readonly truncated?: boolean
|
|
|
- readonly toolCalls: ReadonlyArray<ToolCall>
|
|
|
-}
|
|
|
-
|
|
|
-/** Result of executing a CodeMode program. Program failures are data, not Effect failures. */
|
|
|
-export type ExecuteResult = ExecuteSuccess | ExecuteFailure
|
|
|
-
|
|
|
/** Configuration shared by `CodeMode.make` and `CodeMode.execute`. */
|
|
|
-export type CodeModeOptions<Tools extends Record<string, unknown> = {}> = Omit<ExecuteOptions<Tools>, "code"> & {
|
|
|
+export type Options<Tools extends Record<string, unknown> = {}> = Omit<ExecuteOptions<Tools>, "code"> & {
|
|
|
/** Progressive-disclosure configuration for the agent-facing tool catalog. */
|
|
|
readonly discovery?: DiscoveryOptions
|
|
|
}
|
|
|
|
|
|
-/** Schema for a CodeMode execution request. */
|
|
|
-const Input = Schema.Struct({ code: Schema.String })
|
|
|
+/** Schema for a host tool input containing CodeMode source. */
|
|
|
+export const Input = Schema.Struct({ code: Schema.String })
|
|
|
+export type Input = typeof Input.Type
|
|
|
|
|
|
-const DiagnosticKindSchema = Schema.Literals([
|
|
|
+export const DiagnosticKind = Schema.Literals([
|
|
|
"ParseError",
|
|
|
"UnsupportedSyntax",
|
|
|
"UnknownTool",
|
|
|
@@ -129,38 +98,52 @@ const DiagnosticKindSchema = Schema.Literals([
|
|
|
"ToolFailure",
|
|
|
"ExecutionFailure",
|
|
|
])
|
|
|
+/** Stable categories produced by program, schema, tool, and limit failures. */
|
|
|
+export type DiagnosticKind = typeof DiagnosticKind.Type
|
|
|
+
|
|
|
+export const Diagnostic = Schema.Struct({
|
|
|
+ kind: DiagnosticKind,
|
|
|
+ message: Schema.String,
|
|
|
+ location: Schema.optionalKey(Schema.Struct({ line: Schema.Number, column: Schema.Number })),
|
|
|
+ suggestions: Schema.optionalKey(Schema.Array(Schema.String)),
|
|
|
+})
|
|
|
+/** A normalized program diagnostic safe to return across an agent tool boundary. */
|
|
|
+export type Diagnostic = typeof Diagnostic.Type
|
|
|
+
|
|
|
+const ToolCallSchema = Schema.Struct({ name: Schema.String })
|
|
|
+export const Success = Schema.Struct({
|
|
|
+ ok: Schema.Literal(true),
|
|
|
+ value: Schema.Json,
|
|
|
+ logs: Schema.optionalKey(Schema.Array(Schema.String)),
|
|
|
+ truncated: Schema.optionalKey(Schema.Boolean),
|
|
|
+ toolCalls: Schema.Array(ToolCallSchema),
|
|
|
+})
|
|
|
+/** Successful execution after the result has crossed the plain-data boundary. */
|
|
|
+export type Success = typeof Success.Type
|
|
|
+
|
|
|
+export const Failure = Schema.Struct({
|
|
|
+ ok: Schema.Literal(false),
|
|
|
+ error: Diagnostic,
|
|
|
+ logs: Schema.optionalKey(Schema.Array(Schema.String)),
|
|
|
+ truncated: Schema.optionalKey(Schema.Boolean),
|
|
|
+ toolCalls: Schema.Array(ToolCallSchema),
|
|
|
+})
|
|
|
+/** Failed execution with calls admitted before the diagnostic was produced. */
|
|
|
+export type Failure = typeof Failure.Type
|
|
|
|
|
|
/** Schema for the structured success or diagnostic returned by CodeMode execution. */
|
|
|
-const Result = Schema.Union([
|
|
|
- Schema.Struct({
|
|
|
- ok: Schema.Literal(true),
|
|
|
- value: Schema.Json,
|
|
|
- logs: Schema.optionalKey(Schema.Array(Schema.String)),
|
|
|
- truncated: Schema.optionalKey(Schema.Boolean),
|
|
|
- toolCalls: Schema.Array(Schema.Struct({ name: Schema.String })),
|
|
|
- }),
|
|
|
- Schema.Struct({
|
|
|
- ok: Schema.Literal(false),
|
|
|
- error: Schema.Struct({
|
|
|
- kind: DiagnosticKindSchema,
|
|
|
- message: Schema.String,
|
|
|
- location: Schema.optionalKey(Schema.Struct({ line: Schema.Number, column: Schema.Number })),
|
|
|
- suggestions: Schema.optionalKey(Schema.Array(Schema.String)),
|
|
|
- }),
|
|
|
- logs: Schema.optionalKey(Schema.Array(Schema.String)),
|
|
|
- truncated: Schema.optionalKey(Schema.Boolean),
|
|
|
- toolCalls: Schema.Array(Schema.Struct({ name: Schema.String })),
|
|
|
- }),
|
|
|
-])
|
|
|
+export const Result = Schema.Union([Success, Failure])
|
|
|
+/** Result of executing a CodeMode program. Program failures are data, not Effect failures. */
|
|
|
+export type Result = typeof Result.Type
|
|
|
|
|
|
/** Reusable confined runtime over one explicit tool tree. */
|
|
|
-export type CodeModeRuntime<R = never> = {
|
|
|
+export type Runtime<R = never> = {
|
|
|
/** Lists schema-described tool paths provided by the host. */
|
|
|
readonly catalog: () => ReadonlyArray<ToolDescription>
|
|
|
/** Builds model-facing syntax guidance and visible tool signatures. */
|
|
|
readonly instructions: () => string
|
|
|
/** Executes a program using this runtime's configured host tools. */
|
|
|
- readonly execute: (code: string) => Effect.Effect<ExecuteResult, never, R>
|
|
|
+ readonly execute: (code: string) => Effect.Effect<Result, never, R>
|
|
|
}
|
|
|
|
|
|
type SourcePosition = {
|
|
|
@@ -275,19 +258,6 @@ const errorBrandName = (value: unknown): string | undefined =>
|
|
|
? ((value as Record<PropertyKey, unknown>)[ErrorBrand] as string | undefined)
|
|
|
: undefined
|
|
|
|
|
|
-/** Stable categories produced by program, schema, tool, and limit failures. */
|
|
|
-export type DiagnosticKind =
|
|
|
- | "ParseError"
|
|
|
- | "UnsupportedSyntax"
|
|
|
- | "UnknownTool"
|
|
|
- | "InvalidToolInput"
|
|
|
- | "InvalidToolOutput"
|
|
|
- | "InvalidDataValue"
|
|
|
- | "ToolCallLimitExceeded"
|
|
|
- | "TimeoutExceeded"
|
|
|
- | "ToolFailure"
|
|
|
- | "ExecutionFailure"
|
|
|
-
|
|
|
const arrayMethods = new Set([
|
|
|
"map",
|
|
|
"filter",
|
|
|
@@ -3943,7 +3913,7 @@ const executeWithLimits = <const Tools extends Record<string, unknown>>(
|
|
|
options: ExecuteOptions<Tools>,
|
|
|
limits: ResolvedExecutionLimits,
|
|
|
searchIndex: ToolRuntime.DiscoveryPlan["searchIndex"],
|
|
|
-): Effect.Effect<ExecuteResult, never, Services<Tools>> => {
|
|
|
+): Effect.Effect<Result, never, Services<Tools>> => {
|
|
|
const hooks = {
|
|
|
...(options.onToolCallStart === undefined ? {} : { onToolCallStart: options.onToolCallStart }),
|
|
|
...(options.onToolCallEnd === undefined ? {} : { onToolCallEnd: options.onToolCallEnd }),
|
|
|
@@ -3975,7 +3945,7 @@ const executeWithLimits = <const Tools extends Record<string, unknown>>(
|
|
|
value: result,
|
|
|
...logged(),
|
|
|
toolCalls: tools.calls,
|
|
|
- } satisfies ExecuteResult
|
|
|
+ } satisfies Result
|
|
|
}).pipe((program) => {
|
|
|
const timeoutMs = limits.timeoutMs
|
|
|
if (timeoutMs === undefined) return program
|
|
|
@@ -3988,7 +3958,7 @@ const executeWithLimits = <const Tools extends Record<string, unknown>>(
|
|
|
error: { kind: "TimeoutExceeded", message: `Execution timed out after ${timeoutMs}ms.` },
|
|
|
...logged(),
|
|
|
toolCalls: tools.calls,
|
|
|
- } satisfies ExecuteResult),
|
|
|
+ } satisfies Result),
|
|
|
}),
|
|
|
)
|
|
|
})
|
|
|
@@ -4002,7 +3972,7 @@ const executeWithLimits = <const Tools extends Record<string, unknown>>(
|
|
|
error: normalizeError(Cause.squash(cause)),
|
|
|
...logged(),
|
|
|
toolCalls: tools.calls,
|
|
|
- } satisfies ExecuteResult),
|
|
|
+ } satisfies Result),
|
|
|
),
|
|
|
Effect.map((result) => (limits.maxOutputBytes === undefined ? result : boundOutput(result, limits.maxOutputBytes))),
|
|
|
)
|
|
|
@@ -4026,7 +3996,7 @@ const utf8Truncate = (value: string, maxBytes: number): string => {
|
|
|
* fails the execution; `truncated: true` marks affected results. Only runs when the host set
|
|
|
* `maxOutputBytes` - with the limit absent, output passes through unbounded.
|
|
|
*/
|
|
|
-const boundOutput = (result: ExecuteResult, maxOutputBytes: number): ExecuteResult => {
|
|
|
+const boundOutput = (result: Result, maxOutputBytes: number): Result => {
|
|
|
let truncated = false
|
|
|
|
|
|
let value: DataValue = null
|
|
|
@@ -4068,7 +4038,7 @@ const boundOutput = (result: ExecuteResult, maxOutputBytes: number): ExecuteResu
|
|
|
|
|
|
export const execute = <const Tools extends Record<string, unknown>>(
|
|
|
options: ExecuteOptions<Tools>,
|
|
|
-): Effect.Effect<ExecuteResult, never, Services<Tools>> => {
|
|
|
+): Effect.Effect<Result, never, Services<Tools>> => {
|
|
|
const tools = (options.tools ?? {}) as HostTools<Services<Tools>>
|
|
|
ToolRuntime.assertValidTools(tools)
|
|
|
return executeWithLimits(options, resolveExecutionLimits(options.limits), ToolRuntime.searchIndex(tools))
|
|
|
@@ -4086,8 +4056,8 @@ export const execute = <const Tools extends Record<string, unknown>>(
|
|
|
* ```
|
|
|
*/
|
|
|
export const make = <const Tools extends Record<string, unknown> = {}>(
|
|
|
- options: CodeModeOptions<Tools> = {} as CodeModeOptions<Tools>,
|
|
|
-): CodeModeRuntime<Services<Tools>> => {
|
|
|
+ options: Options<Tools> = {} as Options<Tools>,
|
|
|
+): Runtime<Services<Tools>> => {
|
|
|
const tools = (options.tools ?? {}) as HostTools<Services<Tools>>
|
|
|
ToolRuntime.assertValidTools(tools)
|
|
|
const limits = resolveExecutionLimits(options.limits)
|
|
|
@@ -4102,6 +4072,3 @@ export const make = <const Tools extends Record<string, unknown> = {}>(
|
|
|
execute: executeProgram,
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-/** Constructors for one-shot and reusable CodeMode execution. */
|
|
|
-export const CodeMode = { Input, Result, make, execute }
|