INTEGRITY Dokumentace

Hooky životního cyklu

Think vlastní streamText volání a poskytuje hooky v každé fázi kroku konverzace. Hooky se spouštějí při každém kroku bez ohledu na vstupní cestu: WebSocket chat, dílčí agent chat(), saveMessages(), trvalé submitMessages() provedení, continueLastTurn(), a automatické pokračování po výsledcích nástrojů.

Souhrn hooku

Hook Když se spustí Návrat Asynchronní
configureSession(session) Jednou během onStart Session ano
beforeTurn(ctx) Před streamText TurnConfig nebo void ano
beforeStep(ctx) Před každým krokem modelu StepConfig nebo void ano
beforeToolCall(ctx) Před spuštěním serverového nástroje ToolCallDecision nebo void ano
afterToolCall(ctx) Jakmile je znám výsledek nástroje void ano
onStepFinish(ctx) Po dokončení každého kroku void ano
onChunk(ctx) Na jeden chunk streamu void ano
onChatResponse(result) Po dokončení kola a uložení zprávy void ano
onChatError(error, ctx?) Při chybě během kola chyba k propagaci ne
classifyChatError(error, ctx?) Při chybě kola, když contextOverflow.reactive je zapnuto ChatErrorClassification nebo void ne

Pořadí vykonávání

Pro kolo se dvěma voláními nástrojů:

flowchart TD
    cfg["configureSession() — once at startup, not per-turn"] --> bt["beforeTurn() — inspect context, override model/tools/prompt"]
    bt --> bs

    subgraph loop ["streamText (repeats per step)"]
        bs["beforeStep()"] --> chunk["onChunk() — per streaming chunk"]
        chunk --> btc["beforeToolCall()"]
        btc --> exec["tool executes"]
        exec --> atc["afterToolCall()"]
        atc --> sf["onStepFinish()"]
        sf -->|"more steps"| bs
    end

    sf -->|"turn complete"| ocr["onChatResponse() — message persisted, turn lock released"]

beforeTurn

Volá se před streamText. Přijímá kompletně sestavený kontext: systémový prompt, převedené zprávy, sloučené nástroje a model. Vraťte TurnConfig k přepsání libovolné části, nebo void pro přijetí výchozích hodnot.

beforeTurn(ctx: TurnContext): TurnConfig | void | Promise<TurnConfig | void>

TurnContext

Pole Typ Popis
system string Sestavený systémový prompt (z kontextových bloků nebo getSystemPrompt())
messages ModelMessage[] Sestavené zprávy modelu (zkrácené, ořezané)
tools ToolSet Sloučená sada nástrojů (workspace + getTools + session + extensions + MCP + client)
model LanguageModel Model z getModel()
continuation boolean Zda jde o navazující kolo (automatické pokračování po výsledku nástroje)
body Record<string, unknown> Vlastní pole těla z klientského požadavku

TurnConfig

Všechna pole jsou volitelná. Vraťte pouze to, co chcete změnit.

Pole Typ Popis
model LanguageModel Přepište model pro tento turn
system string Přepište systémový prompt
messages ModelMessage[] Přepište sestavené zprávy
tools ToolSet Další nástroje ke sloučení (přídavné)
activeTools string[] Omezte, které nástroje může model volat
toolChoice ToolChoice Vynucení konkrétního volání nástroje
maxSteps number Přepsat maxSteps pro toto kolo
sendReasoning boolean Odeslat části uvažování pro toto kolo
chatStreamStallTimeoutMs number Přepište watchdog zaseknutí streamu pro tento turn (0 ji vypne); po kole se automaticky obnoví. Užitečné pro kolo se známě pomalým nástrojem, viz Trvalé obnovení
output Output Vyžádat strukturovaný výstup pro toto kolo
providerOptions Record<string, unknown> Možnosti specifické pro poskytovatele
experimental_telemetry object nastavení telemetrie AI SDK pro toto kolo
experimental_transform StreamTextTransform | StreamTextTransform[] transformace streamu AI SDK pro toto kolo: kontrola nebo přepis částí streamu (například vyslání source části odvozené z výsledků nástrojů). Uplatní se v daném pořadí.

