refactor(codemode): namespace public types (#35435)
This commit is contained in:
parent
f950497173
commit
f9d1d3b259
14 changed files with 423 additions and 475 deletions
|
|
@ -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 }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue