INTEGRITY Документация

Agents как инструменты

Agents как инструменты позволяют одному чат-агенту поручить часть своей работы другому дочернему агенту, способному вести чат. Потомок представляет собой полноценного дочернего агента со своим собственным хранилищем Durable Object, сообщениями, инструментами, возобновляемым потоком и URL для детального просмотра. Родитель ведёт небольшой реестр запусков, благодаря которому клиенты могут отобразить временную шкалу потомка, воспроизвести её после обновления страницы и позже удалить.

Agents как инструменты поддерживают @cloudflare/think агенты и AIChatAgent подклассы. AIChatAgent потомки выполняются в headless-режиме через saveMessages(), поэтому им следует использовать инструменты на стороне сервера. Клиентские инструменты, предоставляемые браузером, недоступны во время хода агентного инструмента, если только вы не смоделируете это взаимодействие как состояние на стороне сервера или как отдельный workflow, опосредованный родительским агентом.

Agents как инструменты в сравнении с RPC дочернего агента

Используйте subAgent(...).chat() когда родительскому коду нужен прямой потоковый RPC к конкретному дочернему агенту, а ваш код сам управляет пересылкой, отменой и политикой повтора.

Используйте agentTool() или runAgentTool() когда родительская модель или workflow делегирует работу дочернему агенту и вам нужны сохранённые дочерние запуски, event replay, проброс abort и детализация в UI. Сведения о специфичных для Think решениях по ходу см. в Выберите API ходов.

Используйте агента как инструмент AI SDK

Используйте agentTool() когда решение о вызове вспомогательной функции должно принимать родительская модель.

import { Think } from "@cloudflare/think";
import { agentTool } from "agents/agent-tools";
import { z } from "zod";

export class Researcher extends Think {
	getSystemPrompt() {
		return "Research the user's topic and end with a concise summary.";
	}
}

export class Assistant extends Think {
	getTools() {
		return {
			research: agentTool(Researcher, {
				description: "Research one topic in depth.",
				displayName: "Researcher",
				inputSchema: z.object({
					query: z.string().min(3),
				}),
			}),
		};
	}
}
import { Think } from "@cloudflare/think";
import { agentTool } from "agents/agent-tools";
import { z } from "zod";

export class Researcher extends Think<Env> {
	getSystemPrompt() {
		return "Research the user's topic and end with a concise summary.";
	}
}

export class Assistant extends Think<Env> {
	getTools() {
		return {
			research: agentTool(Researcher, {
				description: "Research one topic in depth.",
				displayName: "Researcher",
				inputSchema: z.object({
					query: z.string().min(3),
				}),
			}),
		};
	}
}

Дочерний класс также может быть AIChatAgent:

import { AIChatAgent } from "@cloudflare/ai-chat";
import { agentTool } from "agents/agent-tools";
import { convertToModelMessages, stepCountIs, streamText } from "ai";
import { z } from "zod";

export class Summarizer extends AIChatAgent {
	formatAgentToolInput(input, request) {
		return {
			id: `agent-tool-${request.runId}-input`,
			role: "user",
			parts: [{ type: "text", text: `Summarize:\n\n${input.text}` }],
		};
	}

	async onChatMessage() {
		const result = streamText({
			model: this.env.MODEL,
			messages: await convertToModelMessages(this.messages),
		});
		return result.toUIMessageStreamResponse();
	}
}

export class Assistant extends AIChatAgent {
	async onChatMessage() {
		const result = streamText({
			model: this.env.MODEL,
			messages: await convertToModelMessages(this.messages),
			tools: {
				summarize: agentTool(Summarizer, {
					description: "Summarize long text in a separate retained agent.",
					inputSchema: z.object({ text: z.string() }),
				}),
			},
			stopWhen: stepCountIs(5),
		});

		return result.toUIMessageStreamResponse();
	}
}
import { AIChatAgent } from "@cloudflare/ai-chat";
import { agentTool } from "agents/agent-tools";
import { convertToModelMessages, stepCountIs, streamText } from "ai";
import { z } from "zod";

export class Summarizer extends AIChatAgent<Env> {
	protected override formatAgentToolInput(input: { text: string }, request) {
		return {
			id: `agent-tool-${request.runId}-input`,
			role: "user",
			parts: [{ type: "text", text: `Summarize:\n\n${input.text}` }],
		};
	}

	async onChatMessage() {
		const result = streamText({
			model: this.env.MODEL,
			messages: await convertToModelMessages(this.messages),
		});
		return result.toUIMessageStreamResponse();
	}
}

export class Assistant extends AIChatAgent<Env> {
	async onChatMessage() {
		const result = streamText({
			model: this.env.MODEL,
			messages: await convertToModelMessages(this.messages),
			tools: {
				summarize: agentTool(Summarizer, {
					description: "Summarize long text in a separate retained agent.",
					inputSchema: z.object({ text: z.string() }),
				}),
			},
			stopWhen: stepCountIs(5),
		});

		return result.toUIMessageStreamResponse();
	}
}

Сгенерированный инструмент вызывает this.runAgentTool(ChildAgent, ...), передаёт потоково agent-tool-event фреймы через родительский WebSocket и возвращает сводку дочернего агента родительской модели. Если выполнение завершается ошибкой, прерывается или останавливается, инструмент возвращает структурированную AgentToolFailure вместо пустого значения успешного результата:

type AgentToolFailure = {
	ok: false;
	status: "error" | "aborted" | "interrupted";
	error: string; // human-readable, safe to surface
	retryable: boolean;
	// Present only when `status` is "interrupted":
	reason?: AgentToolInterruptedReason;
	childStillRunning?: boolean;
};

type AgentToolInterruptedReason =
	| "no-progress"
	| "window-exceeded"
	| "not-tailable"
	| "inspect-timeout"
	| "inspect-failed"
	| "recovery-deadline"
	| "budget-exceeded";

retryable это true только для interrupted run: дочерний агент был сброшен или заменён из-за деплоя или recovery родителя и так и не достиг логического завершения, поэтому повторная отправка того же вызова может завершиться успешно. Настоящий error или намеренный aborted это retryable: false. Это позволяет родительскому промпту по соглашению или оркестрирующему каркасу повторно запустить операцию после временного прерывания, а не сообщать пользователю об окончательном сбое. AgentToolFailure экспортируется из agents.

На interrupted run, reason предоставляет машиночитаемую причину и childStillRunning сообщает, работал ли ещё дочерний агент, когда родительский агент прекратил ожидание (true) либо была с тех пор уничтожена (false). Ветвитесь по ним, а не разбирайте error текст: например, повторно отправить no-progress прерывание (дочерний агент всё ещё может самовосстановиться), а переподключение к нему или отображение window-exceeded один (дочерний объект был уничтожен). Оба reason и childStillRunning также дублируются в agent-tool-event кадр передачи и useAgentToolEvents() состояние run.

Для дочерних Think-узлов, которые выполняют работу в стиле workflow без видимого пользователю текста ассистента, переопределите getAgentToolOutput() и, при необходимости, getAgentToolSummary(). Текст ассистента остаётся сводкой по умолчанию, если он присутствует, но выполнение Think agent-tool может успешно завершиться без отправки текстовых фрагментов.

Сохраняйте любой структурированный вывод до завершения дочернего хода, потому что getAgentToolOutput() считывается, как только saveMessages() разрешится. Держите getAgentToolSummary() компактным для отображения; полное структурированное значение хранится отдельно как результат работы инструмента.

export class Extractor extends Think {
	getAgentToolOutput(runId) {
		const rows = this.sql`
			SELECT result_json FROM extraction_runs WHERE id = ${runId}
		`;
		return rows[0] ? JSON.parse(rows[0].result_json) : undefined;
	}

