/** * Agent class that uses the agent-loop directly. * No transport abstraction - calls streamSimple via the loop. */ /** * [WHO]: AgentOptions, Agent, and loop policy option plumbing * [FROM]: Depends on ./agent-loop.js and ./structured-adaptive-agent-loop.js * [TO]: Consumed by core/lib/agent-core/src/index.ts * [HERE]: core/lib/agent-core/src/agent.ts - */ import { type ImageContent, type Message, type Model, type ThinkingBudgets, type Transport } from "@catui/ai/types"; import type { AgentEvent, AgentLoopFramework, AgentLoopFrameworkInput, AgentLoopConfig, AgentMessage, AgentState, AgentTool, StreamFn, ThinkingLevel } from "./types.js"; export interface AgentOptions { initialState?: Partial; /** * Converts AgentMessage[] to LLM-compatible Message[] before each LLM call. * Default filters to user/assistant/toolResult and converts attachments. */ convertToLlm?: (messages: AgentMessage[]) => Message[] | Promise; /** * Optional transform applied to context before convertToLlm. * Use for context pruning, injecting external context, etc. */ transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise; /** * Steering mode: "all" = send all steering messages at once, "one-at-a-time" = one per turn */ steeringMode?: "all" | "one-at-a-time"; /** * Follow-up mode: "all" = send all follow-up messages at once, "one-at-a-time" = one per turn */ followUpMode?: "all" | "one-at-a-time"; /** * Custom stream function (for proxy backends, etc.). Default uses streamSimple. */ streamFn?: StreamFn; /** * Optional session identifier forwarded to LLM providers. * Used by providers that support session-based caching (e.g., OpenAI Codex). */ sessionId?: string; /** * Resolves an API key dynamically for each LLM call. * Useful for expiring tokens (e.g., GitHub Copilot OAuth). */ getApiKey?: (provider: string) => Promise | string | undefined; /** * Custom token budgets for thinking levels (token-based providers only). */ thinkingBudgets?: ThinkingBudgets; /** * Preferred transport for providers that support multiple transports. */ transport?: Transport; /** * Maximum delay in milliseconds to wait for a retry when the server requests a long wait. * If the server's requested delay exceeds this value, the request fails immediately, * allowing higher-level retry logic to handle it with user visibility. * Default: 60000 (60 seconds). Set to 0 to disable the cap. */ maxRetryDelayMs?: number; /** * Force a loop framework for all models in this Agent. * When omitted, the current model's `agentLoopFramework` setting is used. */ agentLoopFramework?: AgentLoopFrameworkInput; /** * Optional tool permission gate used by loop execution. */ canUseTool?: AgentLoopConfig["canUseTool"]; /** * Optional aggregate tool-result batch budget used by loop execution. */ maxToolResultBatchSizeChars?: AgentLoopConfig["maxToolResultBatchSizeChars"]; /** * Optional in-loop model error recovery hook used by loop execution. */ recoverModelError?: AgentLoopConfig["recoverModelError"]; /** Maximum in-loop model error recoveries per prompt. */ maxModelErrorRecoveryAttempts?: number; /** Maximum automatic output-token recovery turns per prompt. */ maxOutputTokenRecoveryAttempts?: number; /** Optional target for automatic continuation when output is under-complete. */ outputTokenBudget?: AgentLoopConfig["outputTokenBudget"]; /** Optional stop hook for validation/correction continuation turns. */ runStopHooks?: AgentLoopConfig["runStopHooks"]; /** Maximum stop-hook continuation turns per prompt. */ maxStopHookContinuations?: number; /** Optional non-blocking summary hook for completed tool batches. */ createToolUseSummary?: AgentLoopConfig["createToolUseSummary"]; /** Maximum concurrency for concurrency-safe tool batches. */ maxToolConcurrency?: number; /** Maximum assistant turns allowed for one prompt/continue loop. */ maxTurnsPerPrompt?: number; /** Maximum tool calls allowed for one prompt/continue loop. */ maxToolCallsPerPrompt?: number; } export type AgentLoopPolicyOptions = Pick; export declare class Agent { private _state; private listeners; private abortController?; private convertToLlm; private transformContext?; private steeringQueue; private followUpQueue; private steeringMode; private followUpMode; streamFn: StreamFn; private _sessionId?; getApiKey?: (provider: string) => Promise | string | undefined; private runningPrompt?; private resolveRunningPrompt?; private _thinkingBudgets?; private _transport; private _maxRetryDelayMs?; private _agentLoopFramework?; private canUseTool?; private maxToolResultBatchSizeChars?; private recoverModelError?; private maxModelErrorRecoveryAttempts?; private maxOutputTokenRecoveryAttempts?; private outputTokenBudget?; private runStopHooks?; private maxStopHookContinuations?; private createToolUseSummary?; private maxToolConcurrency?; private maxTurnsPerPrompt?; private maxToolCallsPerPrompt?; constructor(opts?: AgentOptions); /** * Get the current session ID used for provider caching. */ get sessionId(): string | undefined; /** * Set the session ID for provider caching. * Call this when switching sessions (new session, branch, resume). */ set sessionId(value: string | undefined); /** * Get the current thinking budgets. */ get thinkingBudgets(): ThinkingBudgets | undefined; /** * Set custom thinking budgets for token-based providers. */ set thinkingBudgets(value: ThinkingBudgets | undefined); /** * Get the current preferred transport. */ get transport(): Transport; /** * Set the preferred transport. */ setTransport(value: Transport): void; /** * Get the current max retry delay in milliseconds. */ get maxRetryDelayMs(): number | undefined; /** * Set the maximum delay to wait for server-requested retries. * Set to 0 to disable the cap. */ set maxRetryDelayMs(value: number | undefined); get agentLoopFramework(): AgentLoopFramework; setAgentLoopFramework(value: AgentLoopFrameworkInput | undefined): void; get state(): AgentState; subscribe(fn: (e: AgentEvent) => void): () => void; setSystemPrompt(v: string): void; setModel(m: Model): void; setThinkingLevel(l: ThinkingLevel): void; setSteeringMode(mode: "all" | "one-at-a-time"): void; getSteeringMode(): "all" | "one-at-a-time"; setFollowUpMode(mode: "all" | "one-at-a-time"): void; getFollowUpMode(): "all" | "one-at-a-time"; setTools(t: AgentTool[]): void; setLoopPolicy(options: Partial): void; setModelErrorRecovery(recoverModelError: AgentLoopConfig["recoverModelError"] | undefined): void; replaceMessages(ms: AgentMessage[]): void; appendMessage(m: AgentMessage): void; /** * Queue a steering message to interrupt the agent mid-run. * Delivered after current tool execution, skips remaining tools. */ steer(m: AgentMessage): void; /** * Queue a follow-up message to be processed after the agent finishes. * Delivered only when agent has no more tool calls or steering messages. */ followUp(m: AgentMessage): void; clearSteeringQueue(): void; clearFollowUpQueue(): void; clearAllQueues(): void; hasQueuedMessages(): boolean; private dequeueSteeringMessages; private dequeueFollowUpMessages; clearMessages(): void; abort(): void; waitForIdle(): Promise; reset(): void; /** Send a prompt with an AgentMessage */ prompt(message: AgentMessage | AgentMessage[]): Promise; prompt(input: string, images?: ImageContent[]): Promise; /** * Continue from current context (used for retries and resuming queued messages). */ continue(): Promise; /** * Run the agent loop. * If messages are provided, starts a new conversation turn with those messages. * Otherwise, continues from existing context. */ private _runLoop; private emit; }