UNPKG

@convex-dev/agent

Version:

A agent component for Convex.

49 lines (44 loc) 1.76 kB
import type { StepResult, StopCondition } from "ai"; /** * A stop condition that only matches tool calls which completed * successfully (i.e. produced a `tool-result`, not a `tool-error`). * * Use this instead of the AI SDK's `hasToolCall` when you want the * agent to retry on argument validation failures rather than stopping. */ export function hasSuccessfulToolCall(toolName: string): StopCondition<any> { return ({ steps }) => steps[steps.length - 1]?.toolResults?.some( (result) => result.toolName === toolName, ) ?? false; } export async function willContinue( steps: StepResult<any>[], stopWhen: StopCondition<any> | Array<StopCondition<any>> | undefined, ): Promise<boolean> { const step = steps.at(-1)!; // we aren't doing another round after a tool result // TODO: whether to handle continuing after too much context used.. if (step.finishReason !== "tool-calls") return false; // Count both successful results and errors as completed outputs. // In AI SDK v6, failed tool calls produce tool-error content parts // instead of tool-result, so only checking toolResults misses them. const completedOutputs = step.content?.filter( (p) => p.type === "tool-result" || p.type === "tool-error", ).length ?? step.toolResults.length; // we don't have a tool result, so we'll wait for more if (step.toolCalls.length > completedOutputs) return false; if (Array.isArray(stopWhen)) { return (await Promise.all(stopWhen.map(async (s) => s({ steps })))).every( (stop) => !stop, ); } return !!stopWhen && !(await stopWhen({ steps })); } export function errorToString(error: unknown): string { if (error instanceof Error) { return error.message; } return String(error); }