	getAgentToolSummary(_runId, output) {
		return output ? "Extraction complete" : "";
	}
}
export class Extractor extends Think<Env> {
	protected override getAgentToolOutput(runId: string) {
		const rows = this.sql<{ result_json: string }>`
			SELECT result_json FROM extraction_runs WHERE id = ${runId}
		`;
		return rows[0] ? JSON.parse(rows[0].result_json) : undefined;
	}

	protected override getAgentToolSummary(_runId: string, output: unknown) {
		return output ? "Extraction complete" : "";
	}
}

Императивный запуск инструмента агента

Используйте runAgentTool() для детерминированных workflow, запланированной работы, HTTP-обработчиков или fan-out кода.

const [a, b] = await Promise.allSettled([
	this.runAgentTool(Researcher, {
		input: { query: "HTTP/3" },
		parentToolCallId: toolCallId,
		displayOrder: 0,
	}),
	this.runAgentTool(Researcher, {
		input: { query: "gRPC" },
		parentToolCallId: toolCallId,
		displayOrder: 1,
	}),
]);
const [a, b] = await Promise.allSettled([
	this.runAgentTool(Researcher, {
		input: { query: "HTTP/3" },
		parentToolCallId: toolCallId,
		displayOrder: 0,
	}),
	this.runAgentTool(Researcher, {
		input: { query: "gRPC" },
		parentToolCallId: toolCallId,
		displayOrder: 1,
	}),
]);

runAgentTool() идемпотентен по runId. Передача того же runId никогда не запускает дублирующий дочерний ход. Завершённые, неудачные, прерванные и остановленные запуски сохраняются, пока вы явно их не очистите.

Отсоединённые запуски (в фоновом режиме)

По умолчанию runAgentTool() ожидает дочерний элемент до терминального состояния перед возвратом. Для длительной работы (крупный импорт, рендеринг видео, глубокие исследования), которую вы не хотите блокировать в ходе, инициировавшем вызов, передайте detached. Запуск отправляется на выполнение, текущий ход продолжается, и runAgentTool() немедленно возвращает handle:

type DetachedRunAgentToolResult = {
	runId: string;
	agentType: string;
	status: "running" | "error"; // "error" only if dispatch itself was rejected
};

detached: true работает по принципу fire-and-forget: наблюдайте за ходом выполнения через agent-tool-event фреймы (те же, которые useAgentToolEvents() потребляет) и глобальный onAgentToolFinish() хук. Передайте объект, чтобы связать целевой устойчивый callback завершения:

export class Importer extends Think {
	async startImport(input) {
		const { runId } = await this.runAgentTool(ImportAgent, {
			input,
			detached: { onFinish: "onImportDone", maxBudgetMs: 60 * 60 * 1000 },
		});
		return runId;
	}

	// Fires once, even if the Durable Object was evicted and rehydrated while the
	// child ran. Referenced by METHOD NAME (like schedule()) — never a closure,
	// which cannot survive eviction.
	async onImportDone(run, result) {
		switch (result.status) {
			case "completed":
				await this.markImportReady(run.runId, result.summary);
				break;
			case "error":
				await this.markImportFailed(run.runId, result.error);
				break;
			case "interrupted":
				// reason "budget-exceeded" ⇒ the run hit its maxBudgetMs ceiling.
				// interrupted is soft: a child that finishes anyway re-fires this
				// hook with "completed", so make the handler idempotent.
				break;
		}
	}
}
export class Importer extends Think<Env> {
	async startImport(input: ImportInput) {
		const { runId } = await this.runAgentTool(ImportAgent, {
			input,
			detached: { onFinish: "onImportDone", maxBudgetMs: 60 * 60 * 1000 },
		});
		return runId;
	}

