Skip to content

Subagents

Subagents

Give a parent agent a specialist it can call:

subagent-basics.ts
import {
import Agent
Agent
,
import Subagent
Subagent
} from "@yielded/agent";
import {
import Schema
Schema
} from "effect";
import {
import Toolkit
Toolkit
} from "effect/ai";
export const
const Summarize: Subagent.SubagentDelegation<"summarize", Schema.String, Schema.String, string, {}, Schema.String, Schema.Struct<{
readonly output: Schema.String;
readonly budgetExhausted: Schema.Boolean;
}>, Schema.Never, never, never, "error"> & {
readonly target: Agent.Definition<Schema.String, Schema.String, string, Toolkit.Toolkit<{}>, undefined, undefined, undefined> & {
readonly id: Brand<"@effect-agent/core/AgentId"> & "summarizer";
};
}
Summarize
=
import Subagent
Subagent
.
make<"summarize", Schema.String, Schema.String, string, {}, Schema.String, Schema.Struct<{
readonly output: Schema.String;
readonly budgetExhausted: Schema.Boolean;
}>, Schema.Never, never, never, Agent.Definition<Schema.String, Schema.String, string, Toolkit.Toolkit<{}>, undefined, undefined, undefined> & {
readonly id: Brand<"@effect-agent/core/AgentId"> & "summarizer";
}>(name: "summarize", options: Omit<Subagent.SubagentDefineOptions<Schema.String, Schema.String, ... 7 more ..., "error">, "parameters" | ... 3 more ... | "projectResult"> & {
...;
} & {
...;
}): Subagent.SubagentDelegation<...> & {
...;
} (+1 overload)
export make

Expose one child Agent as an attached Effect AI Tool. The nonempty application name is preserved as both Tool name and delegation identity; no prefix is required. Parameters and result projections default to the child's input and result envelope. Throws when the name is empty. Nested Tool visibility follows the effective inherited grant.

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

Model-visible description of the delegated capability.

description
: "Summarize a support case in three sentences.",
target: Agent.Definition<Schema.String, Schema.String, string, Toolkit.Toolkit<{}>, Agent.RunDispositionDeclaration<string, Schema.Top> | undefined, unknown, Schema.Top | undefined> & Agent.Definition<Schema.String, Schema.String, string, Toolkit.Toolkit<{}>, undefined, undefined, undefined> & {
readonly id: Brand<"@effect-agent/core/AgentId"> & "summarizer";
}

The model-agnostic child Agent Definition this delegation targets (SUB-002).

target
:
import Agent
Agent
.
function make<"summarizer", Schema.String, Schema.String, string, Toolkit.Toolkit<{}>, undefined>(id: "summarizer", options: Agent.DefinitionOptions<Schema.String, Schema.String, string, Toolkit.Toolkit<{}>, undefined, undefined, undefined> & {
readonly inputPrompt?: undefined;
readonly runDisposition?: undefined;
}): Agent.Definition<Schema.String, Schema.String, string, Toolkit.Toolkit<{}>, undefined, undefined, undefined> & {
readonly id: Brand<"@effect-agent/core/AgentId"> & "summarizer";
} (+3 overloads)

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

make
("summarizer", {
DefinitionOptions<String, String, string, Toolkit<{}>, 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, String, string, Toolkit<{}>, undefined, undefined, undefined>.output: Schema.String
output
:
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, String, string, Toolkit<{}>, undefined, undefined, undefined>.instructions: string
instructions
: "Summarize the case. Include the issue and next action.",
DefinitionOptions<String, String, string, Toolkit<{}>, undefined, undefined, undefined>.toolkit: Toolkit.Toolkit<{}>
toolkit
:
import Toolkit
Toolkit
.
const empty: Toolkit.Toolkit<{}>

An empty toolkit with no tools.

When to use

Use when you need an empty starting point for building toolkits or a default toolkit value that can be extended with merge.

@stability ― unstable

@category ― constructors

@since ― 4.0.0

empty
,
}),
});
export const
const Support: Agent.Definition<Schema.String, Schema.String, "Use summarize to prepare a concise case summary, then answer the user.", Toolkit.Toolkit<{
readonly summarize: Tool<"summarize", {
readonly parameters: Schema.String;
readonly success: Schema.Struct<{
readonly output: Schema.String;
readonly budgetExhausted: Schema.Boolean;
}>;
readonly failure: Subagent.SubagentToolFailure<Schema.Never>;
readonly failureMode: "error";
}, AgentSpawner | RunEventSink | SubagentDurability>;
}>, undefined, undefined, undefined> & {
...;
}
Support
=
import Agent
Agent
.
function make<"support", Schema.String, Schema.String, "Use summarize to prepare a concise case summary, then answer the user.", Toolkit.Toolkit<{
readonly summarize: Tool<"summarize", {
readonly parameters: Schema.String;
readonly success: Schema.Struct<{
readonly output: Schema.String;
readonly budgetExhausted: Schema.Boolean;
}>;
readonly failure: Subagent.SubagentToolFailure<Schema.Never>;
readonly failureMode: "error";
}, AgentSpawner | RunEventSink | SubagentDurability>;
}>, undefined>(id: "support", options: Agent.DefinitionOptions<...> & {
...;
}): Agent.Definition<...> & {
...;
} (+3 overloads)

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

