Skip to content

CodeMode

Code mode presents a toolkit to a model as one tool, execute, which runs code the model writes. The code calls the tools of the presented toolkit as functions, await tools.<name>(input), so a model does in one run what takes it many calls otherwise: it calls a tool, reads the result in code, and filters it or goes on with the next call, and only what the code returns comes back to the model. What it is shown is the same however many tools there are, and costs the tokens of their declarations.

Running code is the job of a CodeRuntime, which this package does not have: it takes an isolate that cannot reach anything but the tools it is given, and an adapter that has one implements the interface, as @amends-dev/codemode-opencode does over opencode’s interpreter. Everything else is here. A tool the code calls runs as it does when a model calls it directly, so its input is checked and its failures are what it says. The code fails when it throws, runs too long, or returns too much, and the model reads that.

A tool that needs approval cannot be called from code, which a session cannot ask a person about in the middle of a run. It stays a tool of its own beside execute, and a session asks about its calls as it does for any tool.

Since v0.1.0

Makes the toolkit of execute, and the tools of presented that need approval, over presented and the runtime that runs the code. Building contacts nothing.

Example (Presenting tools as code the model writes)

import { Assembly, CodeMode } from "@amends-dev/toolkit"
import { Effect } from "effect"
declare const members: ReadonlyArray<Assembly.Member>
declare const runtime: CodeMode.CodeRuntime // an isolate that reaches only the tools it is given
const program = Effect.gen(function* () {
const assembled = yield* Assembly.toolkit(members, (_source, definition) =>
definition.annotations.readOnly === true ? "allow" : "approve"
)
// The model is shown `execute`, which calls the read-only tools as `await tools.<name>(input)`,
// and each tool that needs approval as a tool of its own.
return yield* CodeMode.toolkit(assembled, runtime, { timeout: "30 seconds" })
})

Signature

declare const toolkit: <Tools extends Record<string, Tool.Any>>(
presented: Toolkit.WithHandler<Tools>,
runtime: CodeRuntime,
options?: Options | undefined
) => Effect.Effect<
Toolkit.WithHandler<
Toolkit.MergeRecords<
| Tools
| {
readonly execute: Tool.Tool<
"execute",
{
readonly parameters: Schema.Struct<{ readonly code: Schema.String }>
readonly success: Schema.Struct<{
readonly result: Schema.Codec<Schema.Json, Schema.Json, never, never>
readonly logs: Schema.$Array<Schema.String>
}>
readonly failure: Schema.Struct<{
readonly code: Schema.String
readonly message: Schema.String
readonly retryable: Schema.Boolean
}>
readonly failureMode: "return"
},
never
>
}
>
>,
never,
Tool.HandlerServices<Tools[keyof Tools]>
>

Source

Since v0.1.0

Why code did not finish: it threw, or the runtime could not run it. A CodeRuntime fails with it, and the model reads it as a Failure with what the code logged before.

Signature

declare class CodeError

Source

Since v0.1.0

Runs code in an isolate that can reach nothing but the tools of the execution, which it gives the code as tools, beside console. An adapter that has such an isolate implements it, as @amends-dev/codemode-opencode does; this package does not.

Signature

export interface CodeRuntime {
/**
* Runs the code, and ends the run when interrupted. It fails with `CodeError` when the code
* throws, and for anything else that stops the run, such as a runtime that cannot start.
*/
readonly run: (execution: Execution) => Effect.Effect<Outcome, CodeError>
}

Source

Since v0.1.0

One run of code, which a CodeRuntime carries out.

Signature

export interface Execution {
/** The code, as the body of an async function, which `return`s what the run gives back. */
readonly code: string
/** The names of the tools the code may call, as `tools.<name>`, which any other name is not. */
readonly tools: ReadonlyArray<string>
/**
* Calls a tool with an input object, which the code gave or left empty, and answers with what the
* tool gave, or fails as the tool failed. The code reads a failure as an error it can catch.
*/
readonly call: (tool: string, input: Schema.JsonObject) => Effect.Effect<Schema.Json, ToolSource.Failure>
}

Source

Since v0.1.0

What toolkit takes besides the toolkit it presents and the runtime.

Signature

export interface Options {
/** How long a run may take, which its tool calls count in. A minute by default. */
readonly timeout?: Duration.Input
/** The most characters of JSON a run may return. 50,000 by default. */
readonly maxResultLength?: number
}

Source

Since v0.1.0

What a run gave back, which is what the model reads of execute when the code finishes.

Signature

declare const Outcome: Schema.Struct<{
readonly result: Schema.Codec<Schema.Json, Schema.Json, never, never>
readonly logs: Schema.$Array<Schema.String>
}>

Source

Since v0.1.0

Signature

export interface Outcome extends Schema.Schema.Type<typeof Outcome> {}

Source

Since v0.1.0