	// Fires once, even if the Durable Object was evicted and rehydrated while the
	// child ran. Referenced by METHOD NAME (like schedule()) — never a closure,
	// which cannot survive eviction.
	async onImportDone(run: AgentToolRunInfo, result: AgentToolLifecycleResult) {
		switch (result.status) {
			case "completed":
				await this.markImportReady(run.runId, result.summary);
				break;
			case "error":
				await this.markImportFailed(run.runId, result.error);
				break;
			case "interrupted":
				// reason "budget-exceeded" ⇒ the run hit its maxBudgetMs ceiling.
				// interrupted is soft: a child that finishes anyway re-fires this
				// hook with "completed", so make the handler idempotent.
				break;
		}
	}
}

Основные особенности поведения:

await this.cancelAgentTool(runId); // idempotent; delivers onFinish "aborted"
await this.cancelAgentTool(runId); // idempotent; delivers onFinish "aborted"

Уведомить чат по завершении (Think / AIChatAgent)

На чат-агенте (@cloudflare/think или AIChatAgent) обычно нужно, чтобы модель react к завершённому фоновому запуску. Вместо того чтобы подключать onFinish вручную, передайте notify: true : когда запуск завершается, агент добавляет сообщение в чат (идемпотентно по комбинации запуска и статуса, поэтому завершение exactly-once никогда не дублируется), и модель делает следующий ход с результатом в контексте:

await this.runAgentTool(ResearchAgent, { input, detached: { notify: true } });
await this.runAgentTool(ResearchAgent, { input, detached: { notify: true } });

Если ваше приложение направляет или скрывает синтетические сообщения по metadata.source, передайте собственный источник:

await this.runAgentTool(ResearchAgent, {
	input,
	detached: { notify: { source: "research-background" } },
});
await this.runAgentTool(ResearchAgent, {
	input,
	detached: { notify: { source: "research-background" } },
});

Переопределить formatDetachedCompletion(run, result) чтобы настроить вставляемый текст, или верните пустую строку, чтобы подавить уведомление для данного исхода. Явный onFinish имеет приоритет над notify.

inspectAgentToolRun контракт

Дочернего процесса inspectAgentToolRun(runId) возвращает текущий снимок статуса run, или null. null не означает «failed» : это означает, что у дочернего агента нет записи об этом запуске ещё. Это нормально сразу после диспетчеризации (дочерний объект может ещё сохранять свою первую строку), а также это то, что возвращает только что восстановленный дочерний объект до того, как он лениво согласует устаревший running row. Вызывающий код, как и собственный reconcile backbone фреймворка, считает null как «не завершено, продолжайте отслеживание в пределах бюджета», а не как окончательный сбой. Только отличное отnull для проверки через терминал status (completed / error / aborted) завершает запуск.

Сообщайте о прогрессе и вехах

Дочерний агент, выполняющийся как инструмент агента (ожидаемый или отсоединённый), может сообщать о ходе выполнения в процессе работы, чтобы родитель мог отображать строку статуса в реальном времени, измерять выполнение на стороне сервера или реагировать на именованную контрольную точку до завершения запуска. Вызовите reportProgress() изнутри дочернего агента (например, из execute):

export class ImportAgent extends Think {
	getTools() {
		return {
			ingest: tool({
				inputSchema: z.object({ url: z.string() }),
				execute: async ({ url }) => {
					// Ephemeral progress: drives a generic bar / phase / status line.
					await this.reportProgress({
						fraction: 0.6,
						phase: "ingesting",
						message: "Ingested 40k/80k rows",
					});
					// ...
				},
			}),
		};
	}
}
export class ImportAgent extends Think<Env> {
	getTools() {
		return {
			ingest: tool({
				inputSchema: z.object({ url: z.string() }),
				execute: async ({ url }) => {
					// Ephemeral progress: drives a generic bar / phase / status line.
					await this.reportProgress({
						fraction: 0.6,
						phase: "ingesting",
						message: "Ingested 40k/80k rows",
					});
					// ...
				},
			}),
		};
	}
}