Příklady

Přepněte na levnější model pro navazující kola:

beforeTurn(ctx: TurnContext) {
	if (ctx.continuation) {
		return { model: this.cheapModel };
	}
}

Omezte, které nástroje může model volat:

beforeTurn(ctx: TurnContext) {
	return { activeTools: ["read", "write", "getWeather"] };
}

Přidejte kontext pro každé kolo z těla klientského požadavku:

beforeTurn(ctx: TurnContext) {
	if (ctx.body?.selectedFile) {
		return {
			system: ctx.system + `\n\nUser is editing: ${ctx.body.selectedFile}`,
		};
	}
}

Skrytí uvažování u interních pokračovacích kol:

beforeTurn(ctx: TurnContext) {
	if (ctx.continuation) {
		return { sendReasoning: false };
	}
}

Vynuťte strukturovaný výstup pro dané kolo:

import { Output } from "ai";
import { z } from "zod";

const ResultSchema = z.object({ severity: z.enum(["low", "high"]) });

beforeTurn(ctx: TurnContext) {
	if (ctx.body?.mode === "structured-answer") {
		return {
			output: Output.object({ schema: ResultSchema }),
			activeTools: [],
		};
	}
}

output je nastavení pouze na úrovni kola. V AI SDK prepareStep nepřijímá output override, takže beforeStep nemůže přepínat strukturovaný výstup v rámci jednoho kroku.

beforeStep

Volá se před každým krokem AI SDK v agentní smyčce. Think tento hook předává do streamText jako prepareStep, takže dostává celý kontext prepare-step z AI SDK a může vracet přepisy pro jednotlivé kroky. Použijte beforeTurn pro sestavení napříč celým kolem a beforeStep když rozhodnutí závisí na čísle kroku nebo výsledcích předchozích kroků.

beforeStep(ctx: PrepareStepContext): StepConfig | void {
	if (ctx.stepNumber > 0) {
		return { activeTools: [] };
	}
}

beforeToolCall

Volá se před spuštěním funkce serverového nástroje execute funkce spustí. Think obalí každý nástroj na straně serveru tak, aby hook mohl volání povolit, upravit, zablokovat nebo nahradit ještě předtím, než model obdrží výsledek nástroje.

beforeToolCall(ctx: ToolCallContext): ToolCallDecision | void {
	if (ctx.toolName === "delete" && this.isReadOnlyMode) {
		return { action: "block", reason: "delete is disabled in read-only mode" };
	}

	if (ctx.toolName === "weather") {
		const cached = this.weatherCache.get(JSON.stringify(ctx.input));
		if (cached) return { action: "substitute", output: cached };
	}
}
Pole Typ Popis
toolName string Název volaného nástroje
input unknown Vstup poskytnutý modelem
toolCallId string ID pro toto volání nástroje
messages ModelMessage[] Zprávy viditelné v době provádění nástroje
abortSignal AbortSignal | undefined Signál, který se aktivuje při zrušení kola

Vrátí ToolCallDecision pro řízení běhu:

Rozhodnutí Chování
void nebo { action: "allow" } Spuštění původního nástroje s původním vstupem
{ action: "allow", input } Spuštění původního nástroje s upraveným vstupem
{ action: "block", reason } Přeskočte původní nástroj a vraťte reason jako výsledek nástroje
{ action: "substitute", output } Přeskočte původní nástroj a vraťte output jako výsledek nástroje

Pokud obalený nástroj vrátí AsyncIterable pro předběžné výsledky nástrojů. Think sbalí iterovatelný objekt na jeho poslední vrácenou hodnotu po beforeToolCall se spustí. Pokud od tohoto nástroje potřebujete opravdové předběžné streamování, nezachytávejte ho pomocí beforeToolCall.

afterToolCall

Volá se poté, co je znám výsledek nástroje. Zahrnuje to skutečná spuštění, blokovaná volání, nahrazená volání a vyvolané chyby nástroje.

