← Vytvářejte agenty na Cloudflare / agents / harnesses / think
RPC podřízeného agenta a programová kola
Think funguje jak jako agent nejvyšší úrovně, tak jako podřízený agent. Při použití jako podřízený agent chat() metoda spustí celý tah a streamuje události přes callback.
Pro trvalé přijetí s idempotentním opakováním a pozdější kontrolou stavu viz Programové odesílání. Pro obnovení po vyřazení z paměti si přečtěte Trvalé obnovení.
chat
async chat(
userMessage: string | UIMessage,
callback: StreamCallback,
options?: ChatOptions,
): Promise<void>StreamCallback
| Metoda | Když se spustí |
|---|---|
onStart(event) |
Před zahájením práce; zpřístupňuje ID požadavku pro zrušení |
onEvent(json) |
Pro každý streamovaný chunk (serializovaný do JSON UIMessageChunk) |
onDone() |
Po dokončení kola a uložení zprávy asistenta |
onError(message) |
Při chybě během daného kola |
onInterrupted() |
Volitelné. Pokus byl přerušen a naplánované pokračování (v pozdějším isolate) má na starosti konečný výsledek: není dokončeno, není to konečná chyba. Výchozí chování je no-op |
onInterrupted je důležité pro chat()-řízené kolo, které je přerušeno a poté se obnoví: RPC promise se vyřeší čistě (izolát je stále aktivní), takže odběratel řídící se pouze čistým vyřešením by to mylně vyhodnotil jako úspěch a finalizoval by jakoukoli částečnou odpověď, kterou už streamoval. Berte to jako stav „nedokončeno, ale ani neúspěšné: odpověď má na starosti navazující pokračování“: ponechte kanál otevřený, zobrazte stav obnovování nebo se znovu připojte, místo abyste finalizovali částečnou odpověď. Přerušení kvůli nasazení nebo evikci izolát ukončí dříve, než k tomu stihne dojít (volající místo toho uvidí přerušení přenosu); onInterrupted popisuje cestu od zaseknutí v izolátu k obnovení.
ChatOptions
| Pole | Popis |
|---|---|
signal |
AbortSignal pro zrušení tahu uprostřed streamu |
Nástroje patří podřízenému agentovi. Trvalé schopnosti definujte pomocí podřízeného agenta getTools(), rozšíření, nástroje MCP nebo schémata klientských nástrojů. Starší volající, kteří předávají options.tools na chat() obdrží varování a hodnota se ignoruje.
Příklad: rodič volá potomka
import { Think } from "@cloudflare/think";
export class ParentAgent extends Think {
getModel() {
/* ... */
}
async delegateToChild(task) {
const child = await this.subAgent(ChildAgent, "child-1");
const chunks = [];
await child.chat(task, {
onStart: (event) => {
console.log("Child started:", event.requestId);
},
onEvent: (json) => {
chunks.push(json);
},
onDone: () => {
console.log("Child completed");
},
onError: (error) => {
console.error("Child failed:", error);
},
});
return chunks;
}
}
export class ChildAgent extends Think {
getModel() {
/* ... */
}
getSystemPrompt() {
return "You are a research assistant. Analyze data and report findings.";
}
}import { Think } from "@cloudflare/think";
import type { StreamCallback } from "@cloudflare/think";
export class ParentAgent extends Think<Env> {
getModel() {
/* ... */
}
async delegateToChild(task: string) {
const child = await this.subAgent(ChildAgent, "child-1");
const chunks: string[] = [];
await child.chat(task, {
onStart: (event) => {
console.log("Child started:", event.requestId);
},
onEvent: (json) => {
chunks.push(json);
},
onDone: () => {
console.log("Child completed");
},
onError: (error) => {
console.error("Child failed:", error);
},
});
return chunks;
}
}
export class ChildAgent extends Think<Env> {
getModel() {
/* ... */
}
getSystemPrompt() {
return "You are a research assistant. Analyze data and report findings.";
}
}Rušení kola podřízeného agenta
Použijte onStart a cancelChat() pro bezpečné zrušení RPC napříč hranicí subagenta:
let requestId;
const callback = {
onStart(event) {
requestId = event.requestId;
},
onEvent(json) {
// Forward stream chunks.
},
onDone() {},
onError(error) {
console.error(error);
},
};
const turn = child.chat("Long analysis task", callback);
// Later, from another RPC call or failure handler:
if (requestId) {
await child.cancelChat(requestId, "client disconnected");
}
await turn;let requestId: string | undefined;
const callback: StreamCallback = {
onStart(event) {
requestId = event.requestId;
},
onEvent(json) {
// Forward stream chunks.
},
onDone() {},
onError(error) {
console.error(error);
},
};
const turn = child.chat("Long analysis task", callback);
// Later, from another RPC call or failure handler:
if (requestId) {
await child.cancelChat(requestId, "client disconnected");
}
await turn;Pokud volající a volaný nejsou odděleni pomocí Workers RPC, můžete také předat AbortSignal pro zrušení uprostřed streamu:
const controller = new AbortController();
setTimeout(() => controller.abort(), 30_000);
await child.chat("Long analysis task", callback, {
signal: controller.signal,
});const controller = new AbortController();
setTimeout(() => controller.abort(), 30_000);
await child.chat("Long analysis task", callback, {
signal: controller.signal,
});cancelChat(requestId, reason?) nic neudělá, pokud je kolo již dokončené nebo ID požadavku není známé. Při přerušení zůstává částečná zpráva asistenta uložena.
saveMessages
Vkládejte zprávy a spouštějte tah modelu bez připojení WebSocket. Použijte pro naplánované odpovědi, tahy spouštěné webhookem, proaktivní agenty nebo řetězení od onChatResponse.
async saveMessages(
messages:
| UIMessage[]
| ((current: UIMessage[]) => UIMessage[] | Promise<UIMessage[]>),
options?: SaveMessagesOptions,
): Promise<SaveMessagesResult>Vrátí { requestId, status, error? } kde status je "completed", "error", "skipped", nebo "aborted".
status |
Kdy |
|---|---|
"completed" |
Kolo doběhlo do konce. |
"error" |
Kolo bylo zahájeno, ale stream nahlásil chybu. error obsahuje chybovou zprávu streamu, je-li k dispozici. |
"skipped" |
Kolo znehodnoceno za běhu, například pomocí chat-clear; zpráva uživatele uložena, model se nespustil. |
"aborted" |
Kolo zrušeno před dokončením přes options.signal nebo chat-request-cancel. Částečné fragmenty odpovědi asistenta se přesto uložily. |
Předejte options.signal pro zrušení programového tahu z Durable Object, který jej spouští. AbortSignal nemůže překročit hranice RPC Durable Object a signál se při hibernaci neukládá.
Statické zprávy
await this.saveMessages([
{
id: crypto.randomUUID(),
role: "user",
parts: [{ type: "text", text: "Time for your daily summary." }],
},
]);await this.saveMessages([
{
id: crypto.randomUUID(),
role: "user",
parts: [{ type: "text", text: "Time for your daily summary." }],
},
]);Podoba funkce
Pokud je více saveMessages volání se řadí do fronty, funkční forma se pak spustí s nejnovějšími zprávami až ve chvíli, kdy kolo skutečně začne:
await this.saveMessages((current) => [
...current,
{
id: crypto.randomUUID(),
role: "user",
parts: [{ type: "text", text: "Continue your analysis." }],
},
]);await this.saveMessages((current) => [
...current,
{
id: crypto.randomUUID(),
role: "user",
parts: [{ type: "text", text: "Continue your analysis." }],
},
]);Naplánované odpovědi
Spusťte opakující se kolo promptu pomocí getScheduledTasks():
export class MyAgent extends Think {
getModel() {
/* ... */
}
getScheduledTasks() {
return {
dailyReport: {
schedule: "every day at 09:00",
timezone: "UTC",
prompt: "Generate the daily report.",
},
};
}
}export class MyAgent extends Think<Env> {
getModel() {
/* ... */
}
getScheduledTasks() {
return {
dailyReport: {
schedule: "every day at 09:00",
timezone: "UTC",
prompt: "Generate the daily report.",
},
};
}
}Zřetězení z onChatResponse
Spusťte navazující kolo po dokončení toho aktuálního:
async onChatResponse(result: ChatResponseResult) {
if (result.status === "completed" && this.needsFollowUp(result.message)) {
await this.saveMessages([{
id: crypto.randomUUID(),
role: "user",
parts: [{ type: "text", text: "Now summarize what you found." }],
}]);
}
}continueLastTurn
Spusťte další volání modelu po poslední zprávě asistenta, aniž byste vkládali novou zprávu uživatele. Think uloží výsledek jako novou zprávu asistenta s continuation: true; nepřipojuje části k existující zprávě asistenta.
protected async continueLastTurn(
body?: Record<string, unknown>,
options?: SaveMessagesOptions,
): Promise<SaveMessagesResult>Vrátí { requestId, status: "skipped" } pokud poslední zpráva není zprávou asistenta. Volitelný body parametr přepisuje uložené tělo pro toto pokračování. Předejte options.signal pro zrušení pokračování během jeho běhu.
abortRequest a abortAllRequests
Zrušte probíhající kola chatu zevnitř Durable Object:
protected abortRequest(requestId: string, reason?: unknown): void
protected abortAllRequests(): voidPoužijte abortRequest() když znáte ID požadavku. Použijte abortAllRequests() pro jednoúčelové pomocné funkce, které mají zrušit právě probíhající kolo, ať je jakékoli. Upřednostněte SaveMessagesOptions.signal pro programová kola, pokud můžete signál předat přímo v místě volání.