reportProgress() доступен для чат-агентов (@cloudflare/think и AIChatAgent). Это no-op операция с предупреждением для разработки на базовом Agent класс, в том числе когда он вызывается вне активного запуска агентного инструмента, поэтому тот же дочерний код можно безопасно запускать отдельно. Фреймворк определяет активный запуск по текущему ходу, поэтому вам никогда не нужно вручную передавать ID запуска.

reportProgress<T>(
	progress: {
		fraction?: number; // 0..1 — drives a progress bar
		message?: string; // human-readable status line
		phase?: string; // coarse phase label, e.g. "ingesting"
		milestone?: string; // present ⇒ a durable milestone (see below)
		data?: T; // app-specific payload; live-only unless persisted
	},
	options?: { persist?: boolean },
): Promise<void>;

Эфемерные сигналы передаются по собственному потоку хода дочернего агента как временный data-agent-progress часть, поэтому они повторно рассылаются подключённым клиентам родителя и отображаются в AgentToolRunState.progress через useAgentToolEvents() : панель фоновых запусков может отображать индикатор выполнения, фазу и строку состояния без перехода к деталям. Всплески объединяются (побеждает последнее значение; fraction >= 1 фрейм всегда отправляется). data поле доступно только в режиме реального времени, если вы не передадите { persist: true }.

Наблюдать за прогрессом родительского агента

Переопределить onProgress() чтобы измерять, направлять или показывать прогресс на стороне сервера. Он срабатывает по мере возможности всякий раз, когда сигнал прогресса дочернего процесса передаётся через родительский, как для ожидаемых, так и для отсоединённых запусков:

export class Assistant extends Think {
	async onProgress(run, progress) {
		if (progress.milestone) {
			// A durable milestone landed — branch on it.
		}
		console.log(run.runId, progress.phase, progress.fraction);
	}
}
export class Assistant extends Think<Env> {
	override async onProgress(
		run: AgentToolRunInfo,
		progress: AgentToolProgressSnapshot,
	) {
		if (progress.milestone) {
			// A durable milestone landed — branch on it.
		}
		console.log(run.runId, progress.phase, progress.fraction);
	}
}

onProgress() не является устойчивым: после вытеснения последний снимок отсоединённого запуска восстанавливается из inspectAgentToolRun().progress при сверке состояния, а не повторно вызывая хук. Последний снимок также сохраняется в строке дочернего запуска, поэтому восстановленный родительский процесс может ответить на вопрос «где сейчас этот запуск», не отслеживая живой поток.

Устойчивые вехи

Именование milestone повышает сигнал с временного уровня до устойчивый один. По-прежнему существует только один метод emit:

await this.reportProgress({
	milestone: "sources-gathered",
	data: { sources: 2 },
});
await this.reportProgress({
	milestone: "sources-gathered",
	data: { sources: 2 },
});

Веха сохраняется как одна строка у дочернего процесса с монотонным для каждого запуска sequence, и передаётся вместе с потоком как сохранено data-agent-milestone часть (в отличие от временного прогресса). Поэтому она переживает вытеснение, воспроизводится при детальном просмотре и отображается, дедуплицированная по sequence : на AgentToolRunState.milestones и inspectAgentToolRun().milestones. onProgress() срабатывает и для вех, с progress.milestone устанавливается, чтобы потребитель мог разграничивать веху и эфемерный прогресс.

Уведомить чат о достижении вехи (Think / AIChatAgent)

Для отсоединённого запуска на чат-агенте detached: { onMilestones } показывает сообщение в чате, когда срабатывает заданная веха, до запуск завершится. Каждый (runId, name) срабатывает не более одного раза: независимо от того, зафиксировано ли это вживую или восстановлено после вытеснения, поэтому детерминированный ID сводит тёплую и холодную доставку к модели не более одного раза:

// "narrate" (default): inject a synthetic assistant status line — no model turn.
await this.runAgentTool(Researcher, {
	input,
	detached: { onMilestones: ["sources-gathered"] },
});

