Skip to content

Extensions

Code Mode

Code Mode gives an agent one Effect AI Tool for a small JavaScript program. The program can call a fixed set of application Tools through named globals, then return one JSON value. It fits questions that need authorized reads and writes, overlapping independent I/O, and a compact answer.

For example, an invoice analyst can answer a question this way:

const code = `async () => {
const result = await warehouse.query({
sql: "SELECT region, SUM(revenue) AS total FROM invoice_summary GROUP BY region",
});
return result.rows.sort((a, b) => Number(b.total) - Number(a.total))[0];
}`;

warehouse is not a database client. It is a generated global that routes through the runtime’s Tool broker to an application-owned Tool handler. The handler decides which resources the program may read or change.

In your Yielded Agent application, add the Cloudflare executor:

bun add @yielded/agent-platform-cloudflare@beta effect

Keep framework packages at the same release.

This smaller example uses fixed invoice rows so the complete Tool and handler are visible. Generated code calls warehouse.invoices({ region: "emea" }) and computes its answer from those rows. The linked warehouse example replaces the fixed data with a brokered SQL query.

import {
import InMemory
InMemory
,
import CodeMode
CodeMode
,
import Agent
Agent
,
import AgentRuntime
AgentRuntime
} from "@yielded/agent";
import {
const ToolExecutionClass: Reference<ToolExecutionClassValue>

Effect AI Tool annotation key declaring a Tool's execution class, applied with Tool.annotate(ToolExecutionClass, "...").

Unannotated Tools default to "uncertain": security and durability decisions are fail-closed, so the framework never infers a safer class from a Tool's shape.

ToolExecutionClass
} from "@yielded/agent/durable-step";
import {
const CloudflareCodeMode: {
layer: <A, E, R, Handlers, HandlerError, HandlerRequirements>(definition: {
readonly handlers: Layer.Layer<A, E, R>;
}, options: DynamicWorkerCodeExecutorOptions & {
readonly handlers: Layer.Layer<Handlers, HandlerError, HandlerRequirements>;
}) => Layer.Layer<A, E | HandlerError, Exclude<HandlerRequirements, CodeExecutor> | Exclude<Exclude<R, Handlers>, CodeExecutor>>;
}

Assemble Code Mode handlers with the isolated Dynamic Worker executor.

CloudflareCodeMode
} from "@yielded/agent-platform-cloudflare/cloudflare-code-mode";
import {
import OpenAiClient
OpenAiClient
,
import OpenAiLanguageModel
OpenAiLanguageModel
} from "@effect/ai-openai";
import {
import Effect
Effect
,
import Layer
Layer
,
import Redacted
Redacted
,
import Schema
Schema
} from "effect";
import {
import Tool
Tool
,
import Toolkit
Toolkit
} from "effect/ai";
import {
import FetchHttpClient
FetchHttpClient
} from "effect/http";
import {
class WorkerEnvironment

Context service for reading worker bindings from the current env object.

WorkerEnvironment
} from "effect-cf";
// In an application, Wrangler generates these binding types.
declare
namespace global
global
{
namespace
namespace Cloudflare
Cloudflare
{
interface
interface Cloudflare.Env
Env
{
readonly
Cloudflare.Env.LOADER: WorkerLoader
LOADER
:
interface WorkerLoader
WorkerLoader
;
readonly
Cloudflare.Env.OPENAI_API_KEY: string
OPENAI_API_KEY
: string;
}
}
}
const
const ListInvoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>
ListInvoices
=
import Tool
Tool
.
const make: <"list_invoices", Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>, Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>, Schema.Never, undefined, []>(name: "list_invoices", options?: {
readonly description?: string | undefined;
readonly parameters?: Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}> | undefined;
readonly success?: Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>> | undefined;
readonly failure?: Schema.Never | undefined;
readonly failureMode?: undefined;
readonly dependencies?: [] | undefined;
readonly needsApproval?: Tool.NeedsApproval<...> | undefined;
} | undefined) => Tool.Tool<...>

Creates a user-defined tool with the specified name and configuration.

Details

This is the primary constructor for creating custom tools that AI models can call. The tool definition includes parameter validation, success/failure schemas, and optional service dependencies.

If a tool accepts no parameters but still needs an explicit empty object schema, use

EmptyParams

.

Example (Creating a tool without parameters)

import { Schema } from "effect"
import { Tool } from "effect/ai"
// Simple tool with no parameters
const GetCurrentTime = Tool.make("GetCurrentTime", {
description: "Returns the current timestamp",
success: Schema.Number
})
GetCurrentTime.name // => "GetCurrentTime"

@stability ― unstable

@category ― constructors

@since ― 4.0.0

make
("list_invoices", {
description?: string | undefined

An optional description explaining what the tool does.

description
: "Read invoice totals for a region: emea or americas.",
parameters?: Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}> | undefined

Schema defining the parameters this tool accepts.

parameters
:
import Schema
Schema
.
function Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>(fields: {
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}): Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>

Defines a struct schema from a map of field schemas.

Details

Each field value is a schema. Use

optionalKey

or

optional

to mark fields as optional, and

mutableKey

to mark them as mutable.

The resulting schema's Type is a readonly object type with the fields' decoded types. The Encoded form mirrors the field schemas' encoded types. Declared fields may be inherited and are copied to own properties in the output. The __proto__ field is accepted only when it is an own property. Parsing does not guarantee that output keys retain their input order.

Example (Defining a basic struct)

import { Schema } from "effect"
const Person = Schema.Struct({
name: Schema.String,
age: Schema.Number,
email: Schema.optionalKey(Schema.String)
})
// { readonly name: string; readonly age: number; readonly email?: string }
type Person = typeof Person.Type
Schema.decodeUnknownSync(Person)({ name: "Alice", age: 30 }) // => { name: "Alice", age: 30 }

@category ― constructors

@since ― 3.10.0

Struct
({
region: Schema.Literals<readonly ["emea", "americas"]>
region
:
import Schema
Schema
.
function Literals<readonly ["emea", "americas"]>(literals: readonly ["emea", "americas"]): Schema.Literals<readonly ["emea", "americas"]>

Creates a union schema from an array of literal values.

Example (Defining status codes)

import { Schema } from "effect"
const schema = Schema.Literals(["active", "inactive", "pending"])
Schema.decodeSync(schema)("active") // => "active"

@see ― Literal for a schema that represents a single literal.

@category ― constructors

@since ― 4.0.0

Literals
(["emea", "americas"]) }),
success?: Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>> | undefined

Schema for successful tool execution results.

success
:
import Schema
Schema
.
Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>(self: Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>): Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>
export Array

Defines a ReadonlyArray schema for a given element schema.

Example (Defining an array of strings)

import { Schema } from "effect"
const schema = Schema.Array(Schema.String)
Schema.decodeUnknownSync(schema)(["a", "b", "c"]) // => ["a", "b", "c"]

@category ― constructors

@since ― 4.0.0

Array
(
import Schema
Schema
.
function Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>(fields: {
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}): Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>

Defines a struct schema from a map of field schemas.

Details

Each field value is a schema. Use

optionalKey

or

optional

to mark fields as optional, and

mutableKey

to mark them as mutable.

The resulting schema's Type is a readonly object type with the fields' decoded types. The Encoded form mirrors the field schemas' encoded types. Declared fields may be inherited and are copied to own properties in the output. The __proto__ field is accepted only when it is an own property. Parsing does not guarantee that output keys retain their input order.

Example (Defining a basic struct)

import { Schema } from "effect"
const Person = Schema.Struct({
name: Schema.String,
age: Schema.Number,
email: Schema.optionalKey(Schema.String)
})
// { readonly name: string; readonly age: number; readonly email?: string }
type Person = typeof Person.Type
Schema.decodeUnknownSync(Person)({ name: "Alice", age: 30 }) // => { name: "Alice", age: 30 }

@category ― constructors

@since ― 3.10.0

Struct
({
customer: Schema.String
customer
:
import Schema
Schema
.
const String: Schema.String

Type-level representation of

String

.

Schema for string values. Validates that the input is typeof "string".

@category ― models

@since ― 4.0.0

@category ― schemas

@since ― 4.0.0

String
,
revenue: Schema.Number
revenue
:
import Schema
Schema
.
const Number: Schema.Number

Type-level representation of

Number

.

Schema for number values, including NaN, Infinity, and -Infinity.

Details

Default JSON serializer:

  • Finite numbers are serialized as numbers.
  • Non-finite values are serialized as strings ("NaN", "Infinity", "-Infinity").

@category ― models

@since ― 4.0.0

@see ― Finite for a schema that excludes non-finite values.

@category ― schemas

@since ― 4.0.0

Number
})),
}).
Tool<"list_invoices", { readonly parameters: Struct<{ readonly region: Literals<readonly ["emea", "americas"]>; }>; readonly success: $Array<Struct<{ readonly customer: String; readonly revenue: Number; }>>; readonly failure: Never; readonly failureMode: "error"; }, never>.annotate<never, ToolExecutionClassValue>(tag: Key<never, ToolExecutionClassValue>, value: ToolExecutionClassValue): Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>

Add an annotation to the tool.

