import type { AgentEvent, Message, ToolCall, ToolCallRecord } from '../types.js'; import type { ToolRegistry } from '../tool/registry.js'; import type { ToolContext } from '../tool/types.js'; import type { SecurityGuard } from '../security/guard.js'; import type { HookContext, HookResult } from '../hooks/types.js'; import type { Middleware } from '../middleware/types.js'; import type { HistoryManager } from './history-manager.js'; import type { EngineContext } from './types.js'; /** 工具执行配置 */ export interface ToolExecutorConfig extends EngineContext { /** Tool Registry */ toolRegistry: ToolRegistry; /** 安全守卫(可选) */ securityGuard?: SecurityGuard; /** 全局禁止的工具名列表(执行层拦截,防止 LLM 幻觉调用被禁工具) */ deniedTools?: string[]; /** 单工具执行超时(毫秒) */ toolTimeout: number; /** 长任务(委派/脚本)超时硬上限(毫秒),默认 1800000(30 分钟);覆盖后可让长任务超过默认上限 */ maxScriptTimeoutMs?: number; /** 中间件工具阶段执行器 */ runMiddlewareToolPhase: (phase: 'onToolBefore' | 'onToolAfter', ctx: HookContext) => Promise; /** 历史管理器 */ historyManager: HistoryManager; /** 中间件列表 */ getMiddleware: () => Middleware[] | undefined; /** 是否存在 before_tool hook / onToolBefore 拦截器(存在时禁用流式工具早分发,防止 block/modify 语义被绕过) */ hasBeforeToolInterceptors?: () => boolean; } /** 工具执行结果 */ export interface ToolExecResult { result: string; isError: boolean; actualArgs: Record; duration: number; call: ToolCall; } /** LoopState 接口(与 Engine 交互的最小契约) */ export interface ToolLoopState { sessionId: string; messages: Message[]; toolContext: ToolContext; internalAbort: AbortController; iteration: number; toolCallRecords: ToolCallRecord[]; consecutiveToolFailures: Map; /** 运行时被禁用的工具名集合(由 engine 的 disableDataFetchTools 设置)。 * 与 deniedTools(构造时固定)不同,这是动态的:当 iterationGuard / dataFetchGuard * 触发后,数据获取类工具被加入此集合,阻止 LLM 幻觉调用已被禁用的工具。 */ blockedTools?: Set; /** 流式工具早分发:已就绪工具调用的预执行结果缓存(callId -> 执行结果)。 * 由 engine 在每次 LLM 调用前新建/重置;executeOneToolCall 命中缓存时跳过实际执行。 */ earlyToolResults?: Map; /** 流式工具早分发:进行中的预执行 Promise(流结束后 await 收尾) */ earlyExecutions?: Promise[]; } /** * 工具执行管理器 * * 职责: * - 按并发属性分组执行 tool_calls * - 串行/并行执行 + 超时保护 * - 熔断器(连续失败自动阻断) * - 安全检查(execute_command) * - Hook/Middleware 生命周期集成 */ export declare class AgentToolExecutor { private config; /** 连续失败熔断阈值:同一工具连续失败超过此值后自动阻断(降低以加速失败重试终止) */ private static readonly CIRCUIT_BREAKER_THRESHOLD; /** 被禁工具集合(构造时编译,O(1) 查找) */ private deniedToolsSet; constructor(config: ToolExecutorConfig); /** * 流式工具早分发:LLM 仍在生成后续内容时,立即预执行已聚合完成的工具调用。 * * 安全约束(任一命中则不早分发,交由流结束后的正常路径处理): * - 工具未注册 / 被禁(deniedTools / blockedTools)/ 熔断中 * - execute_command(securityGuard 可能改写参数) * - delegate_task(子代理路径复杂,含限流槽位) * - 非并发工具(必须保持分组串行语义) * - 参数 JSON 解析失败(可能流截断,需走截断抢救路径) * - 存在 before_tool hook / onToolBefore middleware(可能 block 或 modify 参数) * * 预执行结果写入 state.earlyToolResults;executeOneToolCall 命中缓存时 * 跳过实际执行(事件发射、历史写入、records、after hooks 均保持原时序不变)。 */ startEarlyExecution(state: ToolLoopState, call: ToolCall): void; /** 等待全部早分发预执行收尾(engine 在 LLM 流结束后调用;abort 场景同样先收尾再退出) */ awaitEarlyExecutions(state: ToolLoopState): Promise; /** 执行一批 tool_calls(按并发属性分组) */ executeToolCalls(state: ToolLoopState, toolCalls: ToolCall[]): AsyncGenerator; /** * P2 #9: 统一的工具结果输出辅助 — 消除 8+ 处重复的 push+addHistory+record 模式 * * 推送 tool_result 事件 + 写入历史 + 记录到 toolCallRecords */ private emitToolResult; /** 按并发属性将 tool_calls 分组 */ private groupByConcurrency; /** 并行执行一组工具(按顺序推送事件和结果) */ private executeToolGroupParallel; /** * 空参数/截断参数检测(串行与并行路径共用)。 * * 因 max_tokens 截断导致 JSON 解析失败或关键参数缺失、或参数实质为空时, * 返回可自我纠正的明确错误;返回 null 表示参数正常可继续执行。 * * countsAsFailure 语义:截断类参数错误(内容过长)属于可纠正参数问题,模型改用 * write_file + content_file 策略即可成功,不计入连续失败计数(避免触发 per-tool 熔断, * 否则正确的重试也会被永久拦截)。空参数错误仍计入。真正的运行时失败(执行后报错)始终正常累加熔断计数。 */ private buildTruncationGuard; /** 串行执行单个工具调用(含安全检查 + Hooks) */ private executeOneToolCall; /** * 检测工具结果是否为"软失败"(工具执行未抛异常,但结果内容表明操作失败)。 * 解决 HTTP 200 但 body 含错误、浏览器超时、脚本运行时错误等未被识别为失败的问题。 * 这些软失败会导致 consecutiveAllFailThreshold 熔断器无法正确触发。 */ private detectSoftFailure; /** 带超时的工具执行 */ private runWithTimeout; /** * 执行非 delegate_task 工具(带超时),从 runWithTimeout 抽取以保持逻辑清晰 */ private executeToolWithTimeout; /** * 执行 delegate_task(带超时 + 子 Agent AbortController + 部分结果保留) * * 与普通工具不同,delegate_task 的超时会同时 abort 子 Agent, * 防止子 Agent 在父级超时后继续运行导致资源泄漏。 * * 超时或异常时,尝试从子 Agent 获取部分结果(通过 ctx.injectPartialResult 累积的内容), * 避免子 Agent 长时间运行后所有输出都丢失。 */ private executeDelegateWithTimeout; private emitUnavailableToolResult; /** 检查工具是否被熔断 */ private isCircuitBroken; /** 更新工具连续失败计数 */ private updateFailureCount; /** * 从截断的 JSON 中抢救 run_script 的参数。 * 当 LLM 生成过长的 code 导致 JSON 被截断时,尝试提取 language 和 code 字段并修复执行。 * 返回 null 表示抢救失败。 */ private rescueRunScriptArgs; /** * 从截断的 JSON 中抢救 delegate_task 的参数。 * delegate_task 的 task 字段可能很长(包含数据、指令),导致 JSON 被截断。 * 抢救策略:提取 agent(短字段,不会被截断)和 task(可能不完整但仍可执行)。 * 返回 null 表示抢救失败。 */ private rescueDelegateTaskArgs; /** * 从截断的 JSON 中抢救 write_file / append_file 的参数。 * 当 LLM 生成过长的 content 导致 JSON 被截断时,尝试提取 path 和部分内容并写入。 * 返回 null 表示抢救失败。 */ private rescueWriteFileArgs; } //# sourceMappingURL=tool-executor.d.ts.map