make
("support", {
DefinitionOptions<String, String, "Use summarize to prepare a concise case summary, then answer the user.", Toolkit<{ readonly summarize: Tool<"summarize", { readonly parameters: String; readonly success: Struct<...>; readonly failure: SubagentToolFailure<...>; readonly failureMode: "error"; }, AgentSpawner | ... 1 more ... | SubagentDurability>; }>, 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, String, "Use summarize to prepare a concise case summary, then answer the user.", Toolkit<{ readonly summarize: Tool<"summarize", { readonly parameters: String; readonly success: Struct<...>; readonly failure: SubagentToolFailure<...>; readonly failureMode: "error"; }, AgentSpawner | ... 1 more ... | SubagentDurability>; }>, undefined, undefined, undefined>.output: Schema.String
output
:
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, String, "Use summarize to prepare a concise case summary, then answer the user.", Toolkit<{ readonly summarize: Tool<"summarize", { readonly parameters: String; readonly success: Struct<...>; readonly failure: SubagentToolFailure<...>; readonly failureMode: "error"; }, AgentSpawner | ... 1 more ... | SubagentDurability>; }>, undefined, undefined, undefined>.instructions: "Use summarize to prepare a concise case summary, then answer the user."
instructions
: "Use summarize to prepare a concise case summary, then answer the user.",
DefinitionOptions<String, String, "Use summarize to prepare a concise case summary, then answer the user.", Toolkit<{ readonly summarize: Tool<"summarize", { readonly parameters: String; readonly success: Struct<...>; readonly failure: SubagentToolFailure<...>; readonly failureMode: "error"; }, AgentSpawner | ... 1 more ... | SubagentDurability>; }>, undefined, undefined, undefined>.toolkit: Toolkit.Toolkit<{
readonly summarize: Tool<"summarize", {
readonly parameters: Schema.String;
readonly success: Schema.Struct<{
readonly output: Schema.String;
readonly budgetExhausted: Schema.Boolean;
}>;
readonly failure: Subagent.SubagentToolFailure<Schema.Never>;
readonly failureMode: "error";
}, AgentSpawner | RunEventSink | SubagentDurability>;
}>
toolkit
:
import Toolkit
Toolkit
.
const make: <[Tool<"summarize", {
readonly parameters: Schema.String;
readonly success: Schema.Struct<{
readonly output: Schema.String;
readonly budgetExhausted: Schema.Boolean;
}>;
readonly failure: Subagent.SubagentToolFailure<Schema.Never>;
readonly failureMode: "error";
}, AgentSpawner | RunEventSink | SubagentDurability>]>(tools_0: Tool<"summarize", {
readonly parameters: Schema.String;
readonly success: Schema.Struct<{
readonly output: Schema.String;
readonly budgetExhausted: Schema.Boolean;
}>;
readonly failure: Subagent.SubagentToolFailure<Schema.Never>;
readonly failureMode: "error";
}, AgentSpawner | ... 1 more ... | SubagentDurability>) => 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 Summarize: Subagent.SubagentDelegation<"summarize", Schema.String, Schema.String, string, {}, Schema.String, Schema.Struct<{
readonly output: Schema.String;
readonly budgetExhausted: Schema.Boolean;
}>, Schema.Never, never, never, "error"> & {
readonly target: Agent.Definition<Schema.String, Schema.String, string, Toolkit.Toolkit<{}>, undefined, undefined, undefined> & {
readonly id: Brand<"@effect-agent/core/AgentId"> & "summarizer";
};
}
Summarize
.
SubagentDelegation<"summarize", String, String, string, {}, String, Struct<{ readonly output: String; readonly budgetExhausted: Boolean; }>, Never, never, never, "error">.tool: Tool<"summarize", {
readonly parameters: Schema.String;
readonly success: Schema.Struct<{
readonly output: Schema.String;
readonly budgetExhausted: Schema.Boolean;
}>;
readonly failure: Subagent.SubagentToolFailure<Schema.Never>;
readonly failureMode: "error";
}, AgentSpawner | RunEventSink | SubagentDurability>

The real Effect AI Tool to include in the parent Toolkit (SUB-001).

tool
),
});