// "react": post a user-role turn so the model responds (steer, start dependent
// work). Costs a model turn.
await this.runAgentTool(Researcher, {
	input,
	detached: { onMilestones: { names: ["needs-approval"], mode: "react" } },
});
// "narrate" (default): inject a synthetic assistant status line — no model turn.
await this.runAgentTool(Researcher, {
	input,
	detached: { onMilestones: ["sources-gathered"] },
});

// "react": post a user-role turn so the model responds (steer, start dependent
// work). Costs a model turn.
await this.runAgentTool(Researcher, {
	input,
	detached: { onMilestones: { names: ["needs-approval"], mode: "react" } },
});

Переопределить formatDetachedMilestone(run, milestone) чтобы изменить формулировку или вернуть пустую строку, чтобы скрыть определённую веху. Синтетические narrate-сообщения содержат metadata.source, чтобы клиенты могли отображать их как событие агента, а не как ход человека.

Сброс бюджета отсутствия прогресса для отсоединённых запусков

После того как отсоединённый дочерний процесс сообщил хотя бы один сигнал, механизм сверки прекращает попытки, если выполнение затем молчит в течение detachedNoProgressBudgetMs (по умолчанию 1 час; переопределяется для каждого запуска через detached: { noProgressBudgetMs }). Это проявляется как status: "interrupted", reason: "no-progress". Дочерний агент, который никогда не отчитывается, ограничен только абсолютным detachedMaxBudgetMs потолок: запуск никогда не прекращается только из-за того, что он медленный. Задайте noProgressBudgetMs к 0 или Infinity чтобы отключить окно сброса для запуска.

Отрисовывайте временные шкалы дочерних агентов в React

useAgentToolEvents() это headless-хук. Он подписывается на существующее родительское соединение, устраняет состояния гонки между воспроизведением и живыми данными и применяет дочерние UIMessageChunk тела в части сообщения и группирует параллельные запуски по ID родительского вызова инструмента. Состояние каждого запуска содержит progress и milestones, чтобы панель фоновых запусков могла отображать живой индикатор выполнения, фазу и метки этапов без необходимости открывать подробности.

import { useAgent, useAgentToolEvents } from "agents/react";
import { useAgentChat } from "@cloudflare/ai-chat/react";

const agent = useAgent({ agent: "Assistant", name: userId });
const { messages } = useAgentChat({ agent });
const agentTools = useAgentToolEvents({ agent });

for (const message of messages) {
	for (const part of message.parts) {
		if (part.type === "tool-call") {
			const runs = agentTools.getRunsForToolCall(part.toolCallId);
			// Render the child runs beside this tool call.
		}
	}
}
import { useAgent, useAgentToolEvents } from "agents/react";
import { useAgentChat } from "@cloudflare/ai-chat/react";

const agent = useAgent({ agent: "Assistant", name: userId });
const { messages } = useAgentChat({ agent });
const agentTools = useAgentToolEvents({ agent });

for (const message of messages) {
	for (const part of message.parts) {
		if (part.type === "tool-call") {
			const runs = agentTools.getRunsForToolCall(part.toolCallId);
			// Render the child runs beside this tool call.
		}
	}
}

Императивные запуски без родительского вызова инструмента доступны как agentTools.unboundRuns.

Изучите детали и ограничьте доступ

Agents как инструменты представляют собой обычные дочерние агенты. Подключайтесь к сохранённому дочернему агенту через route родителя:

useAgent({
	agent: "Assistant",
	name: userId,
	sub: [{ agent: "Researcher", name: runId }],
});
useAgent({
	agent: "Assistant",
	name: userId,
	sub: [{ agent: "Researcher", name: runId }],
});

Ограничивайте внешний доступ с помощью родительского реестра, чтобы угаданные идентификаторы запуска не могли порождать новые дочерние грани:

override async onBeforeSubAgent(_request, child) {
	if (!this.hasAgentToolRun(child.className, child.name)) {
		return new Response("Not found", { status: 404 });
	}
}

Очистить сохранённые запуски

Запуски и дочерние грани по умолчанию сохраняются для обновления, детального просмотра и последующей проверки. Удаляйте их явно при очистке истории чата или при применении собственной политики хранения данных:

await this.clearAgentToolRuns();
await this.clearAgentToolRuns({
	status: ["completed", "error", "aborted", "interrupted"],
});
await this.clearAgentToolRuns({ olderThan: Date.now() - 7 * 24 * 60 * 60_000 });
await this.clearAgentToolRuns();
await this.clearAgentToolRuns({
	status: ["completed", "error", "aborted", "interrupted"],
});
await this.clearAgentToolRuns({ olderThan: Date.now() - 7 * 24 * 60 * 60_000 });

Если сохранённый запуск всё ещё starting или running, очистка отменяет дочерний агент, прежде чем удалить его грань.

Прерванные запуски и восстановление

Запуски агентных инструментов сохраняются у родителя. Если родитель перезапускается (при развёртывании или вытеснении), пока дочерний запуск ещё starting или running, он не бросает дочерний агент. Восстановление при запуске заново подключается к работающему дочернему агенту и досматривает его поток вплоть до финального результата дочернего агента. Поскольку дочерний агент представляет собой sub-agent со своим собственным chatRecovery, он самостоятельно восстанавливает свой прерванный ход, пока родительский агент передаёт его вывод дальше. Завершённый дочерний агент финализируется без повторного выполнения уже готовой работы.

Ожидание повторного подключения составляет с ключом по прогрессу, а не фиксированные часы реального времени. Два статических options настроить это:

Опция По умолчанию Поведение
agentToolReattachNoProgressTimeoutMs 120000 (2 мин) Сколько времени родитель ожидает с нет продвижения вперёд, прежде чем сдаться. Сбрасывается при каждом переданном чанке, поэтому потоковый дочерний элемент отслеживается вплоть до конечного статуса.
agentToolReattachMaxWindowMs Infinity Необязательный жёсткий потолок по астрономическому времени на одну попытку повторного подключения. По умолчанию не ограничен (аналогично параметру восстановления чата maxRecoveryWork), поэтому исправный, долго работающий дочерний процесс никогда не обрывается. Чтобы задать верхний предел, укажите конечное значение.

Исходы give-up соответствуют AgentToolFailure поля:

Зависший дочерний процесс не может блокировать восстановление бесконечно. Бюджет отсутствия прогресса ограничивает время молчания дочернего процесса. Неконтролируемый рост содержимого ограничивается собственным chatRecovery (maxRecoveryWork и shouldKeepRecovering), а не таймером, доступным только родительскому объекту.

Отслеживание согласования с родителем через agentTool канал наблюдаемости:

import { subscribe } from "agents/observability";

const unsubscribe = subscribe("agentTool", (event) => {
	if (event.type === "agent_tool:recovery:row") {
		console.log("Recovered agent-tool row", event.payload);
	}
});
import { subscribe } from "agents/observability";

const unsubscribe = subscribe("agentTool", (event) => {
	if (event.type === "agent_tool:recovery:row") {
		console.log("Recovered agent-tool row", event.payload);
	}
});

Низкоуровневый diagnostics_channel подписчикам следует использовать имя канала agents:agent_tool.

Пример

Пример: Agents как инструменты

Запускайте дочерние агенты, способные вести чат, как сохранённые инструменты, транслируйте их временные шкалы прямо в интерфейсе и переходите к деталям дочерних агентов.

Дочерние агенты

Порождайте дочерних агентов с изолированным хранилищем, типизированным RPC и вложенной маршрутизацией клиентов.

Чат-агенты

Создавайте чат-интерфейсы ИИ с помощью AIChatAgent и useAgentChat.