afterToolCall(ctx: ToolCallResultContext) {
	if (!ctx.success) return;

	this.env.ANALYTICS.writeDataPoint({
		blobs: [ctx.toolName],
		doubles: [JSON.stringify(ctx.output).length],
	});
}
Pole Typ Popis
toolName string Název nástroje, který byl zavolán
input unknown Vstup poskytnutý modelem
toolCallId string ID pro toto volání nástroje
messages ModelMessage[] Zprávy viditelné v době provádění nástroje
durationMs number Doba běhu nástroje v milisekundách
success boolean Zda model obdržel úspěšný výsledek nástroje
output unknown Přítomné, když success je true
error unknown Přítomné, když success je false

Pro blokovaná a nahrazená volání nástrojů success je true protože model obdrží platný výsledek nástroje. Pouze chyby vyvolané (thrown) při původním spuštění nástroje se projeví jako success: false.

onStepFinish

Volá se po dokončení každého kroku v agentní smyčce. StepContext je událost step-finish z AI SDK, takže obsahuje kompletní záznam kroku: vygenerovaný text, uvažování, soubory, zdroje, typovaná volání nástrojů a jejich výsledky, využití, upozornění, metadata požadavku a odpovědi a metadata poskytovatele.

onStepFinish(ctx: StepContext) {
	console.log(
		`Step ${ctx.stepNumber} (${ctx.finishReason}): ` +
			`${ctx.usage.inputTokens}in/${ctx.usage.outputTokens}out`,
	);
}
Pole Popis
stepNumber Index kroku počítaný od nuly
text Text vygenerovaný v tomto kroku
reasoning Části uvažování vydané modelem
files Soubory vygenerované během kroku
sources Citace nebo zdroje použité modelem
toolCalls Typovaná volání nástrojů provedená v tomto kroku
toolResults Typované výsledky nástrojů přijaté v tomto kroku
finishReason Proč krok skončil
usage Využití tokenů včetně tokenů z cache a tokenů pro reasoning
providerMetadata Metadata specifická pro poskytovatele

onChunk

Volá se pro každý streamovaný chunk: vysoká frekvence, spouští se pro každý token. Použijte pro analýzu streamování, ukazatele průběhu nebo počítání tokenů. Pouze pro pozorování.

onChatResponse

Volá se poté, co kolo chatu vytvoří a uloží zprávu asistenta. Zámek kola se uvolní ještě před spuštěním tohoto hooku, takže je bezpečné zavolat saveMessages nebo jiné metody zevnitř.

Spouští se u všech průběhů kola, které ukládají zprávu asistenta: WebSocket, RPC subagenta, saveMessages, a automatické pokračování. Pokud kolo selže dříve, než vytvoří jakoukoli část odpovědi asistenta, onChatError místo toho zpracuje chybu.

onChatResponse(result: ChatResponseResult) {
	if (result.status === "completed") {
		console.log(`Turn ${result.requestId}: ${result.message.parts.length} parts`);
	}
}
Pole Typ Popis
message UIMessage Persistovaná zpráva asistenta
requestId string Jedinečné ID tohoto kola
continuation boolean Zda šlo o navazující kolo
status "completed" | "error" | "aborted" Jak kolo skončilo
error string? Chybová zpráva (když status je "error")

onChatError

Volá se, když během kola chatu dojde k chybě. Chybu vraťte, pokud ji chcete propagovat dál, nebo vraťte jinou chybu. Volitelný kontext popisuje, kde k selhání došlo a zda už byly zprávy uživatele uloženy. Částečná zpráva asistenta (pokud existuje) se uloží ještě před spuštěním tohoto hooku.

onChatError(error: unknown, ctx?: ChatErrorContext): unknown

ChatErrorContext zahrnuje:

Pole Typ Popis
requestId string | undefined ID požadavku chatu, pokud je k dispozici
stage "parse" | "persist" | "turn" | "stream" | "recovery" | "transcript" Fáze selhání
messagesPersisted boolean Zda byly příchozí uživatelské zprávy již uloženy
classification ChatErrorClassification | undefined Nastavte na "context_overflow" na koncovém onChatError když se přetečení kontextu nepodařilo obnovit (viz classifyChatError); undefined jinak