annotate
(
const ToolExecutionClass: Reference<ToolExecutionClassValue>

Effect AI Tool annotation key declaring a Tool's execution class, applied with Tool.annotate(ToolExecutionClass, "...").

Unannotated Tools default to "uncertain": security and durability decisions are fail-closed, so the framework never infers a safer class from a Tool's shape.

ToolExecutionClass
, "readonly");
const
const InvoiceHandlers: Layer.Layer<Tool.Handler<"list_invoices">, never, never>
InvoiceHandlers
=
import Toolkit
Toolkit
.
const make: <[Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>]>(tools_0: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>) => Toolkit.Toolkit<...>

Creates a new toolkit from the specified tools.

Details

This is the primary constructor for creating toolkits. It accepts multiple tools and organizes them into a toolkit that can be provided to AI language models.

Example (Creating a toolkit)

import { Effect, Schema } from "effect"
import { Tool, Toolkit } from "effect/ai"
const GetCurrentTime = Tool.make("GetCurrentTime", {
description: "Get the current timestamp",
success: Schema.Number
})
const GetWeather = Tool.make("get_weather", {
description: "Get weather information",
parameters: Schema.Struct({ location: Schema.String }),
success: Schema.Struct({
temperature: Schema.Number,
condition: Schema.String
})
})
const toolkit = Toolkit.make(GetCurrentTime, GetWeather)
const ready = toolkit.pipe(Effect.provide(toolkit.toLayer({
GetCurrentTime: () => Effect.succeed(0),
get_weather: () => Effect.succeed({ temperature: 20, condition: "clear" })
})))
Object.keys((await Effect.runPromise(ready)).tools) // => ["GetCurrentTime", "get_weather"]

@stability ― unstable

@category ― constructors

@since ― 4.0.0

make
(
const ListInvoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>
ListInvoices
).
Toolkit<{ readonly list_invoices: Tool<"list_invoices", { readonly parameters: Struct<{ readonly region: Literals<readonly ["emea", "americas"]>; }>; readonly success: $Array<Struct<{ readonly customer: String; readonly revenue: Number; }>>; readonly failure: Never; readonly failureMode: "error"; }, never>; }>.toLayer<{
list_invoices: ({ region }: {
readonly region: "emea" | "americas";
}) => Effect.Effect<{
customer: string;
region: string;
revenue: number;
}[], never, never>;
}, never, never>(build: {
list_invoices: ({ region }: {
readonly region: "emea" | "americas";
}) => Effect.Effect<{
customer: string;
region: string;
revenue: number;
}[], never, never>;
} | Effect.Effect<{
list_invoices: ({ region }: {
readonly region: "emea" | "americas";
}) => Effect.Effect<{
customer: string;
region: string;
revenue: number;
}[], never, never>;
}, never, never>): Layer.Layer<Tool.Handler<"list_invoices">, never, never>

Converts a toolkit into a Layer containing handlers for each tool in the toolkit.

toLayer
({
list_invoices: ({ region }: {
readonly region: "emea" | "americas";
}) => Effect.Effect<{
customer: string;
region: string;
revenue: number;
}[], never, never>
list_invoices
: ({
region: "emea" | "americas"
region
}) =>
import Effect
Effect
.
const succeed: <{
customer: string;
region: string;
revenue: number;
}[]>(value: {
customer: string;
region: string;
revenue: number;
}[]) => Effect.Effect<{
customer: string;
region: string;
revenue: number;
}[], never, never>

Creates an Effect that always succeeds with a given value.

When to use

Use when an effect should complete successfully with a specific value without any errors or external dependencies.

Example (Creating a successful effect)

import { Effect } from "effect"
// Creating an effect that represents a successful scenario
//
// ┌─── Effect<number, never, never>
// ▼
const success = Effect.succeed(42)
Effect.runSync(success) // => 42

@see ― fail to create an effect that represents a failure.

@category ― constructors

@since ― 2.0.0

succeed
(
[
{
customer: string
customer
: "Acme",
region: string
region
: "emea",
revenue: number
revenue
: 12_000 },
{
customer: string
customer
: "Atlas",
region: string
region
: "emea",
revenue: number
revenue
: 8_000 },
{
customer: string
customer
: "Beacon",
region: string
region
: "americas",
revenue: number
revenue
: 15_000 },
].
Array<{ customer: string; region: string; revenue: number; }>.filter(predicate: (value: {
customer: string;
region: string;
revenue: number;
}, index: number, array: {
customer: string;
region: string;
revenue: number;
}[]) => unknown, thisArg?: any): {
customer: string;
region: string;
revenue: number;
}[] (+1 overload)

Returns the elements of an array that meet the condition specified in a callback function.

@param ― predicate A function that accepts up to three arguments. The filter method calls the predicate function one time for each element in the array.

@param ― thisArg An object to which the this keyword can refer in the predicate function. If thisArg is omitted, undefined is used as the this value.

filter
((
invoice: {
customer: string;
region: string;
revenue: number;
}
invoice
) =>
invoice: {
customer: string;
region: string;
revenue: number;
}
invoice
.
region: string
region
===
region: "emea" | "americas"
region
),
),
});
const
const codeMode: CodeMode.CodeModeDefinition<"run_javascript", {
warehouse: {
invoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>;
};
}, never>
codeMode
=
import CodeMode
CodeMode
.
make<"run_javascript", {
warehouse: {
invoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>;
};
}, never>(name: "run_javascript", options: CodeMode.CodeModeOptions<{
warehouse: {
invoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>;
};
}, never>): CodeMode.CodeModeDefinition<...>
export make
make
("run_javascript", {
CodeModeOptions<Namespaces extends CodeModeNamespaces, RedactionRequirements = never>.description: string

Model-visible description; the builder appends the sandbox contract.

description
: "Read invoices, calculate the answer in JavaScript, and return a small JSON result.",
CodeModeOptions<{ warehouse: { invoices: Tool<"list_invoices", { readonly parameters: Struct<{ readonly region: Literals<readonly ["emea", "americas"]>; }>; readonly success: $Array<Struct<{ readonly customer: String; readonly revenue: Number; }>>; readonly failure: Never; readonly failureMode: "error"; }, never>; }; }, never>.tools: {
warehouse: {
invoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>;
};
}

Explicit allowlist: namespace name → method name → native Effect AI Tool. Reads and mutations are allowed; calls requiring additional approval fail closed.

tools
: {
warehouse: {
invoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>;
}
warehouse
: {
invoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>
invoices
:
const ListInvoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>
ListInvoices
} },
CodeModeOptions<Namespaces extends CodeModeNamespaces, RedactionRequirements = never>.maxEgressBytes?: number | undefined

Aggregate model-visible egress budget in UTF-8 bytes across the final result, captured logs, and any thrown value (CAP-016). Default 65536.

maxEgressBytes
: 8 * 1024,
});
const
const analyst: Agent.Definition<Schema.String, Schema.Struct<{
readonly answer: Schema.String;
}>, "Use run_javascript to calculate invoice answers. Return an answer as JSON.", Toolkit.Toolkit<{
readonly run_javascript: CodeMode.CodeModeTool<"run_javascript">;
}>, undefined, undefined, undefined> & {
readonly id: Brand<"@effect-agent/core/AgentId"> & "invoice-analyst";
}
analyst
=
import Agent
Agent
.
function make<"invoice-analyst", Schema.String, Schema.Struct<{
readonly answer: Schema.String;
}>, "Use run_javascript to calculate invoice answers. Return an answer as JSON.", Toolkit.Toolkit<{
readonly run_javascript: CodeMode.CodeModeTool<"run_javascript">;
}>, undefined>(id: "invoice-analyst", options: Agent.DefinitionOptions<Schema.String, Schema.Struct<{
readonly answer: Schema.String;
}>, "Use run_javascript to calculate invoice answers. Return an answer as JSON.", Toolkit.Toolkit<{
readonly run_javascript: CodeMode.CodeModeTool<"run_javascript">;
}>, undefined, undefined, undefined> & {
...;
}): Agent.Definition<...> & {
...;
} (+3 overloads)

Validate an agent ID and return a shallowly frozen, model-agnostic definition.

