import type { AgentEvent, Message, ToolCall, TokenUsage } from '../types.js'; import type { LLMProvider, ResponseFormat } from '../llm/types.js'; import type { ToolDefinition } from '../tool/types.js'; import type { RetryPolicy, EngineContext } from './types.js'; import type { HistoryManager } from './history-manager.js'; /** LLM 调用配置 */ export interface LLMCallerConfig extends EngineContext { /** 主 LLM Provider */ llmProvider: LLMProvider; /** 降级 LLM Provider(可选) */ fallbackProvider?: LLMProvider; /** 重试策略 */ retryPolicy?: RetryPolicy; /** LLM 推理超时(毫秒) */ llmTimeout: number; /** 历史管理器(可选,用于上下文过长时压缩) */ historyManager?: HistoryManager; /** 调试模式:开启后把 LLM 请求的网络诊断信息(域名/IP/代理/耗时)以 debug 事件抛出 */ debug?: boolean; } /** 单次 LLM 调用的可观测指标(附加在 LLMCallResult 上,不影响主流程消费) */ export interface LLMCallObservability { /** 首 token 延迟(毫秒,从 callWithRetry 入口到首个内容 chunk) */ timeToFirstToken?: number; /** 生成速度(tokens/秒) */ tokensPerSecond?: number; /** 实际重试次数(不含首次调用) */ retryCount?: number; /** 实际生效的模型(降级到 fallback 时记录 fallback 模型名) */ fallbackModel?: string; } /** 流式 LLM 调用回调(流式工具早分发) */ export interface LLMStreamCallbacks { /** * 单个 tool_call 的参数聚合完成(后续 tool_call index 出现,或流结束)时立即上报。 * 消费方可借此提前启动工具执行,使执行时间与剩余内容生成时间重叠。 */ onToolCallReady?: (call: ToolCall) => void; /** * 新的 LLM 调用尝试即将开始(重试 / TPM 退避 / fallback)。 * 上一次尝试产生的早分发状态应作废:早分发缓存须清空,避免跨尝试复用过期结果。 */ onToolCallReset?: () => void; } /** 单次 LLM 调用结果 */ export interface LLMCallResult { /** 完整的 assistant message */ assistant: Message; /** 本次调用消耗的 token */ usage?: TokenUsage; /** 可观测指标(TTFT / 重试 / 降级 / 速度),供 observability 中间件消费 */ observability?: LLMCallObservability; } /** * LLM 调用管理器 * * 职责: * - 流式调用 LLM(支持 tool_calls 累积) * - 重试 + 指数退避 * - 主 Provider → Fallback Provider 降级 */ export declare class LLMCaller { private config; constructor(config: LLMCallerConfig); /** 更新主 Provider(热更新场景) */ updateProvider(provider: LLMProvider): void; /** 是否为不可重试错误(4xx 类确定性错误) */ private isNonRetryableError; /** * 错误分类:将错误分类为不同类型,用于决定重试策略和用户提示。 * * 分类优先级: * 1. 结构化字段优先 —— 若 err 携带 `kind` 或 `retryable`,直接依此判定,跨供应商一致; * 2. 文本兜底 —— 无结构化字段时回落到错误文本解析(保持旧行为兼容)。 * * 分类优先级(文本兜底):context_too_long > rate_limit_tpm > non_retryable > timeout > server_error > network_error > retryable */ private classifyError; /** * 是否为 TPM(Tokens Per Minute)速率限制错误。 * * TPM 是按分钟计的时间窗口限制,与配额耗尽(quota)本质不同: * - TPM 429:等待速率窗口重置(~60s)后重试即可恢复 * - quota 429:配额真正耗尽,重试无意义 * * 典型错误消息:"rate limit exceeded on dimension: tpm" */ private isTPMRateLimitError; /** * 带重试和降级的 LLM 调用 * 返回 assistant message 或 null(所有尝试失败) * * 特殊处理:当 API 返回"输入过长"错误时,自动压缩历史并重试(最多一次) * 遇到不可重试错误(4xx 配额/认证等)时立即放弃,不浪费重试次数 */ callWithRetry(sessionId: string, messages: Message[], toolDefs: ToolDefinition[], abortSignal: AbortSignal, callbacks?: LLMStreamCallbacks, responseFormat?: ResponseFormat): AsyncGenerator; /** 是否为"上下文过长"错误 */ private isContextTooLongError; /** * TPM 速率限制专用退避重试。 * * TPM(Tokens Per Minute)是按分钟计的滚动窗口限制,窗口内累积的 token 消耗 * 不会因为等待 20s/30s 而消失——只有窗口完全滑过(~60s)后最早消耗的 token * 才过期。因此必须等待接近完整窗口周期再重试,否则重试请求叠加已有消耗仍会 429。 * * 策略:每次固定等待 60s(覆盖完整 TPM 窗口),重试 2 次。 * 当错误不再是 TPM 类型时提前跳出(可能是其他错误或已成功)。 */ private retryOnTPM; /** 单次 LLM 调用(流式),带诊断信息 */ private callOnceWithDiag; } //# sourceMappingURL=llm-caller.d.ts.map