Think také vyvolává chat:request:failed na agents:chat kanál pozorovatelnosti se stejnými informacemi o fázi a perzistenci.

onChatError(error: unknown, ctx?: ChatErrorContext) {
	console.error("Chat turn failed:", ctx?.stage, error);
	if (ctx?.classification === "context_overflow") {
		return new Error("This conversation is too long to continue. Please start a new one.");
	}
	return new Error("Something went wrong. Please try again.");
}

classifyChatError

Volá se, když během kola dojde k chybě, před onChatError. Přemapuje surovou chybu poskytovatele na kategorii nezávislou na poskytovateli, díky čemuž Think může reagovat, aniž by musel mít v frameworku napevno zadané řetězce specifické pro poskytovatele: stejné rozdělení jako u tokenCounter které předáváte do compactAfter(). Mapování spravuje aplikace, protože ví, se kterým poskytovatelem a modelem komunikuje.

classifyChatError(error: unknown, ctx?: ChatErrorContext): ChatErrorClassification | void

ChatErrorClassification je "context_overflow" | "rate_limit" | "transient" | "fatal" | "unknown". Dnes tento hook řídí pouze zotavení po přetečení kontextu. Think ho volá, když v kole dojde k chybě a contextOverflow.reactive je zapnuto. Pokud je reactive vypnuté, nevolá se.

Vracení "context_overflow" spouští záložní mechanismus zhuštění a opakování (viz Obnovení po přetečení kontextového okna). Pokud obnova kolo nezachrání, tato klasifikace se projeví na konečném onChatError volání přes ChatErrorContext.classification.

Ostatní kategorie jsou vyhrazeny pro budoucí použití. Vrácení některé z nich dnes nemá žádný účinek a nepředává se do onChatError. Vrácení void (výchozí) zachovává stávající chování při ukončení.

Argumentem může být Error, AI SDK APICallError (s statusCode/responseBody), nebo, v případě chyb poskytovatele uvnitř streamu, které se projeví jako chybová část streamu a ne jako vyvolaná výjimka, řetězec s chybovou zprávou. Podle toho zúžete typ. Chyby poskytovatele způsobené přetečením kontextu přicházejí jako chybové části uvnitř streamu, takže je tento hook dostává jako řetězec, ne jako vyvolanou výjimku.

Druhý argument je ChatErrorContext. Během obnovy po přetečení je { stage: "stream", requestId }, takže klasifikátor může chybu spojit s právě probíhajícím tahem, například zavolat cancelChat(requestId) a předčasně ukončí zotavování.

Příklad

V běžném případě přiřaďte sdružený defaultContextOverflowClassifier, což odpovídá chybám přetečení kontextu u Anthropic, OpenAI, Google, Bedrock a dalších:

import { Think, defaultContextOverflowClassifier } from "@cloudflare/think";

export class MyAgent extends Think {
	classifyChatError = defaultContextOverflowClassifier;
}
import { Think, defaultContextOverflowClassifier } from "@cloudflare/think";

export class MyAgent extends Think<Env> {
	override classifyChatError = defaultContextOverflowClassifier;
}

Nebo si napište vlastní, případně s delegováním na vestavěný klasifikátor:

import { Think, defaultContextOverflowClassifier } from "@cloudflare/think";

export class MyAgent extends Think {
	classifyChatError(error) {
		if (error instanceof Error && /rate.?limit/i.test(error.message)) {
			return "rate_limit";
		}
		return defaultContextOverflowClassifier(error);
	}
}
import type { ChatErrorClassification } from "@cloudflare/think";
import { Think, defaultContextOverflowClassifier } from "@cloudflare/think";

export class MyAgent extends Think<Env> {
	override classifyChatError(error: unknown): ChatErrorClassification | void {
		if (error instanceof Error && /rate.?limit/i.test(error.message)) {
			return "rate_limit";
		}
		return defaultContextOverflowClassifier(error);
	}
}