make
("invoice-analyst", {
DefinitionOptions<String, Struct<{ readonly answer: String; }>, "Use run_javascript to calculate invoice answers. Return an answer as JSON.", Toolkit<{ readonly run_javascript: CodeModeTool<...>; }>, undefined, undefined, undefined>.input: Schema.String
input
:
import Schema
Schema
.
const String: Schema.String

Type-level representation of

String

.

Schema for string values. Validates that the input is typeof "string".

@category ― models

@since ― 4.0.0

@category ― schemas

@since ― 4.0.0

String
,
DefinitionOptions<String, Struct<{ readonly answer: String; }>, "Use run_javascript to calculate invoice answers. Return an answer as JSON.", Toolkit<{ readonly run_javascript: CodeModeTool<...>; }>, undefined, undefined, undefined>.output: Schema.Struct<{
readonly answer: Schema.String;
}>
output
:
import Schema
Schema
.
function Struct<{
readonly answer: Schema.String;
}>(fields: {
readonly answer: Schema.String;
}): Schema.Struct<{
readonly answer: Schema.String;
}>

Defines a struct schema from a map of field schemas.

Details

Each field value is a schema. Use

optionalKey

or

optional

to mark fields as optional, and

mutableKey

to mark them as mutable.

The resulting schema's Type is a readonly object type with the fields' decoded types. The Encoded form mirrors the field schemas' encoded types. Declared fields may be inherited and are copied to own properties in the output. The __proto__ field is accepted only when it is an own property. Parsing does not guarantee that output keys retain their input order.

Example (Defining a basic struct)

import { Schema } from "effect"
const Person = Schema.Struct({
name: Schema.String,
age: Schema.Number,
email: Schema.optionalKey(Schema.String)
})
// { readonly name: string; readonly age: number; readonly email?: string }
type Person = typeof Person.Type
Schema.decodeUnknownSync(Person)({ name: "Alice", age: 30 }) // => { name: "Alice", age: 30 }

@category ― constructors

@since ― 3.10.0

Struct
({
answer: Schema.String
answer
:
import Schema
Schema
.
const String: Schema.String

Type-level representation of

String

.

Schema for string values. Validates that the input is typeof "string".

@category ― models

@since ― 4.0.0

@category ― schemas

@since ― 4.0.0

String
}),
DefinitionOptions<String, Struct<{ readonly answer: String; }>, "Use run_javascript to calculate invoice answers. Return an answer as JSON.", Toolkit<{ readonly run_javascript: CodeModeTool<...>; }>, undefined, undefined, undefined>.instructions: "Use run_javascript to calculate invoice answers. Return an answer as JSON."
instructions
: "Use run_javascript to calculate invoice answers. Return an answer as JSON.",
DefinitionOptions<String, Struct<{ readonly answer: String; }>, "Use run_javascript to calculate invoice answers. Return an answer as JSON.", Toolkit<{ readonly run_javascript: CodeModeTool<...>; }>, undefined, undefined, undefined>.toolkit: Toolkit.Toolkit<{
readonly run_javascript: CodeMode.CodeModeTool<"run_javascript">;
}>
toolkit
:
import Toolkit
Toolkit
.
const make: <[CodeMode.CodeModeTool<"run_javascript">]>(tools_0: CodeMode.CodeModeTool<"run_javascript">) => Toolkit.Toolkit<{
readonly run_javascript: CodeMode.CodeModeTool<"run_javascript">;
}>

Creates a new toolkit from the specified tools.

Details

This is the primary constructor for creating toolkits. It accepts multiple tools and organizes them into a toolkit that can be provided to AI language models.

Example (Creating a toolkit)

import { Effect, Schema } from "effect"
import { Tool, Toolkit } from "effect/ai"
const GetCurrentTime = Tool.make("GetCurrentTime", {
description: "Get the current timestamp",
success: Schema.Number
})
const GetWeather = Tool.make("get_weather", {
description: "Get weather information",
parameters: Schema.Struct({ location: Schema.String }),
success: Schema.Struct({
temperature: Schema.Number,
condition: Schema.String
})
})
const toolkit = Toolkit.make(GetCurrentTime, GetWeather)
const ready = toolkit.pipe(Effect.provide(toolkit.toLayer({
GetCurrentTime: () => Effect.succeed(0),
get_weather: () => Effect.succeed({ temperature: 20, condition: "clear" })
})))
Object.keys((await Effect.runPromise(ready)).tools) // => ["GetCurrentTime", "get_weather"]

@stability ― unstable

@category ― constructors

@since ― 4.0.0

make
(
const codeMode: CodeMode.CodeModeDefinition<"run_javascript", {
warehouse: {
invoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>;
};
}, never>
codeMode
.
CodeModeDefinition<"run_javascript", { warehouse: { invoices: Tool<"list_invoices", { readonly parameters: Struct<{ readonly region: Literals<readonly ["emea", "americas"]>; }>; readonly success: $Array<Struct<{ readonly customer: String; readonly revenue: Number; }>>; readonly failure: Never; readonly failureMode: "error"; }, never>; }; }, never>.tool: CodeMode.CodeModeTool<"run_javascript">

The ordinary Effect AI Tool to include in the model-facing Toolkit.

tool
),
DefinitionOptions<String, Struct<{ readonly answer: String; }>, "Use run_javascript to calculate invoice answers. Return an answer as JSON.", Toolkit<{ readonly run_javascript: CodeModeTool<...>; }>, undefined, undefined, undefined>.policy?: Partial<Readonly<Omit<{
readonly runStatus: "appended" | "off";
readonly maxTurns: number;
readonly maxToolCalls: number;
readonly maxDuration: Duration;
readonly toolConcurrency: number;
readonly repeatedFailureLimit: number;
readonly onExhaustion: "final-answer" | "fail";
readonly completionReserveTokens: number;
readonly toolResultBounds: ToolResultBounds;
readonly compaction: CompactionPolicy;
readonly tokenBudget?: number | undefined;
readonly costBudgetMicrousd?: number | undefined;
readonly contextTokenLimit?: number | undefined;
readonly restartOnJoinedInput?: boolean | undefined;
readonly modelRetries?: number | undefined;
}, "runStatus" | ... 5 more ... | "compaction"> & {
...;
}>> | undefined
policy
: {
maxTurns?: number | undefined
maxTurns
: 3,
maxToolCalls?: number | undefined
maxToolCalls
: 6,
maxDuration?: Input | undefined

Finite, positive wall-clock duration accepted in any Effect Duration input form.

maxDuration
: "45 seconds",
// This sandbox example runs one generated program at a time.
toolConcurrency?: number | undefined
toolConcurrency
: 1,
},
});
const
const AnalystLive: Layer.Layer<Tool.Handler<"run_javascript"> | LanguageModel | ProviderName | ModelName | ThreadHistory | Store | SubagentReservations, never, WorkerEnvironment>
AnalystLive
=
import Layer
Layer
.
const unwrap: <Tool.Handler<"run_javascript"> | LanguageModel | ProviderName | ModelName | ThreadHistory | Store | SubagentReservations, never, never, never, WorkerEnvironment>(self: Effect.Effect<Layer.Layer<Tool.Handler<"run_javascript"> | LanguageModel | ProviderName | ModelName | ThreadHistory | Store | SubagentReservations, never, never>, never, WorkerEnvironment>) => Layer.Layer<...>

Unwraps a Layer from an Effect, flattening the nested structure.

When to use

Use when you have an Effect that produces a Layer and you want to use that layer directly.

Details

The resulting Layer will have the combined error and dependency types from both the outer Effect and the inner Layer.

Example (Unwrapping an effectful layer)

import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
const layerEffect = Effect.succeed(
Layer.succeed(Database, { query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) })
)
const unwrappedLayer = Layer.unwrap(layerEffect)
const program = Database.use((database) => database.query("SELECT 1"))
Effect.runSync(Effect.provide(program, unwrappedLayer)) // => "result"

@category ― converting

@since ― 4.0.0

