import { Effect, Schema } from "effect" /** * JSON Schema subset accepted for render-only tool schemas. * * A JSON-Schema-described side of a tool is used to generate the model-visible TypeScript * signature only - CodeMode performs no validation against it. This is the natural shape for * adapter-provided tools (e.g. MCP definitions) whose schemas arrive as JSON Schema documents. */ export type JsonSchema = { readonly type?: string | ReadonlyArray readonly enum?: ReadonlyArray readonly const?: unknown readonly anyOf?: ReadonlyArray readonly oneOf?: ReadonlyArray readonly allOf?: ReadonlyArray readonly properties?: Readonly> readonly required?: ReadonlyArray readonly items?: JsonSchema readonly additionalProperties?: boolean | JsonSchema readonly description?: string readonly default?: unknown readonly format?: string readonly deprecated?: boolean readonly minItems?: number readonly maxItems?: number readonly $ref?: string readonly $defs?: Readonly> readonly definitions?: Readonly> } /** Either a validating Effect Schema or a render-only JSON Schema document. */ export type SchemaType = Schema.Decoder | JsonSchema /** Schema-backed tool definition consumed by a CodeMode tool tree. */ export type Definition = { readonly _tag: "CodeModeTool" readonly description: string readonly input: SchemaType readonly output: SchemaType | undefined readonly run: (input: unknown) => Effect.Effect } /** The value `run` receives: the decoded type for Effect Schemas, `unknown` for JSON Schemas. */ type InputType = S extends Schema.Decoder ? S["Type"] : unknown /** The value `run` returns: the encoded type for Effect Schemas, `unknown` otherwise. */ type ResultType = S extends Schema.Decoder ? S["Encoded"] : unknown /** Options for defining one CodeMode tool. */ export type Options = { readonly description: string readonly input: I readonly output?: O readonly run: (input: InputType) => Effect.Effect, unknown, R> } export const isDefinition = (value: unknown): value is Definition => typeof value === "object" && value !== null && "_tag" in value && value._tag === "CodeModeTool" /** * Defines one schema-described tool available to a CodeMode program through `tools.*`. * * `input` and `output` each accept a validating Effect Schema or a render-only JSON Schema * document. Effect Schema input is decoded before `run` is invoked, and `run` returns the * encoded representation of an Effect Schema `output`, which CodeMode decodes before returning * it to the program. JSON Schemas only shape the model-visible signature; values pass through * unvalidated. `output` is optional - without it the signature advertises `unknown` and the * host result is exposed as-is. The host tool remains responsible for authorization and * durable side-effect handling. * * @example * ```ts * const lookup = Tool.make({ * description: "Look up an order", * input: Schema.Struct({ id: Schema.String }), * output: Schema.Struct({ status: Schema.String }), * run: ({ id }) => Effect.succeed({ status: "open" }), * }) * * const fromJsonSchema = Tool.make({ * description: "Call an adapter-described tool", * input: { type: "object", properties: { id: { type: "string" } }, required: ["id"] }, * run: (input) => callHost(input), * }) * ``` */ export const make = ( options: Options, ): Definition => ({ _tag: "CodeModeTool", description: options.description, input: options.input, output: options.output, run: (input) => options.run(input as InputType), })