Skip to main content
Orchestrate

Subagents

Let an agent hand work to other agents, each in its own Actor.

A subagent is another agent. A tool on the lead agent calls it by key, like any other Actor.

Lead agentresearch toolResearcherResearcherResearcherpromptanswer,then finish()
import { Type } from "@earendil-works/pi-ai";
import { defineTool } from "@earendil-works/pi-coding-agent";
import { pi } from "@rivet-dev/pi";
import { type Registry, setup } from "rivetkit";
import { createClient } from "rivetkit/client";

const research = defineTool({
	name: "research",
	label: "Research",
	description: "Research several questions at once. Each question gets its own agent.",
	parameters: Type.Object({ questions: Type.Array(Type.String()) }),
	async execute(_toolCallId, { questions }) {
		const answers = await Promise.all(questions.map(askResearcher));
		return { content: answers.map((text) => ({ type: "text" as const, text })), details: undefined };
	},
});

const lead = pi({ model: "anthropic/claude-opus-5-5", customTools: [research] });

const researcher = pi({
	model: "anthropic/claude-opus-5-5",
	actions: { finish: (c) => c.destroy() },
});

const client = createClient<Registry<{ researcher: typeof researcher }>>();

export const registry = setup({ use: { lead, researcher } });

async function askResearcher(question: string) {
	const subagent = client.researcher.getOrCreate([crypto.randomUUID()]);
	await subagent.prompt(question);
	const answer = await subagent.getLastAssistantText();
	await subagent.finish();
	return `${question}\n${answer}`;
}
  • research gives each question its own researcher, with a new key, and prompts them all at once. It returns their answers to the lead as the tool result.
  • After reading an answer, askResearcher calls finish, which destroys the researcher and its session. Otherwise every question would leave an Actor behind.