The parent calls summarize like any other tool. The child gets that call’s input, runs with its own instructions and conversation, and returns { output, budgetExhausted }. Its intermediate history stays out of the parent’s context. Each agent can use its own model and toolkit.

Subagent.layer(delegation) requires a model: supply it with Layer.provide(model) or provide it around the parent program. An AutoModel selects from each new child’s delegated task automatically. A shared selection store retains the child’s choice for follow-ups; sibling threads select independently.

This defines the agents. Choose how to run them below.

Kind Parent behavior Use it when
In-memory attached Waits for a tool result; child shares its Scope Restarting the task after a process crash is acceptable
Durable attached Suspends, then resumes with the child’s result The parent needs the answer and progress must survive restarts
Durable background Continues; receives declared updates and a completion report The user should keep chatting while work runs

Both attached forms use Summarize.tool. Durable execution comes from the host you run them on. For background work, expose start and follow-up tools instead:

const
const background: Readonly<{
tools: Subagent.BackgroundTools<"summarizer", String, Struct<{
readonly output: String;
readonly budgetExhausted: Boolean;
}>, Never, {
readonly start: true;
readonly followUp: true;
readonly reportToParent: true;
}>;
toolkit: Toolkit<Subagent.BackgroundTools<"summarizer", String, Struct<{
readonly output: String;
readonly budgetExhausted: Boolean;
}>, Never, {
readonly start: true;
readonly followUp: true;
readonly reportToParent: true;
}>>;
layer: Layer<...>;
}>
background
=
import Subagent
Subagent
.
function background<"summarizer", String, String, string, {}, {
readonly start: true;
readonly followUp: true;
readonly reportToParent: true;
}>(target: Definition<String, String, string, Toolkit<{}>, RunDispositionDeclaration<string, Top> | undefined, unknown, Top | undefined> & {
readonly id: Brand<"@effect-agent/core/AgentId"> & "summarizer";
}, selected: {
readonly start: true;
readonly followUp: true;
readonly reportToParent: true;
}): Readonly<{
tools: Subagent.BackgroundTools<"summarizer", String, Struct<...>, Never, {
...;
}>;
toolkit: Toolkit<...>;
layer: Layer<...>;
}> (+1 overload)

Derive selected background Tools directly from a child Agent, using its ID as the delegation name and its input/output Schemas as the default contract. Pass an explicit Subagent.make declaration to customize the name, projections, grants, or policy bounds.

background
(
const Summarize: Subagent.SubagentDelegation<"summarize", String, String, string, {}, String, Struct<{
readonly output: String;
readonly budgetExhausted: Boolean;
}>, Never, never, never, "error"> & {
readonly target: Definition<String, String, string, Toolkit<{}>, undefined, undefined, undefined> & {
readonly id: Brand<"@effect-agent/core/AgentId"> & "summarizer";
};
}
Summarize
.
target: Definition<String, String, string, Toolkit<{}>, RunDispositionDeclaration<string, Top> | undefined, unknown, Top | undefined> & Definition<String, String, string, Toolkit<{}>, undefined, undefined, undefined> & {
readonly id: Brand<"@effect-agent/core/AgentId"> & "summarizer";
}

The model-agnostic child Agent Definition this delegation targets (SUB-002).

target
, {
start: true
start
: true,
followUp: true
followUp
: true,
reportToParent: true
reportToParent
: true,
});

Give the parent background.toolkit and provide background.layer for its handlers. The background guide shows how findings become new input to the parent.

Attached children can run concurrently, but the parent’s next model call waits for the batch to settle. A durable parent releases its execution slot while waiting and recovers the same child after a restart. Aborting the parent propagates cancellation to attached children.

Background workers keep running after the parent finishes or aborts. Follow-ups continue the same child thread. Durable hosts recover their accepted work and pending report delivery.

All three forms enforce permissions and budgets. Parent tools are not inherited. See the subagent reference for projections, nested delegation, and limits, or durability for recovery of uncertain external actions.

Looking for a section from the previous guide?

Child definitions, delegation tools, and model Layers live in the in-memory attached walkthrough.

Durable registration and recovery now live in the durable attached guide.

Starting workers, follow-ups, and replies now live in the background guide.

Advanced policies now live in the subagent reference.

Peer routes now live in Agent messaging.