unwrap
(
import Effect
Effect
.
const gen: <Effect.Effect<Cloudflare.Env, never, WorkerEnvironment>, Layer.Layer<Tool.Handler<"run_javascript"> | LanguageModel | ProviderName | ModelName | ThreadHistory | Store | SubagentReservations, never, never>>(f: () => Generator<Effect.Effect<Cloudflare.Env, never, WorkerEnvironment>, Layer.Layer<Tool.Handler<"run_javascript"> | LanguageModel | ... 4 more ... | SubagentReservations, never, never>, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to use

Use when you want to write effectful code that looks and behaves like synchronous code, while still handling asynchronous tasks, errors, and complex control flow such as loops and conditions.

Generator functions work similarly to async/await but keep errors, requirements, and interruption in the Effect type. You can yield* values from effects and return the final result at the end.

Example (Sequencing effects with generators)

import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
await Effect.runPromise(program) // => "Final amount to charge: 96"

@category ― constructors

@since ― 2.0.0

gen
(function* () {
const
const env: Cloudflare.Env
env
= yield*
class WorkerEnvironment

Context service for reading worker bindings from the current env object.

WorkerEnvironment
;
const
const CodeModeLive: Layer.Layer<Tool.Handler<"run_javascript">, never, never>
CodeModeLive
=
const CloudflareCodeMode: {
layer: <A, E, R, Handlers, HandlerError, HandlerRequirements>(definition: {
readonly handlers: Layer.Layer<A, E, R>;
}, options: DynamicWorkerCodeExecutorOptions & {
readonly handlers: Layer.Layer<Handlers, HandlerError, HandlerRequirements>;
}) => Layer.Layer<A, E | HandlerError, Exclude<HandlerRequirements, CodeExecutor> | Exclude<Exclude<R, Handlers>, CodeExecutor>>;
}

Assemble Code Mode handlers with the isolated Dynamic Worker executor.

CloudflareCodeMode
.
layer: <Tool.Handler<"run_javascript">, never, CodeMode.CodeModeLayerRequirements<{
warehouse: {
invoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>;
};
}, never>, Tool.Handler<"list_invoices">, never, never>(definition: {
...;
}, options: DynamicWorkerCodeExecutorOptions & {
...;
}) => Layer.Layer<...>

Provide the selected tool handlers at construction, where Code Mode captures them. Their errors and remaining dependencies stay visible. The definition still owns the allowlist and limits; the runtime supplies the live Tool broker for each scoped pass.

layer
(
const codeMode: CodeMode.CodeModeDefinition<"run_javascript", {
warehouse: {
invoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly region: Schema.Literals<readonly ["emea", "americas"]>;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly customer: Schema.String;
readonly revenue: Schema.Number;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>;
};
}, never>
codeMode
, {
DynamicWorkerCodeExecutorOptions.loader: WorkerLoader

The worker_loader binding.

loader
:
const env: Cloudflare.Env
env
.
Cloudflare.Env.LOADER: WorkerLoader
LOADER
,
handlers: Layer.Layer<Tool.Handler<"list_invoices">, never, never>
handlers
:
const InvoiceHandlers: Layer.Layer<Tool.Handler<"list_invoices">, never, never>
InvoiceHandlers
,
});
const
const ModelLive: Layer.Layer<LanguageModel | ProviderName | ModelName, never, never>
ModelLive
=
import OpenAiLanguageModel
OpenAiLanguageModel
.
const model: (model: (string & {}) | OpenAiLanguageModel.Model, config?: Omit<{
readonly metadata?: {
readonly [x: string]: string;
} | undefined;
readonly top_logprobs?: number | undefined;
readonly temperature?: number | undefined;
readonly top_p?: number | undefined;
readonly user?: string | undefined;
readonly prompt_cache_key?: string | undefined;
readonly prompt_cache_options?: {
readonly mode?: "explicit" | "implicit" | undefined;
readonly ttl?: "30m" | undefined;
} | undefined;
... 17 more ...;
readonly useItemReferences?: boolean | undefined;
}, "model">) => Model<"openai", LanguageModel, OpenAiClient.OpenAiClient>

Creates an OpenAI model descriptor that can be provided with Effect.provide.

When to use

Use when you want an OpenAI language model value that carries provider and model metadata and can be supplied directly to an Effect program.

@see ― layer for creating a LanguageModel.LanguageModel layer directly

@see ― make for constructing the language model service effectfully

@stability ― unstable

@category ― constructors

@since ― 4.0.0

model
("gpt-6-luna").
Pipeable.pipe<Model<"openai", LanguageModel, OpenAiClient.OpenAiClient>, Layer.Layer<LanguageModel | ProviderName | ModelName, never, never>>(this: Model<"openai", LanguageModel, OpenAiClient.OpenAiClient>, ab: (_: Model<"openai", LanguageModel, OpenAiClient.OpenAiClient>) => Layer.Layer<LanguageModel | ProviderName | ModelName, never, never>): Layer.Layer<...> (+21 overloads)
pipe
(
import Layer
Layer
.
const provide: <never, never, OpenAiClient.OpenAiClient>(that: Layer.Layer<OpenAiClient.OpenAiClient, never, never>) => <RIn2, E2, ROut2>(self: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<ROut2, E2, Exclude<RIn2, OpenAiClient.OpenAiClient>> (+3 overloads)

Feeds the output services of the dependency layer into the requirements of this layer, returning a layer that only provides the services from this layer.

When to use

Use when you need to hide an implementation dependency layer from callers.

Details

In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is built first and is used to satisfy the requirements of serviceLayer.

Example (Providing layer dependencies)

import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const logs: Array<string> = []
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" }
logs // => ["[LOG] Looking up user 123"]

@see ― provideMerge for retaining the dependency services

@category ― providing services

@since ― 2.0.0

provide
(
import OpenAiClient
OpenAiClient
.
const layer: (options: OpenAiClient.Options) => Layer.Layer<OpenAiClient.OpenAiClient, never, HttpClient>

Creates a layer for the OpenAI client with the given options.

When to use

Use when you already have explicit Options values, such as an API key or custom API URL, and want to provide OpenAiClient as a Layer.

@see ― make for constructing the client service effectfully

@see ― layerConfig for loading client settings from Config

@stability ― unstable

@category ― layers

@since ― 4.0.0

layer
({
apiKey?: Redacted.Redacted<string> | undefined

The OpenAI API key.

apiKey
:
import Redacted
Redacted
.
const make: <string>(value: string, options?: {
readonly label?: string | undefined;
}) => Redacted.Redacted<string>

Creates a Redacted wrapper for a sensitive value.

When to use

Use to wrap a sensitive value so normal string, JSON, and inspection output is redacted.

Details

The wrapper redacts string, JSON, and inspection output to reduce accidental disclosure. The original value remains retrievable with Redacted.value until the wrapper is wiped or becomes unreachable.

Example (Creating a redacted value)

import { Redacted } from "effect"
const API_KEY = Redacted.make("1234567890")
String(API_KEY) // => "<redacted>"

@category ― constructors

@since ― 3.3.0

make
(
const env: Cloudflare.Env
env
.
Cloudflare.Env.OPENAI_API_KEY: string
OPENAI_API_KEY
) }).
Pipeable.pipe<Layer.Layer<OpenAiClient.OpenAiClient, never, HttpClient>, Layer.Layer<OpenAiClient.OpenAiClient, never, never>>(this: Layer.Layer<OpenAiClient.OpenAiClient, never, HttpClient>, ab: (_: Layer.Layer<OpenAiClient.OpenAiClient, never, HttpClient>) => Layer.Layer<OpenAiClient.OpenAiClient, never, never>): Layer.Layer<OpenAiClient.OpenAiClient, never, never> (+21 overloads)
pipe
(
import Layer
Layer
.
const provide: <never, never, HttpClient>(that: Layer.Layer<HttpClient, never, never>) => <RIn2, E2, ROut2>(self: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<ROut2, E2, Exclude<RIn2, HttpClient>> (+3 overloads)

Feeds the output services of the dependency layer into the requirements of this layer, returning a layer that only provides the services from this layer.

When to use

Use when you need to hide an implementation dependency layer from callers.

Details

In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is built first and is used to satisfy the requirements of serviceLayer.

Example (Providing layer dependencies)

import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const logs: Array<string> = []
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
Effect.runSync(program) // => { id: "123", name: "DB: SELECT * FROM users WHERE id = 123" }
logs // => ["[LOG] Looking up user 123"]

@see ― provideMerge for retaining the dependency services

@category ― providing services

@since ― 2.0.0

provide
(
import FetchHttpClient
FetchHttpClient
.
const layer: Layer.Layer<HttpClient, never, never>

Layer that provides an HttpClient implementation backed by the configured Fetch function.

When to use

Use when an Effect program should execute HttpClient requests through the platform fetch implementation, especially in browser, edge, or Node.js runtimes with globalThis.fetch.

Details

The layer uses the current Fetch reference and optional RequestInit service for each request. Request-specific method, headers, body, and abort signal are supplied by the client and override matching RequestInit fields.

Gotchas

Fetch behavior comes from the runtime's implementation, so CORS, cookies, redirects, abort handling, and streaming support can vary by platform. Stream request bodies are sent as Web streams with duplex: "half", and any content-length header is removed before calling fetch.

@see ― Fetch for supplying the fetch implementation used by this layer

@see ― RequestInit for default RequestInit options applied before request-specific fields

@stability ― unstable

@category ― layers

@since ― 4.0.0

layer
),
),
),
);
return
import Layer
Layer
.
const mergeAll: <[Layer.Layer<Tool.Handler<"run_javascript">, never, never>, Layer.Layer<LanguageModel | ProviderName | ModelName, never, never>, Layer.Layer<ThreadHistory | Store | SubagentReservations, never, never>]>(layers_0: Layer.Layer<Tool.Handler<"run_javascript">, never, never>, layers_1: Layer.Layer<LanguageModel | ProviderName | ModelName, never, never>, layers_2: Layer.Layer<...>) => Layer.Layer<...>

Combines all the provided layers concurrently, creating a new layer with merged input, error, and output types.

When to use

Use when you need to combine multiple independent layers.

Details

All layers are built concurrently, and their outputs are merged into a single layer.

If multiple merged layers depend on the same layer value, that dependency is shared by default. Reuse a named layer value when you want services to share the same resource, such as one database pool.

Example (Merging independent layers)

import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
const dbLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result"))
})
const logs: Array<string> = []
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => logs.push(msg)))
})
const mergedLayer = Layer.mergeAll(dbLayer, loggerLayer)
const program = Logger.use((logger) => logger.log("ready"))
Effect.runSync(Effect.provide(program, mergedLayer))
logs // => ["ready"]

@see ― merge for merging one layer with another layer or array

@category ― zipping

@since ― 2.0.0

mergeAll
(
const CodeModeLive: Layer.Layer<Tool.Handler<"run_javascript">, never, never>
CodeModeLive
,
const ModelLive: Layer.Layer<LanguageModel | ProviderName | ModelName, never, never>
ModelLive
,
import InMemory
InMemory
.
const layer: Layer.Layer<ThreadHistory | Store | SubagentReservations, never, never>

Run agents and attached subagents with in-memory conversation history. Provide once around the parent program and all child handler Layers so siblings share history and one reservation ledger. Reuse a Thread ID to continue a conversation. Conversations can span any number of Runs within the store's capacity limits. Use scoped for disposable request workflows within this shared store. Each independent Layer build owns fresh state; state is released when its Scope closes. Process loss loses history and active execution; this Layer provides no crash recovery.

Models, tool handlers, and provider clients remain application-supplied. Default IDs need no Layer; enclosing ID and context-preparation overrides are preserved. For storage-backed history, provide PersistentHistory.layer and a shared SubagentReservationsMemoryLive instead. Durable hosts own their own assembly.

layer
);
}),
);
export const
const program: Effect.Effect<{
readonly threadId: string & Brand<"@effect-agent/core/ThreadId">;
readonly runId: string & Brand<"@effect-agent/core/RunId">;
readonly output: {
readonly answer: string;
};
readonly finishReason: "completed" | "model-stop" | "budget-exhausted";
readonly turns: number;
readonly exhausted?: "tokens" | "tool-calls" | "turns" | undefined;
readonly runDisposition?: Schema.Json | undefined;
readonly usage?: RunTotals | undefined;
readonly delegatedUsage?: RunTotals | undefined;
}, AgentRuntime.AgentRuntimeFailure<Agent.Definition<Schema.String, ... 5 more ..., undefined> & {
readonly id: Brand<"@effect-agent/core/AgentId"> & "invoice-analyst";
}, never, never>, WorkerEnvironment>
program
=
import AgentRuntime
AgentRuntime
.
run<Agent.Definition<Schema.String, Schema.Struct<{
readonly answer: Schema.String;
}>, "Use run_javascript to calculate invoice answers. Return an answer as JSON.", Toolkit.Toolkit<{
readonly run_javascript: CodeMode.CodeModeTool<"run_javascript">;
}>, undefined, undefined, undefined> & {
readonly id: Brand<"@effect-agent/core/AgentId"> & "invoice-analyst";
}, never, never>(agent: Agent.Definition<Schema.String, Schema.Struct<{
readonly answer: Schema.String;
}>, ... 4 more ..., undefined> & {
readonly id: Brand<"@effect-agent/core/AgentId"> & "invoice-analyst";
}, input: string, options?: RunOptions<...> | undefined): Effect.Effect<...>
export run

Accept schema-encoded input, retaining runtime validation. Use runUnknown for external data.

run
(
const analyst: Agent.Definition<Schema.String, Schema.Struct<{
readonly answer: Schema.String;
}>, "Use run_javascript to calculate invoice answers. Return an answer as JSON.", Toolkit.Toolkit<{
readonly run_javascript: CodeMode.CodeModeTool<"run_javascript">;
}>, undefined, undefined, undefined> & {
readonly id: Brand<"@effect-agent/core/AgentId"> & "invoice-analyst";
}
analyst
, "What is the total invoice revenue in EMEA?").
Pipeable.pipe<Effect.Effect<{
readonly threadId: string & Brand<"@effect-agent/core/ThreadId">;
readonly runId: string & Brand<"@effect-agent/core/RunId">;
readonly output: {
readonly answer: string;
};
readonly finishReason: "completed" | "model-stop" | "budget-exhausted";
readonly turns: number;
readonly exhausted?: "tokens" | "tool-calls" | "turns" | undefined;
readonly runDisposition?: Schema.Json | undefined;
readonly usage?: RunTotals | undefined;
readonly delegatedUsage?: RunTotals | undefined;
}, AgentRuntime.AgentRuntimeFailure<Agent.Definition<...> & {
...;
}, never, never>, AgentRuntime.AgentRuntimeRequirements<...>>, Effect.Effect<...>, Effect.Effect<...>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect
Effect
.
const provide: <Tool.Handler<"run_javascript"> | LanguageModel | ProviderName | ModelName | ThreadHistory | Store | SubagentReservations, never, WorkerEnvironment>(layer: Layer.Layer<Tool.Handler<"run_javascript"> | LanguageModel | ProviderName | ModelName | ThreadHistory | Store | SubagentReservations, never, WorkerEnvironment>, options?: {
readonly local?: boolean | undefined;
} | undefined) => <A, E, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+5 overloads)

Provides dependencies to an effect using layers or a context. Use options.local to build the layer every time; by default, layers are shared between provide calls.

Example (Providing dependencies with a layer)

import { Context, Effect, Layer } from "effect"
interface Database {
readonly query: (sql: string) => Effect.Effect<string>
}
const Database = Context.Service<Database>("Database")
const DatabaseLayer = Layer.succeed(Database)({
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result for: ${sql}`))
})
const program = Effect.gen(function*() {
const db = yield* Database
return yield* db.query("SELECT * FROM users")
})
const provided = Effect.provide(program, DatabaseLayer)
await Effect.runPromise(provided) // => "Result for: SELECT * FROM users"

@category ― providing services

@since ― 2.0.0

provide
(
const AnalystLive: Layer.Layer<Tool.Handler<"run_javascript"> | LanguageModel | ProviderName | ModelName | ThreadHistory | Store | SubagentReservations, never, WorkerEnvironment>
AnalystLive
),
import Effect
Effect
.
const scoped: <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Scope>>

Runs an effect with a scope that closes when the effect completes.

When to use

Use to acquire scoped resources for the duration of a single workflow.

Details

Finalizers for resources acquired inside the workflow run as soon as the workflow completes, whether by success, failure, or interruption.

Example (Running a scoped acquisition)

import { Effect } from "effect"
const output: Array<unknown> = []
const resource = Effect.acquireRelease(
Effect.sync(() => { output.push("Acquiring resource") }).pipe(Effect.as("resource")),
() => Effect.sync(() => { output.push("Releasing resource") })
)
const program = Effect.scoped(
Effect.gen(function*() {
const res = yield* resource
yield* Effect.sync(() => { output.push(`Using ${res}`) })
return res
})
)
Effect.runSync(program)
output // => ["Acquiring resource", "Using resource", "Releasing resource"]

@category ― resource management

@since ― 2.0.0

scoped
,
);

Only the question is input to the agent. AnalystLive yields WorkerEnvironment to obtain the loader and provider key, leaving that service visible in the composed program’s requirements. An effect-cf Worker supplies it. The application owns the HTTP response and authentication.

CodeMode.make fixes the namespaces and methods visible to generated code. Include codeMode.tool in the agent’s Toolkit. CloudflareCodeMode.layer supplies the selected Tool handlers and executor at construction, capturing the services used by inner calls. Handler construction errors and remaining service requirements stay visible. The runtime supplies its own Tool broker. For a custom executor, provide it and the selected handlers directly to codeMode.handlers.

Code Mode accepts read and mutation Tools without additional approval requirements. The broker retains parameter and result schemas, visibility, inherited grants, host action-time authorization, and run budgets. RunToolAuthorization receives each inner call with its programmatic parent identity before reservation and execution. Approving the outer Tool does not authorize its inner calls. Already authorized calls require no additional approval round trip; Tools declaring needsApproval remain unsupported and fail closed. Enforce resource and tenant access inside handlers. For read-only workloads, use a read-only database identity where available. The warehouse example’s Durable Object uses an application SQL allowlist because its SQLite authorizer blocks PRAGMA query_only. That scanner is a demo boundary.

For a large allowlist, set includeDeclarations: false to keep namespace inventories and full declarations out of the initial tool description. Add ToolDiscovery.make beside the execution tool. Discovery returns only matching, currently eligible methods and their encoded schemas.

import {
import Agent
Agent
,
import CodeMode
CodeMode
,
import ToolDiscovery
ToolDiscovery
} from "@yielded/agent";
import {
const ToolExecutionClass: Reference<ToolExecutionClassValue>

Effect AI Tool annotation key declaring a Tool's execution class, applied with Tool.annotate(ToolExecutionClass, "...").

Unannotated Tools default to "uncertain": security and durability decisions are fail-closed, so the framework never infers a safer class from a Tool's shape.

ToolExecutionClass
} from "@yielded/agent/durable-step";
import {
import Schema
Schema
} from "effect";
import {
import Tool
Tool
,
import Toolkit
Toolkit
} from "effect/ai";
const
const ListInvoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly customer: Schema.String;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly amountCents: Schema.Int;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>
ListInvoices
=
import Tool
Tool
.
const make: <"list_invoices", Schema.Struct<{
readonly customer: Schema.String;
}>, Schema.$Array<Schema.Struct<{
readonly amountCents: Schema.Int;
}>>, Schema.Never, undefined, []>(name: "list_invoices", options?: {
readonly description?: string | undefined;
readonly parameters?: Schema.Struct<{
readonly customer: Schema.String;
}> | undefined;
readonly success?: Schema.$Array<Schema.Struct<{
readonly amountCents: Schema.Int;
}>> | undefined;
readonly failure?: Schema.Never | undefined;
readonly failureMode?: undefined;
readonly dependencies?: [] | undefined;
readonly needsApproval?: Tool.NeedsApproval<...> | undefined;
} | undefined) => Tool.Tool<...>

Creates a user-defined tool with the specified name and configuration.

Details

This is the primary constructor for creating custom tools that AI models can call. The tool definition includes parameter validation, success/failure schemas, and optional service dependencies.

If a tool accepts no parameters but still needs an explicit empty object schema, use

EmptyParams

.

Example (Creating a tool without parameters)

import { Schema } from "effect"
import { Tool } from "effect/ai"
// Simple tool with no parameters
const GetCurrentTime = Tool.make("GetCurrentTime", {
description: "Returns the current timestamp",
success: Schema.Number
})
GetCurrentTime.name // => "GetCurrentTime"

@stability ― unstable

@category ― constructors

@since ― 4.0.0

make
("list_invoices", {
description?: string | undefined

An optional description explaining what the tool does.

description
: "Read invoice amounts for a customer.",
parameters?: Schema.Struct<{
readonly customer: Schema.String;
}> | undefined

Schema defining the parameters this tool accepts.

parameters
:
import Schema
Schema
.
function Struct<{
readonly customer: Schema.String;
}>(fields: {
readonly customer: Schema.String;
}): Schema.Struct<{
readonly customer: Schema.String;
}>

Defines a struct schema from a map of field schemas.

Details

Each field value is a schema. Use

optionalKey

or

optional

to mark fields as optional, and

mutableKey

to mark them as mutable.

The resulting schema's Type is a readonly object type with the fields' decoded types. The Encoded form mirrors the field schemas' encoded types. Declared fields may be inherited and are copied to own properties in the output. The __proto__ field is accepted only when it is an own property. Parsing does not guarantee that output keys retain their input order.

Example (Defining a basic struct)

import { Schema } from "effect"
const Person = Schema.Struct({
name: Schema.String,
age: Schema.Number,
email: Schema.optionalKey(Schema.String)
})
// { readonly name: string; readonly age: number; readonly email?: string }
type Person = typeof Person.Type
Schema.decodeUnknownSync(Person)({ name: "Alice", age: 30 }) // => { name: "Alice", age: 30 }

@category ― constructors

@since ― 3.10.0

Struct
({
customer: Schema.String
customer
:
import Schema
Schema
.
const String: Schema.String

Type-level representation of

String

.

Schema for string values. Validates that the input is typeof "string".

@category ― models

@since ― 4.0.0

@category ― schemas

@since ― 4.0.0

String
}),
success?: Schema.$Array<Schema.Struct<{
readonly amountCents: Schema.Int;
}>> | undefined

Schema for successful tool execution results.

success
:
import Schema
Schema
.
Array<Schema.Struct<{
readonly amountCents: Schema.Int;
}>>(self: Schema.Struct<{
readonly amountCents: Schema.Int;
}>): Schema.$Array<Schema.Struct<{
readonly amountCents: Schema.Int;
}>>
export Array

Defines a ReadonlyArray schema for a given element schema.

Example (Defining an array of strings)

import { Schema } from "effect"
const schema = Schema.Array(Schema.String)
Schema.decodeUnknownSync(schema)(["a", "b", "c"]) // => ["a", "b", "c"]

@category ― constructors

@since ― 4.0.0

Array
(
import Schema
Schema
.
function Struct<{
readonly amountCents: Schema.Int;
}>(fields: {
readonly amountCents: Schema.Int;
}): Schema.Struct<{
readonly amountCents: Schema.Int;
}>

Defines a struct schema from a map of field schemas.

Details

Each field value is a schema. Use

optionalKey

or

optional

to mark fields as optional, and

mutableKey

to mark them as mutable.

The resulting schema's Type is a readonly object type with the fields' decoded types. The Encoded form mirrors the field schemas' encoded types. Declared fields may be inherited and are copied to own properties in the output. The __proto__ field is accepted only when it is an own property. Parsing does not guarantee that output keys retain their input order.

Example (Defining a basic struct)

import { Schema } from "effect"
const Person = Schema.Struct({
name: Schema.String,
age: Schema.Number,
email: Schema.optionalKey(Schema.String)
})
// { readonly name: string; readonly age: number; readonly email?: string }
type Person = typeof Person.Type
Schema.decodeUnknownSync(Person)({ name: "Alice", age: 30 }) // => { name: "Alice", age: 30 }

@category ― constructors

@since ― 3.10.0

Struct
({
amountCents: Schema.Int
amountCents
:
import Schema
Schema
.
const Int: Schema.Int

Type-level representation of

Int

.

Schema for integers, rejecting NaN, Infinity, and -Infinity.

@category ― models

@since ― 3.10.0

@category ― schemas

@since ― 3.10.0

Int
})),
}).
Tool<"list_invoices", { readonly parameters: Struct<{ readonly customer: String; }>; readonly success: $Array<Struct<{ readonly amountCents: Int; }>>; readonly failure: Never; readonly failureMode: "error"; }, never>.annotate<never, ToolExecutionClassValue>(tag: Key<never, ToolExecutionClassValue>, value: ToolExecutionClassValue): Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly customer: Schema.String;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly amountCents: Schema.Int;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>

Add an annotation to the tool.

annotate
(
const ToolExecutionClass: Reference<ToolExecutionClassValue>

Effect AI Tool annotation key declaring a Tool's execution class, applied with Tool.annotate(ToolExecutionClass, "...").

Unannotated Tools default to "uncertain": security and durability decisions are fail-closed, so the framework never infers a safer class from a Tool's shape.

ToolExecutionClass
, "readonly");
export const
const codeMode: CodeMode.CodeModeDefinition<"run_javascript", {
billing: {
invoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly customer: Schema.String;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly amountCents: Schema.Int;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>;
};
}, never>
codeMode
=
import CodeMode
CodeMode
.
make<"run_javascript", {
billing: {
invoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly customer: Schema.String;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly amountCents: Schema.Int;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>;
};
}, never>(name: "run_javascript", options: CodeMode.CodeModeOptions<{
billing: {
invoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly customer: Schema.String;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly amountCents: Schema.Int;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>;
};
}, never>): CodeMode.CodeModeDefinition<...>
export make
make
("run_javascript", {
CodeModeOptions<Namespaces extends CodeModeNamespaces, RedactionRequirements = never>.description: string

Model-visible description; the builder appends the sandbox contract.

description
: "Use discovered methods to compute invoice answers in JavaScript.",
CodeModeOptions<Namespaces extends CodeModeNamespaces, RedactionRequirements = never>.includeDeclarations?: boolean | undefined

Include all sandbox declarations in the model-facing description. Defaults to true.

includeDeclarations
: false,
CodeModeOptions<{ billing: { invoices: Tool<"list_invoices", { readonly parameters: Struct<{ readonly customer: String; }>; readonly success: $Array<Struct<{ readonly amountCents: Int; }>>; readonly failure: Never; readonly failureMode: "error"; }, never>; }; }, never>.tools: {
billing: {
invoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly customer: Schema.String;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly amountCents: Schema.Int;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>;
};
}

Explicit allowlist: namespace name → method name → native Effect AI Tool. Reads and mutations are allowed; calls requiring additional approval fail closed.

tools
: {
billing: {
invoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly customer: Schema.String;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly amountCents: Schema.Int;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>;
}
billing
: {
invoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly customer: Schema.String;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly amountCents: Schema.Int;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>
invoices
:
const ListInvoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly customer: Schema.String;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly amountCents: Schema.Int;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>
ListInvoices
} },
});
export const
const discovery: Readonly<{
tool: Tool.Tool<"discover_tools", {
readonly parameters: Schema.Struct<{
readonly query: Schema.NonEmptyString;
readonly namespace: Schema.optionalKey<Schema.NonEmptyString>;
}>;
readonly success: Schema.Struct<{
readonly toolNames: Schema.$Array<Schema.NonEmptyString>;
readonly matches: Schema.$Array<typeof ToolDiscovery.Match>;
readonly notice: Schema.optionalKey<Schema.String>;
}>;
readonly failure: Schema.Union<readonly [Schema.Codec<never, never, never, never>, typeof ToolDiscovery.ToolDiscoveryError]>;
readonly failureMode: "error";
}, CurrentToolCatalog>;
toolkit: Toolkit.Toolkit<...>;
handlers: Layer<...>;
}>
discovery
=
import ToolDiscovery
ToolDiscovery
.
const make: <Schema.Never, never>(options?: ToolDiscovery.Options<Schema.Never, never>) => Readonly<{
tool: Tool.Tool<"discover_tools", {
readonly parameters: Schema.Struct<{
readonly query: Schema.NonEmptyString;
readonly namespace: Schema.optionalKey<Schema.NonEmptyString>;
}>;
readonly success: Schema.Struct<{
readonly toolNames: Schema.$Array<Schema.NonEmptyString>;
readonly matches: Schema.$Array<typeof ToolDiscovery.Match>;
readonly notice: Schema.optionalKey<Schema.String>;
}>;
readonly failure: Schema.Union<...>;
readonly failureMode: "error";
}, CurrentToolCatalog>;
toolkit: Toolkit.Toolkit<...>;
handlers: Layer<...>;
}>

Build one native discover_tools Tool and its singleton Toolkit/handler Layer. Include the Tool beside the application's existing native Tools. The engine owns catalogue authority and applies successful native selections after a complete Tool batch; the handler mutates no exposure state. Default search matches all case-insensitive whitespace-separated terms against names, descriptions, methods and namespace hints, ordered by catalogue id.

make
();
export const
const analyst: Agent.Definition<Schema.String, Schema.Struct<{
readonly answer: Schema.String;
}>, "Discover invoice methods, compute the answer, then return JSON.", Toolkit.Toolkit<{
readonly discover_tools: Tool.Tool<"discover_tools", {
readonly parameters: Schema.Struct<{
readonly query: Schema.NonEmptyString;
readonly namespace: Schema.optionalKey<Schema.NonEmptyString>;
}>;
readonly success: Schema.Struct<{
readonly toolNames: Schema.$Array<Schema.NonEmptyString>;
readonly matches: Schema.$Array<typeof ToolDiscovery.Match>;
readonly notice: Schema.optionalKey<Schema.String>;
}>;
readonly failure: Schema.Union<readonly [Schema.Codec<never, never, never, never>, typeof ToolDiscovery.ToolDiscoveryError]>;
readonly failureMode: "error";
}, CurrentToolCatalog>;
readonly run_javascript: CodeMode.CodeModeTool<...>;
}>, undefined, undefined, undefined> & {
...;
}
analyst
=
import Agent
Agent
.
function make<"invoice-discovery", Schema.String, Schema.Struct<{
readonly answer: Schema.String;
}>, "Discover invoice methods, compute the answer, then return JSON.", Toolkit.Toolkit<{
readonly discover_tools: Tool.Tool<"discover_tools", {
readonly parameters: Schema.Struct<{
readonly query: Schema.NonEmptyString;
readonly namespace: Schema.optionalKey<Schema.NonEmptyString>;
}>;
readonly success: Schema.Struct<{
readonly toolNames: Schema.$Array<Schema.NonEmptyString>;
readonly matches: Schema.$Array<typeof ToolDiscovery.Match>;
readonly notice: Schema.optionalKey<...>;
}>;
readonly failure: Schema.Union<...>;
readonly failureMode: "error";
}, CurrentToolCatalog>;
readonly run_javascript: CodeMode.CodeModeTool<...>;
}>, undefined>(id: "invoice-discovery", options: Agent.DefinitionOptions<...> & {
...;
}): Agent.Definition<...> & {
...;
} (+3 overloads)

Validate an agent ID and return a shallowly frozen, model-agnostic definition.

make
("invoice-discovery", {
DefinitionOptions<String, Struct<{ readonly answer: String; }>, "Discover invoice methods, compute the answer, then return JSON.", Toolkit<{ readonly discover_tools: Tool<"discover_tools", { ...; }, CurrentToolCatalog>; readonly run_javascript: CodeModeTool<...>; }>, undefined, undefined, undefined>.input: Schema.String
input
:
import Schema
Schema
.
const String: Schema.String

Type-level representation of

String

.

Schema for string values. Validates that the input is typeof "string".

@category ― models

@since ― 4.0.0

@category ― schemas

@since ― 4.0.0

String
,
DefinitionOptions<String, Struct<{ readonly answer: String; }>, "Discover invoice methods, compute the answer, then return JSON.", Toolkit<{ readonly discover_tools: Tool<"discover_tools", { ...; }, CurrentToolCatalog>; readonly run_javascript: CodeModeTool<...>; }>, undefined, undefined, undefined>.output: Schema.Struct<{
readonly answer: Schema.String;
}>
output
:
import Schema
Schema
.
function Struct<{
readonly answer: Schema.String;
}>(fields: {
readonly answer: Schema.String;
}): Schema.Struct<{
readonly answer: Schema.String;
}>

Defines a struct schema from a map of field schemas.

Details

Each field value is a schema. Use

optionalKey

or

optional

to mark fields as optional, and

mutableKey

to mark them as mutable.

The resulting schema's Type is a readonly object type with the fields' decoded types. The Encoded form mirrors the field schemas' encoded types. Declared fields may be inherited and are copied to own properties in the output. The __proto__ field is accepted only when it is an own property. Parsing does not guarantee that output keys retain their input order.

Example (Defining a basic struct)

import { Schema } from "effect"
const Person = Schema.Struct({
name: Schema.String,
age: Schema.Number,
email: Schema.optionalKey(Schema.String)
})
// { readonly name: string; readonly age: number; readonly email?: string }
type Person = typeof Person.Type
Schema.decodeUnknownSync(Person)({ name: "Alice", age: 30 }) // => { name: "Alice", age: 30 }

@category ― constructors

@since ― 3.10.0

Struct
({
answer: Schema.String
answer
:
import Schema
Schema
.
const String: Schema.String

Type-level representation of

String

.

Schema for string values. Validates that the input is typeof "string".

@category ― models

@since ― 4.0.0

@category ― schemas

@since ― 4.0.0

String
}),
DefinitionOptions<String, Struct<{ readonly answer: String; }>, "Discover invoice methods, compute the answer, then return JSON.", Toolkit<{ readonly discover_tools: Tool<"discover_tools", { ...; }, CurrentToolCatalog>; readonly run_javascript: CodeModeTool<...>; }>, undefined, undefined, undefined>.instructions: "Discover invoice methods, compute the answer, then return JSON."
instructions
: "Discover invoice methods, compute the answer, then return JSON.",
DefinitionOptions<String, Struct<{ readonly answer: String; }>, "Discover invoice methods, compute the answer, then return JSON.", Toolkit<{ readonly discover_tools: Tool<"discover_tools", { ...; }, CurrentToolCatalog>; readonly run_javascript: CodeModeTool<...>; }>, undefined, undefined, undefined>.toolkit: Toolkit.Toolkit<{
readonly discover_tools: Tool.Tool<"discover_tools", {
readonly parameters: Schema.Struct<{
readonly query: Schema.NonEmptyString;
readonly namespace: Schema.optionalKey<Schema.NonEmptyString>;
}>;
readonly success: Schema.Struct<{
readonly toolNames: Schema.$Array<Schema.NonEmptyString>;
readonly matches: Schema.$Array<typeof ToolDiscovery.Match>;
readonly notice: Schema.optionalKey<Schema.String>;
}>;
readonly failure: Schema.Union<readonly [Schema.Codec<never, never, never, never>, typeof ToolDiscovery.ToolDiscoveryError]>;
readonly failureMode: "error";
}, CurrentToolCatalog>;
readonly run_javascript: CodeMode.CodeModeTool<...>;
}>
toolkit
:
import Toolkit
Toolkit
.
const make: <[Tool.Tool<"discover_tools", {
readonly parameters: Schema.Struct<{
readonly query: Schema.NonEmptyString;
readonly namespace: Schema.optionalKey<Schema.NonEmptyString>;
}>;
readonly success: Schema.Struct<{
readonly toolNames: Schema.$Array<Schema.NonEmptyString>;
readonly matches: Schema.$Array<typeof ToolDiscovery.Match>;
readonly notice: Schema.optionalKey<Schema.String>;
}>;
readonly failure: Schema.Union<readonly [Schema.Codec<never, never, never, never>, typeof ToolDiscovery.ToolDiscoveryError]>;
readonly failureMode: "error";
}, CurrentToolCatalog>, CodeMode.CodeModeTool<...>]>(tools_0: Tool.Tool<...>, tools_1: CodeMode.CodeModeTool<...>) => Toolkit.Toolkit<...>

Creates a new toolkit from the specified tools.

Details

This is the primary constructor for creating toolkits. It accepts multiple tools and organizes them into a toolkit that can be provided to AI language models.

Example (Creating a toolkit)

import { Effect, Schema } from "effect"
import { Tool, Toolkit } from "effect/ai"
const GetCurrentTime = Tool.make("GetCurrentTime", {
description: "Get the current timestamp",
success: Schema.Number
})
const GetWeather = Tool.make("get_weather", {
description: "Get weather information",
parameters: Schema.Struct({ location: Schema.String }),
success: Schema.Struct({
temperature: Schema.Number,
condition: Schema.String
})
})
const toolkit = Toolkit.make(GetCurrentTime, GetWeather)
const ready = toolkit.pipe(Effect.provide(toolkit.toLayer({
GetCurrentTime: () => Effect.succeed(0),
get_weather: () => Effect.succeed({ temperature: 20, condition: "clear" })
})))
Object.keys((await Effect.runPromise(ready)).tools) // => ["GetCurrentTime", "get_weather"]

@stability ― unstable

@category ― constructors

@since ― 4.0.0

make
(
const discovery: Readonly<{
tool: Tool.Tool<"discover_tools", {
readonly parameters: Schema.Struct<{
readonly query: Schema.NonEmptyString;
readonly namespace: Schema.optionalKey<Schema.NonEmptyString>;
}>;
readonly success: Schema.Struct<{
readonly toolNames: Schema.$Array<Schema.NonEmptyString>;
readonly matches: Schema.$Array<typeof ToolDiscovery.Match>;
readonly notice: Schema.optionalKey<Schema.String>;
}>;
readonly failure: Schema.Union<readonly [Schema.Codec<never, never, never, never>, typeof ToolDiscovery.ToolDiscoveryError]>;
readonly failureMode: "error";
}, CurrentToolCatalog>;
toolkit: Toolkit.Toolkit<...>;
handlers: Layer<...>;
}>
discovery
.
tool: Tool.Tool<"discover_tools", {
readonly parameters: Schema.Struct<{
readonly query: Schema.NonEmptyString;
readonly namespace: Schema.optionalKey<Schema.NonEmptyString>;
}>;
readonly success: Schema.Struct<{
readonly toolNames: Schema.$Array<Schema.NonEmptyString>;
readonly matches: Schema.$Array<typeof ToolDiscovery.Match>;
readonly notice: Schema.optionalKey<Schema.String>;
}>;
readonly failure: Schema.Union<readonly [Schema.Codec<never, never, never, never>, typeof ToolDiscovery.ToolDiscoveryError]>;
readonly failureMode: "error";
}, CurrentToolCatalog>
tool
,
const codeMode: CodeMode.CodeModeDefinition<"run_javascript", {
billing: {
invoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly customer: Schema.String;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly amountCents: Schema.Int;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>;
};
}, never>
codeMode
.
CodeModeDefinition<"run_javascript", { billing: { invoices: Tool<"list_invoices", { readonly parameters: Struct<{ readonly customer: String; }>; readonly success: $Array<Struct<{ readonly amountCents: Int; }>>; readonly failure: Never; readonly failureMode: "error"; }, never>; }; }, never>.tool: CodeMode.CodeModeTool<"run_javascript">

The ordinary Effect AI Tool to include in the model-facing Toolkit.

tool
),
DefinitionOptions<InputSchema extends Schema.Top, OutputSchema extends Schema.Top, Instructions extends InstructionSource<InputSchema["Type"], unknown, unknown>, ToolkitValue extends Toolkit.Any, RunDispositionValue extends RunDispositionDeclaration<OutputSchema["Type"], Schema.Top> | undefined = undefined, InputPromptValue extends InputPromptSource<InputSchema["Type"], unknown, unknown> | undefined = undefined, UpdatesSchema extends Schema.Top | undefined = undefined>.toolExposure?: Configuration | undefined
toolExposure
: {
Configuration.initialToolNames?: readonly string[] | undefined
initialToolNames
: [],
Configuration.maxTools?: number | undefined
maxTools
: 8,
Configuration.maxSchemaBytes?: number | undefined
maxSchemaBytes
: 32_768 },
});
// Host-side selective TypeScript declarations; fails with CodeModeDescriptionError.
export const
const invoiceDeclarations: Effect<string, CodeMode.CodeModeDescriptionError, never>
invoiceDeclarations
=
const codeMode: CodeMode.CodeModeDefinition<"run_javascript", {
billing: {
invoices: Tool.Tool<"list_invoices", {
readonly parameters: Schema.Struct<{
readonly customer: Schema.String;
}>;
readonly success: Schema.$Array<Schema.Struct<{
readonly amountCents: Schema.Int;
}>>;
readonly failure: Schema.Never;
readonly failureMode: "error";
}, never>;
};
}, never>
codeMode
.
CodeModeDefinition<"run_javascript", { billing: { invoices: Tool<"list_invoices", { readonly parameters: Struct<{ readonly customer: String; }>; readonly success: $Array<Struct<{ readonly amountCents: Int; }>>; readonly failure: Never; readonly failureMode: "error"; }, never>; }; }, never>.describe: (methods: ReadonlyArray<string>, options?: {
readonly maxBytes?: number | undefined;
}) => Effect<string, CodeMode.CodeModeDescriptionError>

Render complete encoded-schema declarations for 1–64 unique, exact namespace.method names. The UTF-8 byte limit defaults to 16384 and must be an integer from 1 through 262144. Oversized documentation fails rather than truncating a declaration. This host operation does not authorize a model to see the selected methods; filter selections by current visibility and inherited grants before returning its output to a model.

describe
(["billing.invoices"], {
maxBytes?: number | undefined
maxBytes
: 8_192 });

Provide discovery.handlers alongside the existing Code Mode executor/handler Layer. A discovery call with { query: "invoice", namespace: "billing" } describes billing.invoices and selects the owning run_javascript tool for the next turn. Generated code can then call await billing.invoices({ customer: "Acme" }). Common native tools can remain pinned alongside these two tools.

Each match has a distinct ID such as code-mode:run_javascript:billing.invoices, its native tool name, namespace and method. This remains unambiguous when one Tool has several aliases or is also registered natively. Selecting a Code Mode match exposes its outer execution tool; it does not expand the construction-time allowlist. Inner broker calls do not change native exposure.

describe is a host API over that fixed allowlist, not a visibility-filtered model tool. It accepts one to 64 unique exact method paths and defaults to 16 KiB of complete UTF-8 declarations, with a 256 KiB maximum. Invalid paths and excessive output fail with CodeModeDescriptionError. Declarations and discovery results use the native encoded parameter/success schemas; provider schema transformations do not change the sandbox wire contract. The full declarations string remains available to the host even when omitted from the model description.

Use discover_tools for model-facing documentation subject to host visibility and inherited grants. The runtime filters the sandbox’s actual namespaces and methods as well, so generated code cannot enumerate hidden methods. If grants or host policy hide an allowlisted method while includeDeclarations is still true, the runtime refuses the configuration before its full description can leak. Use generic shared descriptions and includeDeclarations: false for that case. Default eager Code Mode behavior remains available when the full allowlist is eligible. Approval, budget and handler authorization constraints continue to apply.

Each generated namespace method returns a Promise. The program must be one async function expression, runs once with no arguments, and returns JSON. console.log output returns with the result. Expected inner Tool failures reject the Promise with a JSON failure envelope, which generated code can catch and handle. Invalid inner arguments are rejected by the broker before their handler starts. Invalid arguments to the outer Code Mode tool, such as an empty code string, return a native ToolParameterValidationError result so the model can correct them without starting the executor.

The Tool broker rejects calls outside the construction-time allowlist. Use Promise.all for independent calls and await for actual dependencies:

async () => {
const project = await tools.createProject({ name: "Launch" });
const tasks = await Promise.all(
["Design", "Build", "Ship"].map((title) => tools.createTask({ projectId: project.id, title })),
);
return { projectId: project.id, tasksCreated: tasks.length };
};

Set limits.maxHostCallConcurrency from 1 through 64 (default 4). Both the executor and broker bound active calls; waiting calls stay in Effect structured concurrency. Independent results return when ready, without waiting for earlier calls. toolConcurrency limits outer Tool Calls, so several simultaneous Code Mode passes can each use their inner concurrency allowance. Set it to 1 when the inner bound should also be the run’s bound.

The executor enforces source, wall-clock, log, result, host-call, and per-host-call byte limits. Code Mode applies maxEgressBytes after optional redaction to the result, logs, and thrown value visible to the model. The agent policy’s maxToolCalls also includes brokered inner calls. See Budgets & bounded autonomy.

The default executor limits include 30 seconds and 64 host calls. Supply a CodeExecutionLimits value through limits when constructing Code Mode to change them; maxWallTime takes an Effect Duration. An agent’s smaller remaining budget still applies. redactEgress can transform the result and logs before the aggregate model-visible byte limit. Its required services remain in the Code Mode handler Layer’s requirements and are captured when that Layer is built. Temporary redactor resources close with each invocation. The redactor must be total: defects and interruption retain their Effect semantics.

Writes are not transactional. A rejected Promise.all ends the program and interrupts outstanding calls; completed writes remain completed. Await every call the result depends on, and use Promise.allSettled when independent failures should not stop the remaining work.

A CodeModeFailure includes invocation-ordered calls with succeeded, failed, uncertain, or not-started status. A confirmed failure does not imply rollback. A started call without a confirmed outcome is uncertain and must be reconciled with the application before retrying. Calls that cannot fit the output budget are counted in omittedCalls; do not assume an omitted call never ran. Evidence takes priority over logs and thrown values when the budget is tight.

Set onPassExit to receive the full ephemeral report after executor fibers and resources close, including timeout, defect, and interruption. The host callback’s Effect service requirements remain visible in the handler Layer. Reports contain tool names and statuses, without copying arguments or results. Existing programmatic Tool spans retain per-call timing and execution identity. No inner Canonical Records or program checkpoints are created; a process loss also loses these local reports.

The outer Tool is always uncertain and Tool.Readonly is false. Under a durable host, an unresolved program enters the ordinary unknown-outcome protocol; it is never automatically replayed, even if its selected Tools happen to be readonly or idempotent. Recovery of a complete JavaScript program requires separate checkpoint/resume semantics.

@yielded/agent-platform-cloudflare supplies dynamicWorkerCodeExecutorLayer. It loads each pass into a fresh Cloudflare Dynamic Worker with globalOutbound: null. Generated code has no ambient network, bindings, secrets, filesystem, or environment. Its only host authority is the scoped RPC capability for allowlisted Tool calls.

Declare a Worker Loader binding in wrangler.jsonc. Cloudflare documents worker_loaders as the binding that gives a Worker access to env.LOADER.

{
"name": "warehouse-analyst",
"main": "src/worker.ts",
"compatibility_date": "2025-05-01",
"worker_loaders": [{ "binding": "LOADER" }],
}

CloudflareCodeMode.layer uses that resolved binding. The lower-level dynamicWorkerCodeExecutorLayer({ loader }) remains available for direct CodeExecutor access.

See Cloudflare’s Dynamic Workers guide for Worker Loader setup and loading modes. This adapter uses load() for a fresh pass.

Code Mode is ephemeral. The executor retains no pass state, and a later pass can run in another isolate. It does not make an Agent durable, persist generated programs, reconnect a lost pass, or replay an unresolved call. Use a Durable Object or another application store for data that must outlive a request. A warehouse application can use a Durable Object for its invoice data.

Use the canonical Cloudflare application for the repository’s deployment setup. A Code Mode integration additionally needs a Worker Loader binding and a bounded Tool allowlist. The broker prevents calls to unlisted Tools, but the application’s handlers still decide which tenant, table, account, or secret may be accessed.

Sandbox execution covers trusted local commands. Its local adapter is unisolated and does not implement the CodeExecutor required here. Browser tools cover page capture, crawl, and interactive passes. Tools with uncertain external effects still require application resource authorization when exposed through Code Mode.