@huyooo/ai-chat-core 0.2.42 → 0.2.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -307,6 +307,17 @@ interface AgentConfig {
307
307
  * ```
308
308
  */
309
309
  mcpServers?: McpServerConfig[];
310
+ /**
311
+ * 上下文总结回调(走 ai-server 等外部服务)
312
+ *
313
+ * 当对话历史超过模型 context window 时,orchestrator 调用此函数执行 AI 总结。
314
+ * 宿主提供实现(如 smart-finder 的 toolAI),ai-chat-core 不关心具体调用方式。
315
+ *
316
+ * @param systemPrompt 总结指令
317
+ * @param userPrompt 格式化后的中间对话历史
318
+ * @returns 总结后的文本
319
+ */
320
+ summarize?: (systemPrompt: string, userPrompt: string) => Promise<string>;
310
321
  }
311
322
  /** 深度思考模式 */
312
323
  type ThinkingMode = 'enabled' | 'disabled';
package/dist/events.d.ts CHANGED
@@ -1 +1 @@
1
- export { ax as AbortEvent, bf as AgentPhase, bg as AgentStatusEvent, b5 as CHAT_EVENT_TYPES, a as ChatEvent, aC as ChatEventType, bd as CompactEndEvent, be as CompactEvent, bc as CompactStartEvent, av as DoneEvent, aa as ErrorCategory, ab as ErrorDetails, aw as ErrorEvent, at as PlanStep, au as PlanStepStatus, aj as SearchEndEvent, ak as SearchEvent, a6 as SearchResult, ai as SearchResultEvent, ah as SearchStartEvent, ay as StatusEvent, aA as StepEndEvent, aB as StepEvent, az as StepStartEvent, ar as TextDeltaEvent, as as TextEvent, ae as ThinkingDeltaEvent, af as ThinkingEndEvent, ag as ThinkingEvent, ad as ThinkingStartEvent, a9 as TokenUsage, ao as ToolApprovalRequestEvent, a8 as ToolCallInfo, an as ToolCallOutputEvent, ap as ToolCallRequestEvent, am as ToolCallResultEvent, al as ToolCallStartEvent, a7 as ToolCallStatus, U as ToolErrorShape, aq as ToolEvent, ac as ToolUIShape, aV as createAbort, bh as createAgentStatus, aQ as createApiError, bj as createCompactEnd, bi as createCompactStart, aO as createDone, aP as createError, aU as createParseError, aR as createRateLimitError, aI as createSearchEnd, aH as createSearchResult, aG as createSearchStart, aX as createStepEnd, aW as createStepStart, aN as createTextDelta, aE as createThinkingDelta, aF as createThinkingEnd, aD as createThinkingStart, aT as createTimeoutError, aL as createToolCallOutput, aM as createToolCallRequest, aK as createToolCallResult, aJ as createToolCallStart, aS as createToolError, b2 as isAbortEvent, bk as isCompactEvent, b1 as isErrorEvent, b4 as isRetryableError, aZ as isSearchEvent, b0 as isStatusEvent, b3 as isStepEvent, a$ as isTextEvent, aY as isThinkingEvent, a4 as isThrowableToolError, a_ as isToolEvent } from './events-7V2drqe4.js';
1
+ export { ax as AbortEvent, bf as AgentPhase, bg as AgentStatusEvent, b5 as CHAT_EVENT_TYPES, a as ChatEvent, aC as ChatEventType, bd as CompactEndEvent, be as CompactEvent, bc as CompactStartEvent, av as DoneEvent, aa as ErrorCategory, ab as ErrorDetails, aw as ErrorEvent, at as PlanStep, au as PlanStepStatus, aj as SearchEndEvent, ak as SearchEvent, a6 as SearchResult, ai as SearchResultEvent, ah as SearchStartEvent, ay as StatusEvent, aA as StepEndEvent, aB as StepEvent, az as StepStartEvent, ar as TextDeltaEvent, as as TextEvent, ae as ThinkingDeltaEvent, af as ThinkingEndEvent, ag as ThinkingEvent, ad as ThinkingStartEvent, a9 as TokenUsage, ao as ToolApprovalRequestEvent, a8 as ToolCallInfo, an as ToolCallOutputEvent, ap as ToolCallRequestEvent, am as ToolCallResultEvent, al as ToolCallStartEvent, a7 as ToolCallStatus, U as ToolErrorShape, aq as ToolEvent, ac as ToolUIShape, aV as createAbort, bh as createAgentStatus, aQ as createApiError, bj as createCompactEnd, bi as createCompactStart, aO as createDone, aP as createError, aU as createParseError, aR as createRateLimitError, aI as createSearchEnd, aH as createSearchResult, aG as createSearchStart, aX as createStepEnd, aW as createStepStart, aN as createTextDelta, aE as createThinkingDelta, aF as createThinkingEnd, aD as createThinkingStart, aT as createTimeoutError, aL as createToolCallOutput, aM as createToolCallRequest, aK as createToolCallResult, aJ as createToolCallStart, aS as createToolError, b2 as isAbortEvent, bk as isCompactEvent, b1 as isErrorEvent, b4 as isRetryableError, aZ as isSearchEvent, b0 as isStatusEvent, b3 as isStepEvent, a$ as isTextEvent, aY as isThinkingEvent, a4 as isThrowableToolError, a_ as isToolEvent } from './events-CU5D5ray.js';
package/dist/events.js CHANGED
@@ -1 +1 @@
1
- var t={doubao:{id:"doubao",displayName:"豆包",supportsVision:!0,supportsThinking:!0,thinkingFormat:"reasoning",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"responses",defaultMaxTokens:16384},deepseek:{id:"deepseek",displayName:"DeepSeek",supportsVision:!1,supportsThinking:!0,thinkingFormat:"reasoning",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"responses",defaultMaxTokens:32768},qwen:{id:"qwen",displayName:"通义千问",supportsVision:!1,supportsThinking:!0,thinkingFormat:"thinking_enabled",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"openai",defaultMaxTokens:32768},gemini:{id:"gemini",displayName:"Gemini",supportsVision:!0,supportsThinking:!0,thinkingFormat:"thought_signature",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"gemini",defaultMaxTokens:65536,requiresSpecialHandling:["thought_signature"]},gpt:{id:"gpt",displayName:"GPT",supportsVision:!0,supportsThinking:!0,thinkingFormat:"reasoning",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"openai",defaultMaxTokens:128e3},claude:{id:"claude",displayName:"Claude",supportsVision:!0,supportsThinking:!0,thinkingFormat:"reasoning",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"openai",defaultMaxTokens:64e3}},e=[{id:"doubao-seed-1-6-250615",displayName:"豆包 Seed 1.6",family:"doubao",protocol:"ark",visible:!0,supportsVision:!0,contextWindow:"256K",contextWindowTokens:256e3,pricing:["输入 0.8 元/百万tokens","输出 2-8 元/百万tokens"]},{id:"doubao-seed-1-8-251215",displayName:"豆包 Seed 1.8",family:"doubao",protocol:"ark",contextWindow:"256K",contextWindowTokens:256e3,pricing:["输入 0.8 元/百万tokens","输出 2-8 元/百万tokens"]},{id:"deepseek-v3-2-251201",displayName:"DeepSeek V3.2",family:"deepseek",protocol:"deepseek",visible:!0,supportsVision:!1,contextWindow:"128K",contextWindowTokens:128e3,pricing:["输入 2 元/百万tokens","输出 3 元/百万tokens"]},{id:"qwen3-vl-plus",displayName:"通义千问 3 VL",family:"qwen",protocol:"qwen",visible:!0,supportsVision:!0,contextWindow:"262K",contextWindowTokens:262144,pricing:["输入 1 元/百万tokens","输出 10 元/百万tokens"]},{id:"gemini-3-pro-preview",displayName:"Gemini 3 Pro",family:"gemini",protocol:"gemini",visible:!0,supportsVision:!0,contextWindow:"1M",contextWindowTokens:1e6,pricing:["输入 1.25 元/百万tokens","输出 10 元/百万tokens"]},{id:"gemini-2.5-flash-preview-05-20",displayName:"Gemini 2.5 Flash",family:"gemini",protocol:"gemini",contextWindow:"1M",contextWindowTokens:1e6,pricing:["输入 0.15 元/百万tokens","输出 0.6 元/百万tokens"]},{id:"gemini-2.5-pro-preview-05-06",displayName:"Gemini 2.5 Pro",family:"gemini",protocol:"gemini",contextWindow:"1M",contextWindowTokens:1e6,pricing:["输入 1.25 元/百万tokens","输出 10 元/百万tokens"]},{id:"openai/gpt-5.2",displayName:"GPT-5.2",family:"gpt",protocol:"openai",visible:!0,supportsVision:!0,contextWindow:"400K",contextWindowTokens:4e5,pricing:["输入 12.6 元/百万tokens","输出 100.8 元/百万tokens"]},{id:"anthropic/claude-opus-4.5",displayName:"Claude Opus 4.5",family:"claude",protocol:"anthropic",visible:!0,supportsVision:!0,contextWindow:"200K",contextWindowTokens:2e5,pricing:["输入 36 元/百万tokens","输出 180 元/百万tokens"]}];function n(t){return e.find(e=>e.id===t||t.includes(e.id))}function o(e){const o=n(e);if(o)return t[o.family]}function i(t){const e=n(t);if(!e)return!1;if("boolean"==typeof e.supportsVision)return e.supportsVision;const i=o(t);return i?.supportsVision??!1}function r(t){const e=o(t.id),n=i(t.id),r=e?.supportsThinking??!1,a=e?.supportsNativeSearch??!1,s=[];return n&&s.push("多模态"),r&&s.push("深度思考"),t.contextWindow&&s.push(`长上下文(${t.contextWindow})`),a&&s.push("联网搜索"),s}function a(t){return t instanceof Error&&"object"==typeof t.toolError&&null!==t.toolError&&"string"==typeof t.toolError.message}function s(t){return{type:"agent_status",data:{phase:t}}}e.filter(t=>t.visible).map(t=>{const e=o(t.id),n=e?.supportsThinking??!1,a=i(t.id);return{modelId:t.id,displayName:t.displayName,supportsThinking:n,supportsVision:a,tooltip:{features:r(t),cost:t.pricing}}});var p=["thinking_start","thinking_delta","thinking_end","search_start","search_result","search_end","tool_call_start","tool_call_result","tool_call_output","tool_approval_request","tool_call_request","text_delta","done","error","abort","step_start","step_end","compact_start","compact_end","agent_status"];function u(){return{type:"thinking_start",data:{startedAt:Date.now()}}}function d(t){return{type:"thinking_delta",data:{content:t}}}function c(t){const e=Date.now();return{type:"thinking_end",data:{endedAt:e,duration:e-t}}}function l(t){return{type:"search_start",data:{query:t,startedAt:Date.now()}}}function g(t,e){const n=Date.now();return{type:"search_result",data:{results:t,endedAt:n,duration:n-e}}}function y(t,e,n){const o=Date.now();return{type:"search_end",data:{success:t,error:n,endedAt:o,duration:o-e}}}function m(t,e,n){return{type:"tool_call_start",data:{id:t,name:e,args:n,startedAt:Date.now()}}}function k(t,e,n,o,i,r,a){const s=Date.now();return{type:"tool_call_result",data:{id:t,name:e,result:n,success:o,error:r,endedAt:s,duration:s-i,ui:a}}}function f(t,e,n,o){return{type:"tool_call_output",data:{id:t,name:e,stream:n,chunk:o,at:Date.now()}}}function h(t,e,n){return{type:"tool_call_request",data:{id:t,name:e,args:n,requestedAt:Date.now()}}}function _(t){return{type:"text_delta",data:{content:t}}}function w(t,e,n){return{type:"done",data:{text:t,usage:e,duration:n}}}function T(t){return{type:"error",data:t}}function x(t,e={}){return T({category:"api",message:t,...e})}function b(t,e,n){return T({category:"rate_limit",message:t,code:"RATE_LIMIT",statusCode:429,retryable:!0,retryAfter:e,context:n})}function v(t,e,n){return T({category:"tool",message:t,code:"TOOL_ERROR",context:e,cause:n,retryable:!1})}function N(t,e){return T({category:"timeout",message:t,code:"TIMEOUT",retryable:!0,context:e})}function W(t,e){return T({category:"parse",message:t,code:"PARSE_ERROR",cause:e,retryable:!1})}function S(t){return{type:"abort",data:{reason:t,abortedAt:Date.now()}}}function V(t,e){return{type:"step_start",data:{stepNumber:t,description:e,startedAt:Date.now()}}}function A(t,e){const n=Date.now();return{type:"step_end",data:{stepNumber:t,endedAt:n,duration:n-e}}}function D(t,e){return{type:"compact_start",data:{estimatedTokens:t,budget:e,startedAt:Date.now()}}}function F(t,e,n,o,i){const r=Date.now();return{type:"compact_end",data:{success:t,compressedTokens:e,originalMessageCount:n,compressedMessageCount:o,endedAt:r,duration:r-i}}}function M(t){return t.type.startsWith("thinking_")}function q(t){return t.type.startsWith("search_")}function C(t){return t.type.startsWith("tool_")}function E(t){return"text_delta"===t.type}function R(t){return"done"===t.type||"error"===t.type||"abort"===t.type}function G(t){return"error"===t.type}function K(t){return"abort"===t.type}function O(t){return t.type.startsWith("step_")}function P(t){return t.type.startsWith("compact_")}function I(t){return"error"===t.type&&!0===t.data.retryable}export{p as CHAT_EVENT_TYPES,S as createAbort,s as createAgentStatus,x as createApiError,F as createCompactEnd,D as createCompactStart,w as createDone,T as createError,W as createParseError,b as createRateLimitError,y as createSearchEnd,g as createSearchResult,l as createSearchStart,A as createStepEnd,V as createStepStart,_ as createTextDelta,d as createThinkingDelta,c as createThinkingEnd,u as createThinkingStart,N as createTimeoutError,f as createToolCallOutput,h as createToolCallRequest,k as createToolCallResult,m as createToolCallStart,v as createToolError,K as isAbortEvent,P as isCompactEvent,G as isErrorEvent,I as isRetryableError,q as isSearchEvent,R as isStatusEvent,O as isStepEvent,E as isTextEvent,M as isThinkingEvent,a as isThrowableToolError,C as isToolEvent};
1
+ var t={doubao:{id:"doubao",displayName:"豆包",supportsVision:!0,supportsThinking:!0,thinkingFormat:"reasoning",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"responses",defaultMaxTokens:16384},deepseek:{id:"deepseek",displayName:"DeepSeek",supportsVision:!1,supportsThinking:!0,thinkingFormat:"reasoning",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"responses",defaultMaxTokens:32768},qwen:{id:"qwen",displayName:"通义千问",supportsVision:!1,supportsThinking:!0,thinkingFormat:"thinking_enabled",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"openai",defaultMaxTokens:32768},gemini:{id:"gemini",displayName:"Gemini",supportsVision:!0,supportsThinking:!0,thinkingFormat:"thought_signature",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"gemini",defaultMaxTokens:65536,requiresSpecialHandling:["thought_signature"]},gpt:{id:"gpt",displayName:"GPT",supportsVision:!0,supportsThinking:!0,thinkingFormat:"reasoning",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"openai",defaultMaxTokens:128e3},claude:{id:"claude",displayName:"Claude",supportsVision:!0,supportsThinking:!0,thinkingFormat:"reasoning",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"openai",defaultMaxTokens:64e3}},e=[{id:"doubao-seed-1-6-250615",displayName:"豆包 Seed 1.6",family:"doubao",protocol:"ark",visible:!0,supportsVision:!0,contextWindow:"256K",contextWindowTokens:256e3,pricing:["输入 0.8 元/百万tokens","输出 2-8 元/百万tokens"]},{id:"doubao-seed-1-8-251215",displayName:"豆包 Seed 1.8",family:"doubao",protocol:"ark",contextWindow:"256K",contextWindowTokens:256e3,pricing:["输入 0.8 元/百万tokens","输出 2-8 元/百万tokens"]},{id:"deepseek-v3-2-251201",displayName:"DeepSeek V3.2",family:"deepseek",protocol:"deepseek",visible:!0,supportsVision:!1,contextWindow:"128K",contextWindowTokens:128e3,pricing:["输入 2 元/百万tokens","输出 3 元/百万tokens"]},{id:"qwen3-vl-plus",displayName:"通义千问 3 VL",family:"qwen",protocol:"qwen",visible:!0,supportsVision:!0,contextWindow:"262K",contextWindowTokens:262144,pricing:["输入 1 元/百万tokens","输出 10 元/百万tokens"]},{id:"qwen3.5-plus",displayName:"通义千问 3.5 Plus",family:"qwen",protocol:"qwen",contextWindow:"1M",contextWindowTokens:1e6,pricing:["输入 0.8 元/百万tokens","输出 4.8 元/百万tokens"]},{id:"qwen-long",displayName:"通义千问 Long",family:"qwen",protocol:"qwen",contextWindow:"10M",contextWindowTokens:1e7,pricing:["输入 0.5 元/百万tokens","输出 2 元/百万tokens"]},{id:"gemini-3-pro-preview",displayName:"Gemini 3 Pro",family:"gemini",protocol:"gemini",visible:!0,supportsVision:!0,contextWindow:"1M",contextWindowTokens:1e6,pricing:["输入 1.25 元/百万tokens","输出 10 元/百万tokens"]},{id:"gemini-2.5-flash-preview-05-20",displayName:"Gemini 2.5 Flash",family:"gemini",protocol:"gemini",contextWindow:"1M",contextWindowTokens:1e6,pricing:["输入 0.15 元/百万tokens","输出 0.6 元/百万tokens"]},{id:"gemini-2.5-pro-preview-05-06",displayName:"Gemini 2.5 Pro",family:"gemini",protocol:"gemini",contextWindow:"1M",contextWindowTokens:1e6,pricing:["输入 1.25 元/百万tokens","输出 10 元/百万tokens"]},{id:"openai/gpt-5.2",displayName:"GPT-5.2",family:"gpt",protocol:"openai",visible:!0,supportsVision:!0,contextWindow:"400K",contextWindowTokens:4e5,pricing:["输入 12.6 元/百万tokens","输出 100.8 元/百万tokens"]},{id:"anthropic/claude-opus-4.5",displayName:"Claude Opus 4.5",family:"claude",protocol:"anthropic",visible:!0,supportsVision:!0,contextWindow:"200K",contextWindowTokens:2e5,pricing:["输入 36 元/百万tokens","输出 180 元/百万tokens"]}];function n(t){return e.find(e=>e.id===t||t.includes(e.id))}function o(e){const o=n(e);if(o)return t[o.family]}function i(t){const e=n(t);if(!e)return!1;if("boolean"==typeof e.supportsVision)return e.supportsVision;const i=o(t);return i?.supportsVision??!1}function r(t){const e=o(t.id),n=i(t.id),r=e?.supportsThinking??!1,a=e?.supportsNativeSearch??!1,s=[];return n&&s.push("多模态"),r&&s.push("深度思考"),t.contextWindow&&s.push(`长上下文(${t.contextWindow})`),a&&s.push("联网搜索"),s}function a(t){return t instanceof Error&&"object"==typeof t.toolError&&null!==t.toolError&&"string"==typeof t.toolError.message}function s(t){return{type:"agent_status",data:{phase:t}}}e.filter(t=>t.visible).map(t=>{const e=o(t.id),n=e?.supportsThinking??!1,a=i(t.id);return{modelId:t.id,displayName:t.displayName,supportsThinking:n,supportsVision:a,tooltip:{features:r(t),cost:t.pricing}}});var p=["thinking_start","thinking_delta","thinking_end","search_start","search_result","search_end","tool_call_start","tool_call_result","tool_call_output","tool_approval_request","tool_call_request","text_delta","done","error","abort","step_start","step_end","compact_start","compact_end","agent_status"];function u(){return{type:"thinking_start",data:{startedAt:Date.now()}}}function d(t){return{type:"thinking_delta",data:{content:t}}}function c(t){const e=Date.now();return{type:"thinking_end",data:{endedAt:e,duration:e-t}}}function l(t){return{type:"search_start",data:{query:t,startedAt:Date.now()}}}function g(t,e){const n=Date.now();return{type:"search_result",data:{results:t,endedAt:n,duration:n-e}}}function y(t,e,n){const o=Date.now();return{type:"search_end",data:{success:t,error:n,endedAt:o,duration:o-e}}}function m(t,e,n){return{type:"tool_call_start",data:{id:t,name:e,args:n,startedAt:Date.now()}}}function k(t,e,n,o,i,r,a){const s=Date.now();return{type:"tool_call_result",data:{id:t,name:e,result:n,success:o,error:r,endedAt:s,duration:s-i,ui:a}}}function f(t,e,n,o){return{type:"tool_call_output",data:{id:t,name:e,stream:n,chunk:o,at:Date.now()}}}function h(t,e,n){return{type:"tool_call_request",data:{id:t,name:e,args:n,requestedAt:Date.now()}}}function _(t){return{type:"text_delta",data:{content:t}}}function w(t,e,n){return{type:"done",data:{text:t,usage:e,duration:n}}}function x(t){return{type:"error",data:t}}function T(t,e={}){return x({category:"api",message:t,...e})}function b(t,e,n){return x({category:"rate_limit",message:t,code:"RATE_LIMIT",statusCode:429,retryable:!0,retryAfter:e,context:n})}function W(t,e,n){return x({category:"tool",message:t,code:"TOOL_ERROR",context:e,cause:n,retryable:!1})}function v(t,e){return x({category:"timeout",message:t,code:"TIMEOUT",retryable:!0,context:e})}function N(t,e){return x({category:"parse",message:t,code:"PARSE_ERROR",cause:e,retryable:!1})}function S(t){return{type:"abort",data:{reason:t,abortedAt:Date.now()}}}function V(t,e){return{type:"step_start",data:{stepNumber:t,description:e,startedAt:Date.now()}}}function q(t,e){const n=Date.now();return{type:"step_end",data:{stepNumber:t,endedAt:n,duration:n-e}}}function A(t,e){return{type:"compact_start",data:{estimatedTokens:t,budget:e,startedAt:Date.now()}}}function D(t,e,n,o,i){const r=Date.now();return{type:"compact_end",data:{success:t,compressedTokens:e,originalMessageCount:n,compressedMessageCount:o,endedAt:r,duration:r-i}}}function M(t){return t.type.startsWith("thinking_")}function F(t){return t.type.startsWith("search_")}function C(t){return t.type.startsWith("tool_")}function E(t){return"text_delta"===t.type}function R(t){return"done"===t.type||"error"===t.type||"abort"===t.type}function G(t){return"error"===t.type}function K(t){return"abort"===t.type}function O(t){return t.type.startsWith("step_")}function P(t){return t.type.startsWith("compact_")}function I(t){return"error"===t.type&&!0===t.data.retryable}export{p as CHAT_EVENT_TYPES,S as createAbort,s as createAgentStatus,T as createApiError,D as createCompactEnd,A as createCompactStart,w as createDone,x as createError,N as createParseError,b as createRateLimitError,y as createSearchEnd,g as createSearchResult,l as createSearchStart,q as createStepEnd,V as createStepStart,_ as createTextDelta,d as createThinkingDelta,c as createThinkingEnd,u as createThinkingStart,v as createTimeoutError,f as createToolCallOutput,h as createToolCallRequest,k as createToolCallResult,m as createToolCallStart,W as createToolError,K as isAbortEvent,P as isCompactEvent,G as isErrorEvent,I as isRetryableError,F as isSearchEvent,R as isStatusEvent,O as isStepEvent,E as isTextEvent,M as isThinkingEvent,a as isThrowableToolError,C as isToolEvent};
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as AgentConfig, T as ToolExecutor$1, M as ModelFamilyConfig, R as RouteResult, C as ChatOptions, a as ChatEvent, b as ModelOption, c as McpConnectionInfo, J as JsonSchemaObject, d as Tool, e as ChatMessage } from './events-7V2drqe4.js';
2
- export { ax as AbortEvent, N as ActionType, B as AutoRunConfig, z as AutoRunMode, b5 as CHAT_EVENT_TYPES, i as CLAUDE_FAMILY, aC as ChatEventType, x as ChatMode, g as DEEPSEEK_FAMILY, D as DOUBAO_FAMILY, av as DoneEvent, aa as ErrorCategory, ab as ErrorDetails, aw as ErrorEvent, O as ExecResult, G as GEMINI_FAMILY, h as GPT_FAMILY, Z as MODELS, f as MODEL_FAMILIES, j as MODEL_REGISTRY, bb as McpConnectionStatus, ba as McpServerConfig, t as ModelFamilyId, w as ModelRegistryEntry, at as PlanStep, au as PlanStepStatus, P as ProtocolId, H as ProviderType, Q as QWEN_FAMILY, L as RenderType, F as ResponsesApiTool, aj as SearchEndEvent, ak as SearchEvent, a6 as SearchResult, ai as SearchResultEvent, ah as SearchStartEvent, S as SearchStrategy, ay as StatusEvent, aA as StepEndEvent, aB as StepEvent, az as StepStartEvent, ar as TextDeltaEvent, as as TextEvent, ae as ThinkingDeltaEvent, af as ThinkingEndEvent, ag as ThinkingEvent, u as ThinkingFormat, y as ThinkingMode, ad as ThinkingStartEvent, a9 as TokenUsage, ao as ToolApprovalRequestEvent, v as ToolCallFormat, a8 as ToolCallInfo, an as ToolCallOutputEvent, ap as ToolCallRequestEvent, am as ToolCallResultEvent, al as ToolCallStartEvent, a7 as ToolCallStatus, X as ToolConfigItem, I as ToolContext, E as ToolDefinition, U as ToolError, V as ToolErrorCode, U as ToolErrorShape, aq as ToolEvent, W as ToolPlugin, K as ToolUI, ac as ToolUIShape, Y as UserToolDefinition, aV as createAbort, aQ as createApiError, aO as createDone, aP as createError, aU as createParseError, aR as createRateLimitError, aI as createSearchEnd, aH as createSearchResult, aG as createSearchStart, aX as createStepEnd, aW as createStepStart, aN as createTextDelta, aE as createThinkingDelta, aF as createThinkingEnd, aD as createThinkingStart, aT as createTimeoutError, aL as createToolCallOutput, aM as createToolCallRequest, aK as createToolCallResult, aJ as createToolCallStart, aS as createToolError, a5 as getArg, b8 as getDefaultProvider, _ as getModelByModelId, k as getModelEntry, l as getModelFamily, m as getModelProtocol, s as getModelSearchStrategy, o as getModelsByFamily, p as getModelsByProtocol, n as getVisibleModels, b2 as isAbortEvent, b1 as isErrorEvent, b9 as isModelForProvider, b4 as isRetryableError, aZ as isSearchEvent, b0 as isStatusEvent, b3 as isStepEvent, a$ as isTextEvent, aY as isThinkingEvent, a4 as isThrowableToolError, a4 as isToolError, a_ as isToolEvent, r as modelSupportsNativeSearch, q as modelSupportsThinking, $ as resolveTools, a3 as rethrowToolError, b6 as routeModelToProvider, b7 as routeModelWithDetails, a2 as throwToolError, a0 as tool, a1 as tools } from './events-7V2drqe4.js';
1
+ import { A as AgentConfig, T as ToolExecutor$1, M as ModelFamilyConfig, R as RouteResult, C as ChatOptions, a as ChatEvent, b as ModelOption, c as McpConnectionInfo, J as JsonSchemaObject, d as Tool, e as ChatMessage } from './events-CU5D5ray.js';
2
+ export { ax as AbortEvent, N as ActionType, B as AutoRunConfig, z as AutoRunMode, b5 as CHAT_EVENT_TYPES, i as CLAUDE_FAMILY, aC as ChatEventType, x as ChatMode, g as DEEPSEEK_FAMILY, D as DOUBAO_FAMILY, av as DoneEvent, aa as ErrorCategory, ab as ErrorDetails, aw as ErrorEvent, O as ExecResult, G as GEMINI_FAMILY, h as GPT_FAMILY, Z as MODELS, f as MODEL_FAMILIES, j as MODEL_REGISTRY, bb as McpConnectionStatus, ba as McpServerConfig, t as ModelFamilyId, w as ModelRegistryEntry, at as PlanStep, au as PlanStepStatus, P as ProtocolId, H as ProviderType, Q as QWEN_FAMILY, L as RenderType, F as ResponsesApiTool, aj as SearchEndEvent, ak as SearchEvent, a6 as SearchResult, ai as SearchResultEvent, ah as SearchStartEvent, S as SearchStrategy, ay as StatusEvent, aA as StepEndEvent, aB as StepEvent, az as StepStartEvent, ar as TextDeltaEvent, as as TextEvent, ae as ThinkingDeltaEvent, af as ThinkingEndEvent, ag as ThinkingEvent, u as ThinkingFormat, y as ThinkingMode, ad as ThinkingStartEvent, a9 as TokenUsage, ao as ToolApprovalRequestEvent, v as ToolCallFormat, a8 as ToolCallInfo, an as ToolCallOutputEvent, ap as ToolCallRequestEvent, am as ToolCallResultEvent, al as ToolCallStartEvent, a7 as ToolCallStatus, X as ToolConfigItem, I as ToolContext, E as ToolDefinition, U as ToolError, V as ToolErrorCode, U as ToolErrorShape, aq as ToolEvent, W as ToolPlugin, K as ToolUI, ac as ToolUIShape, Y as UserToolDefinition, aV as createAbort, aQ as createApiError, aO as createDone, aP as createError, aU as createParseError, aR as createRateLimitError, aI as createSearchEnd, aH as createSearchResult, aG as createSearchStart, aX as createStepEnd, aW as createStepStart, aN as createTextDelta, aE as createThinkingDelta, aF as createThinkingEnd, aD as createThinkingStart, aT as createTimeoutError, aL as createToolCallOutput, aM as createToolCallRequest, aK as createToolCallResult, aJ as createToolCallStart, aS as createToolError, a5 as getArg, b8 as getDefaultProvider, _ as getModelByModelId, k as getModelEntry, l as getModelFamily, m as getModelProtocol, s as getModelSearchStrategy, o as getModelsByFamily, p as getModelsByProtocol, n as getVisibleModels, b2 as isAbortEvent, b1 as isErrorEvent, b9 as isModelForProvider, b4 as isRetryableError, aZ as isSearchEvent, b0 as isStatusEvent, b3 as isStepEvent, a$ as isTextEvent, aY as isThinkingEvent, a4 as isThrowableToolError, a4 as isToolError, a_ as isToolEvent, r as modelSupportsNativeSearch, q as modelSupportsThinking, $ as resolveTools, a3 as rethrowToolError, b6 as routeModelToProvider, b7 as routeModelWithDetails, a2 as throwToolError, a0 as tool, a1 as tools } from './events-CU5D5ray.js';
3
3
 
4
4
  /** 运行时配置(API Keys 和 URLs) */
5
5
  interface RuntimeConfig {
@@ -252,6 +252,8 @@ interface OrchestratorConfig {
252
252
  * 3. 客户端执行后,发新请求继续对话
253
253
  */
254
254
  clientToolNames?: Set<string>;
255
+ /** 上下文总结回调(走 ai-server 等外部服务) */
256
+ summarize?: (systemPrompt: string, userPrompt: string) => Promise<string>;
255
257
  }
256
258
  /** Orchestrator 上下文 */
257
259
  interface OrchestratorContext {
@@ -753,19 +755,8 @@ declare class ChatOrchestrator {
753
755
  * 构建标准化消息列表
754
756
  */
755
757
  private buildMessages;
756
- /**
757
- * 检测并执行上下文压缩,yield 结构化事件
758
- *
759
- * 返回(可能已压缩的)消息列表。如果不需要压缩则直接返回原消息。
760
- */
758
+ /** 检测并执行上下文压缩,通过注入的 summarize 回调走 ai-server */
761
759
  private compactIfNeeded;
762
- /**
763
- * 用当前模型总结对话历史
764
- *
765
- * 把中间历史交给同一个 adapter/model,让 AI 自己生成摘要,
766
- * 然后用 摘要 + 最近几条消息 替换原消息列表。
767
- */
768
- private aiSummarize;
769
760
  }
770
761
  /**
771
762
  * 创建 Orchestrator 实例
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{Client as e}from"@modelcontextprotocol/sdk/client/index.js";import{StdioClientTransport as t}from"@modelcontextprotocol/sdk/client/stdio.js";import{SSEClientTransport as n}from"@modelcontextprotocol/sdk/client/sse.js";import{appendFileSync as o}from"fs";import{createGateway as s,streamText as i,tool as r}from"ai";import{z as a}from"zod";var l={id:"doubao",displayName:"豆包",supportsVision:!0,supportsThinking:!0,thinkingFormat:"reasoning",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"responses",defaultMaxTokens:16384},c={id:"deepseek",displayName:"DeepSeek",supportsVision:!1,supportsThinking:!0,thinkingFormat:"reasoning",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"responses",defaultMaxTokens:32768},u={id:"qwen",displayName:"通义千问",supportsVision:!1,supportsThinking:!0,thinkingFormat:"thinking_enabled",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"openai",defaultMaxTokens:32768},p={id:"gemini",displayName:"Gemini",supportsVision:!0,supportsThinking:!0,thinkingFormat:"thought_signature",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"gemini",defaultMaxTokens:65536,requiresSpecialHandling:["thought_signature"]},d={id:"gpt",displayName:"GPT",supportsVision:!0,supportsThinking:!0,thinkingFormat:"reasoning",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"openai",defaultMaxTokens:128e3},m={id:"claude",displayName:"Claude",supportsVision:!0,supportsThinking:!0,thinkingFormat:"reasoning",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"openai",defaultMaxTokens:64e3},g={doubao:l,deepseek:c,qwen:u,gemini:p,gpt:d,claude:m},h=[{id:"doubao-seed-1-6-250615",displayName:"豆包 Seed 1.6",family:"doubao",protocol:"ark",visible:!0,supportsVision:!0,contextWindow:"256K",contextWindowTokens:256e3,pricing:["输入 0.8 元/百万tokens","输出 2-8 元/百万tokens"]},{id:"doubao-seed-1-8-251215",displayName:"豆包 Seed 1.8",family:"doubao",protocol:"ark",contextWindow:"256K",contextWindowTokens:256e3,pricing:["输入 0.8 元/百万tokens","输出 2-8 元/百万tokens"]},{id:"deepseek-v3-2-251201",displayName:"DeepSeek V3.2",family:"deepseek",protocol:"deepseek",visible:!0,supportsVision:!1,contextWindow:"128K",contextWindowTokens:128e3,pricing:["输入 2 元/百万tokens","输出 3 元/百万tokens"]},{id:"qwen3-vl-plus",displayName:"通义千问 3 VL",family:"qwen",protocol:"qwen",visible:!0,supportsVision:!0,contextWindow:"262K",contextWindowTokens:262144,pricing:["输入 1 元/百万tokens","输出 10 元/百万tokens"]},{id:"gemini-3-pro-preview",displayName:"Gemini 3 Pro",family:"gemini",protocol:"gemini",visible:!0,supportsVision:!0,contextWindow:"1M",contextWindowTokens:1e6,pricing:["输入 1.25 元/百万tokens","输出 10 元/百万tokens"]},{id:"gemini-2.5-flash-preview-05-20",displayName:"Gemini 2.5 Flash",family:"gemini",protocol:"gemini",contextWindow:"1M",contextWindowTokens:1e6,pricing:["输入 0.15 元/百万tokens","输出 0.6 元/百万tokens"]},{id:"gemini-2.5-pro-preview-05-06",displayName:"Gemini 2.5 Pro",family:"gemini",protocol:"gemini",contextWindow:"1M",contextWindowTokens:1e6,pricing:["输入 1.25 元/百万tokens","输出 10 元/百万tokens"]},{id:"openai/gpt-5.2",displayName:"GPT-5.2",family:"gpt",protocol:"openai",visible:!0,supportsVision:!0,contextWindow:"400K",contextWindowTokens:4e5,pricing:["输入 12.6 元/百万tokens","输出 100.8 元/百万tokens"]},{id:"anthropic/claude-opus-4.5",displayName:"Claude Opus 4.5",family:"claude",protocol:"anthropic",visible:!0,supportsVision:!0,contextWindow:"200K",contextWindowTokens:2e5,pricing:["输入 36 元/百万tokens","输出 180 元/百万tokens"]}];function f(e){return h.find(t=>t.id===e||e.includes(t.id))}function y(e){const t=f(e);if(t)return g[t.family]}function k(e){const t=f(e);return t?.protocol}function _(){return h.filter(e=>e.visible)}function b(e){return h.filter(t=>t.family===e)}function w(e){return h.filter(t=>t.protocol===e)}function T(e){const t=y(e);return t?.supportsThinking??!1}function v(e){const t=y(e);return t?.supportsNativeSearch??!1}function C(e){const t=f(e);if(!t)return!1;if("boolean"==typeof t.supportsVision)return t.supportsVision;const n=y(e);return n?.supportsVision??!1}function S(e){const t=y(e);return t?.searchStrategy??"tavily"}function x(e){const t=y(e.id),n=C(e.id),o=t?.supportsThinking??!1,s=t?.supportsNativeSearch??!1,i=[];return n&&i.push("多模态"),o&&i.push("深度思考"),e.contextWindow&&i.push(`长上下文(${e.contextWindow})`),s&&i.push("联网搜索"),i}var A=_().map(e=>{const t=y(e.id),n=t?.supportsThinking??!1,o=C(e.id);return{modelId:e.id,displayName:e.displayName,supportsThinking:n,supportsVision:o,tooltip:{features:x(e),cost:e.pricing}}});function $(e){return A.find(t=>t.modelId===e)}function R(e){return e instanceof Error&&"object"==typeof e.toolError&&null!==e.toolError&&"string"==typeof e.toolError.message}function M(e,t,n){const o={message:e,code:t,...n},s=new Error(e);throw Object.defineProperty(s,"toolError",{value:o,enumerable:!0}),s}function N(e,t,n){if(R(e))throw e;M(e instanceof Error?e.message:String(e),t,n)}function I(e,t){return e[t]}function K(e){return{tools:[e]}}function O(e){return{tools:e}}async function q(e){const t=[];for(const n of e){const e=await n;"tools"in e&&Array.isArray(e.tools)?t.push(...e.tools):"name"in e&&"execute"in e&&t.push(e)}return t}function E(e){return{type:"agent_status",data:{phase:e}}}var P=["thinking_start","thinking_delta","thinking_end","search_start","search_result","search_end","tool_call_start","tool_call_result","tool_call_output","tool_approval_request","tool_call_request","text_delta","done","error","abort","step_start","step_end","compact_start","compact_end","agent_status"];function D(){return{type:"thinking_start",data:{startedAt:Date.now()}}}function U(e){return{type:"thinking_delta",data:{content:e}}}function j(e){const t=Date.now();return{type:"thinking_end",data:{endedAt:t,duration:t-e}}}function W(e){return{type:"search_start",data:{query:e,startedAt:Date.now()}}}function J(e,t){const n=Date.now();return{type:"search_result",data:{results:e,endedAt:n,duration:n-t}}}function z(e,t,n){const o=Date.now();return{type:"search_end",data:{success:e,error:n,endedAt:o,duration:o-t}}}function F(e,t,n){return{type:"tool_call_start",data:{id:e,name:t,args:n,startedAt:Date.now()}}}function V(e,t,n,o,s,i,r){const a=Date.now();return{type:"tool_call_result",data:{id:e,name:t,result:n,success:o,error:i,endedAt:a,duration:a-s,ui:r}}}function G(e,t,n,o){return{type:"tool_call_output",data:{id:e,name:t,stream:n,chunk:o,at:Date.now()}}}function B(e,t,n){return{type:"tool_call_request",data:{id:e,name:t,args:n,requestedAt:Date.now()}}}function L(e){return{type:"text_delta",data:{content:e}}}function Q(e,t,n){return{type:"done",data:{text:e,usage:t,duration:n}}}function H(e){return{type:"error",data:e}}function Y(e,t={}){return H({category:"api",message:e,...t})}function Z(e,t,n){return H({category:"rate_limit",message:e,code:"RATE_LIMIT",statusCode:429,retryable:!0,retryAfter:t,context:n})}function X(e,t,n){return H({category:"tool",message:e,code:"TOOL_ERROR",context:t,cause:n,retryable:!1})}function ee(e,t){return H({category:"timeout",message:e,code:"TIMEOUT",retryable:!0,context:t})}function te(e,t){return H({category:"parse",message:e,code:"PARSE_ERROR",cause:t,retryable:!1})}function ne(e){return{type:"abort",data:{reason:e,abortedAt:Date.now()}}}function oe(e,t){return{type:"step_start",data:{stepNumber:e,description:t,startedAt:Date.now()}}}function se(e,t){const n=Date.now();return{type:"step_end",data:{stepNumber:e,endedAt:n,duration:n-t}}}function ie(e){return e.type.startsWith("thinking_")}function re(e){return e.type.startsWith("search_")}function ae(e){return e.type.startsWith("tool_")}function le(e){return"text_delta"===e.type}function ce(e){return"done"===e.type||"error"===e.type||"abort"===e.type}function ue(e){return"error"===e.type}function pe(e){return"abort"===e.type}function de(e){return e.type.startsWith("step_")}function me(e){return"error"===e.type&&!0===e.data.retryable}var ge=["rm -rf /","rm -rf ~","format","mkfs","dd if=","shutdown","reboot","sudo rm","sudo format"];function he(e=process.cwd()){return{async executeCommand(t,n,o,s){if(o?.aborted)return{success:!1,error:"操作已取消"};if(function(e){const t=e.toLowerCase().trim();return ge.some(e=>t.includes(e.toLowerCase()))}(t))return{success:!1,error:"该命令被安全策略阻止"};try{const{spawn:i}=await import("child_process");return new Promise(r=>{let a="",l="",c=!1,u=null;const p=i("sh",["-c",t],{cwd:n||e,env:process.env,detached:"win32"!==process.platform}),d=e=>{if(!c){c=!0;try{"win32"!==process.platform&&"number"==typeof p.pid?process.kill(-p.pid,e):p.kill(e)}catch{try{p.kill(e)}catch{}}u&&clearTimeout(u),u=setTimeout(()=>{try{"win32"!==process.platform&&"number"==typeof p.pid?process.kill(-p.pid,"SIGKILL"):p.kill("SIGKILL")}catch{}},1500)}},m=setTimeout(()=>{c||(d("SIGTERM"),r({success:!1,error:"命令执行超时(30秒)"}))},3e4),g=()=>{c||(d("SIGTERM"),clearTimeout(m),r({success:!1,error:"操作已取消"}))};o?.addEventListener("abort",g),p.stdout?.on("data",e=>{const t=e.toString();a+=t,s?.onStdout?.(t)}),p.stderr?.on("data",e=>{const t=e.toString();l+=t,s?.onStderr?.(t)}),p.on("close",e=>{if(clearTimeout(m),o?.removeEventListener("abort",g),u&&(clearTimeout(u),u=null),c)return;const t=a.trim(),n=l.trim();if(0===e)r({success:!0,output:t||n||"执行成功"});else if(t){r({success:!0,output:t+(n?`\n[警告: ${n}]`:"")})}else r(n?{success:!1,error:n}:{success:!1,error:`命令退出码: ${e}`})}),p.on("error",e=>{clearTimeout(m),o?.removeEventListener("abort",g),u&&(clearTimeout(u),u=null),c||r({success:!1,error:e.message})})})}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}}}var fe="https://ark.cn-beijing.volces.com/api/v3",ye="https://openrouter.ai/api/v1",ke="doubao-seed-1-6-250615";function _e(e){return be(e).provider}function be(e){const t=f(e);return t?{provider:t.protocol,registryEntry:t,familyConfig:y(e),isDefault:!1}:{provider:"ark",isDefault:!0}}function we(){return"ark"}function Te(e,t){return _e(e)===t}var ve=!1,Ce=null,Se=class e{prefix;constructor(e){this.prefix=e}static enable(e){ve=e}static isEnabled(){return ve}static setLogFile(e){Ce=e}static module(t){return new e(`[${t}]`)}debug(...e){ve&&this.writeToFile("debug",e)}info(...e){ve&&this.writeToFile("info",e)}warn(...e){ve&&this.writeToFile("warn",e)}error(...e){ve&&this.writeToFile("error",e)}writeToFile(e,t){if(Ce)try{const n=JSON.stringify({t:Date.now(),level:e,module:this.prefix,args:t.map(e=>{try{return"string"==typeof e?e:JSON.parse(JSON.stringify(e))}catch{return String(e)}})});o(Ce,n+"\n")}catch{}}},xe=Se.module("MCP"),Ae=class{connections=new Map;async connectAll(e){const t=await Promise.allSettled(e.map(e=>this.connect(e)));for(let n=0;n<t.length;n++){const o=t[n],s=e[n].name;"rejected"===o.status&&xe.error(`[${s}] 连接失败:`,o.reason)}}async connect(o){const{name:s}=o;this.connections.has(s)&&await this.disconnect(s),xe.info(`[${s}] 正在连接...`);const i=new e({name:"ai-chat-mcp-client",version:"1.0.0"});let r;if("stdio"===o.transport){if(!o.command)throw new Error(`[${s}] stdio 模式必须指定 command`);r=new t({command:o.command,args:o.args,env:o.env,cwd:o.cwd})}else{if("sse"!==o.transport)throw new Error(`[${s}] 不支持的传输方式: ${o.transport}`);if(!o.url)throw new Error(`[${s}] sse 模式必须指定 url`);r=new n(new URL(o.url))}const a={config:o,client:i,transport:r,status:"connecting",tools:[]};this.connections.set(s,a);try{await i.connect(r),a.status="connected",xe.info(`[${s}] 已连接`);const e=await this.discoverTools(a);a.tools=e,xe.info(`[${s}] 发现 ${e.length} 个工具:`,e.map(e=>e.name))}catch(e){throw a.status="error",a.error=e instanceof Error?e.message:String(e),xe.error(`[${s}] 连接失败:`,a.error),e}}async discoverTools(e){const{client:t,config:n}=e,{tools:o}=await t.listTools();return o.map(e=>this.adaptTool(e,n.name,t))}adaptTool(e,t,n){const o=this.convertSchema(e.inputSchema);return{name:e.name,description:e.description||`MCP tool from ${t}`,parameters:o,execute:async t=>{const o=await n.callTool({name:e.name,arguments:t}),s=[];if(Array.isArray(o.content))for(const e of o.content)if("object"==typeof e&&null!==e){const t=e;"text"===t.type&&"string"==typeof t.text?s.push(t.text):"image"===t.type?s.push(`[image: ${t.mimeType||"unknown"}]`):"resource"===t.type&&s.push(JSON.stringify(t))}return{text:s.join("\n")||JSON.stringify(o.content)}}}}convertSchema(e){const t={},n=[],o=e.properties;if(o)for(const[e,n]of Object.entries(o))t[e]=this.convertProperty(n);return Array.isArray(e.required)&&n.push(...e.required.filter(e=>"string"==typeof e)),{type:"object",properties:t,required:n.length>0?n:void 0}}convertProperty(e){const t={type:"string"==typeof e.type?e.type:"string"};if("string"==typeof e.description&&(t.description=e.description),Array.isArray(e.enum)&&(t.enum=e.enum),e.items&&"object"==typeof e.items&&(t.items=this.convertProperty(e.items)),e.properties&&"object"==typeof e.properties){t.properties={};for(const[n,o]of Object.entries(e.properties))t.properties[n]=this.convertProperty(o)}return Array.isArray(e.required)&&(t.required=e.required.filter(e=>"string"==typeof e)),t}getAllTools(){const e=[];for(const t of this.connections.values())"connected"===t.status&&e.push(...t.tools);return e}getConnectionInfos(){return Array.from(this.connections.values()).map(e=>({name:e.config.name,status:e.status,toolCount:e.tools.length,error:e.error}))}async disconnect(e){const t=this.connections.get(e);if(t)try{await t.client.close(),xe.info(`[${e}] 已断开`)}catch(t){xe.error(`[${e}] 断开失败:`,t)}finally{t.status="disconnected",t.tools=[],this.connections.delete(e)}}async disconnectAll(){const e=Array.from(this.connections.keys());await Promise.allSettled(e.map(e=>this.disconnect(e)))}},$e=Se.module("ContextCompressor");function Re(e){return e?Math.ceil(e.length/3.2):0}function Me(e){let t=4;if(t+=Re(e.content),e.toolCalls)for(const n of e.toolCalls)t+=Re(n.name),t+=Re(n.arguments),t+=10;return e.images&&(t+=85*e.images.length),t}function Ne(e){let t=3;for(const n of e)t+=Me(n);return t}function Ie(e){const t=e.compactThresholdRatio??.8;return Math.floor(e.contextWindowTokens*t)-e.maxOutputTokens}function Ke(e,t,n){const o="system"===e[0]?.role?e[0]:null;let s=null;for(let t=o?1:0;t<e.length;t++)if("user"===e[t].role){s=e[t];break}const i=[];o&&i.push(o),s&&i.push(s),i.push({role:"system",content:`[对话历史摘要]\n${t}`}),i.push(...n);const r=Ne(i);return $e.info(`AI 总结应用完成: ${e.length} → ${i.length} 条消息, ~${r} tokens`),i}var Oe='你是一个对话历史压缩助手。请总结以下对话历史,保留所有关键信息:\n\n要求:\n1. 保留所有文件修改记录(哪些文件被创建/修改/删除了,具体改了什么)\n2. 保留所有关键决策和结论\n3. 保留错误信息和解决方案\n4. 保留用户的明确要求和偏好\n5. 用简洁的条目列表格式输出\n6. 不要遗漏任何可能影响后续工作的信息\n\n直接输出摘要,不要开头说"以下是摘要"之类的话。';function qe(e){const t=[];for(const n of e){const e="assistant"===n.role?"AI":"user"===n.role?"用户":"工具";if("assistant"===n.role&&n.toolCalls&&n.toolCalls.length>0){const o=n.toolCalls.map(e=>{const t=e.arguments.length>200?e.arguments.slice(0,200)+"...":e.arguments;return` 调用 ${e.name}(${t})`}).join("\n"),s=n.content?`${n.content}\n${o}`:o;t.push(`[${e}]\n${s}`)}else if("tool"===n.role){const o=n.content.length>1e3?n.content.slice(0,1e3)+`... (共 ${n.content.length} 字符)`:n.content;t.push(`[${e}: ${n.toolName??"unknown"}]\n${o}`)}else n.content&&t.push(`[${e}]\n${n.content}`)}return t.join("\n\n---\n\n")}var Ee="web_search_ai";var Pe=Se.module("Orchestrator");function De(e){const t=new Map;for(const n of e){const e=String(n?.url??"").trim();if(!e)continue;const o=String(n?.snippet??"").trim();let s=String(n?.title??"").trim();if(!s)try{s=new URL(e).hostname}catch{s=e}const i=t.get(e);i?(!i.snippet&&o&&(i.snippet=o),!i.title&&s&&(i.title=s)):t.set(e,{title:s,url:e,snippet:o})}return Array.from(t.values())}var Ue=class{config;constructor(e){this.config={maxIterations:25,...e}}async*chat(e,t,n,o){const s=Date.now(),i=this.config.maxIterations??25;let r=this.buildMessages(n,t);const{contextWindowTokens:a,maxOutputTokens:l}=function(e){const t=f(e);if(!t)throw new Error(`模型 ${e} 未在 MODEL_REGISTRY 中注册`);const n=g[t.family];if(!n)throw new Error(`模型 ${e} 的家族 ${t.family} 未定义`);if(!t.contextWindowTokens)throw new Error(`模型 ${e} 缺少 contextWindowTokens 配置`);if(!n.defaultMaxTokens)throw new Error(`模型家族 ${t.family} 缺少 defaultMaxTokens 配置`);return{contextWindowTokens:t.contextWindowTokens,maxOutputTokens:n.defaultMaxTokens}}(o.model),c={contextWindowTokens:a,maxOutputTokens:l};{const t=this.compactIfNeeded(e,r,c,o,n.signal);let s=await t.next();for(;!s.done;)yield s.value,s=await t.next();r=s.value}let u=0,p="",d=[],m=0,h=!1,y=!1,k="",_=0,b={promptTokens:0,completionTokens:0,totalTokens:0,reasoningTokens:0,cachedTokens:0},w=!1;for(;u<i;){if(n.signal.aborted)return void(yield ne("请求已取消"));if(u++,u>1){const t=this.compactIfNeeded(e,r,c,o,n.signal);let s=await t.next();for(;!s.done;)yield s.value,s=await t.next();r=s.value}const i=Date.now();Pe.info(`======= 第 ${u} 轮开始 =======`),yield oe(u),yield E("thinking");let a="",l=0,g=!1,f=!1;const T={};let v=!1;const C=e=>{T[e]=(T[e]||0)+1};try{const c=[];let S=!1;const x=!0===o.enableThinking,A=!0===o.enableSearch;Pe.debug("调用 adapter.streamOnce",{enableThinking:x,enableSearch:A});const $=e.streamOnce(r,n.tools,{model:o.model,enableThinking:x,enableSearch:A,signal:n.signal});for await(const e of $)switch(C(e.type),e.type){case"text":e.text&&(v||(v=!0,Pe.debug("首次收到 text",{thinkingStarted:g,thinkingComplete:f}),yield E(null)),x&&g&&!f&&(Pe.debug("text 触发 thinking_end"),f=!0,yield j(l)),p+=e.text,yield L(e.text));break;case"thinking":if(!x)break;if(e.thinking)if(f)Pe.warn("⚠️ thinkingComplete=true 但收到 thinking",e.thinking.slice(0,30)),Pe.warn("当前状态",{textStarted:v,chunkCounts:T});else if(v)Pe.warn("⚠️ text 开始后收到 thinking",e.thinking.slice(0,30));else{let t=e.thinking;if(!g&&(t=t.replace(/^(?:\r?\n)+/,""),!t))break;g||(g=!0,l=Date.now(),Pe.debug("发送 thinking_start"),yield E(null),yield D()),a+=t,yield U(t)}break;case"thinking_done":if(!x)break;Pe.info("收到 thinking_done",{thinkingStarted:g,thinkingComplete:f}),g&&!f?(f=!0,Pe.debug("发送 thinking_end"),yield j(l)):g||Pe.warn("⚠️ 收到 thinking_done 但 thinkingStarted=false");break;case"tool_call":if(e.toolCall){if(!n.tools||0===n.tools.length){Pe.warn("收到 tool_call 但当前未注入工具,已忽略",{toolName:e.toolCall.name});break}c.push(e.toolCall),S=!0}break;case"search_result":if(!A)break;e.searchResults&&(h||(h=!0,m=Date.now(),yield E(null),yield W(t)),d=De(e.searchResults),yield J(d,m));break;case"done":Pe.info("收到 done",{finishReason:e.finishReason,usage:e.usage}),Pe.info(`第 ${u} 轮 chunk 统计`,T),"tool_calls"===e.finishReason&&(S=!0),e.usage&&(w=!0,b.promptTokens+=e.usage.promptTokens||0,b.completionTokens+=e.usage.completionTokens||0,b.totalTokens+=e.usage.totalTokens||0,b.reasoningTokens+=e.usage.reasoningTokens||0,b.cachedTokens+=e.usage.cachedTokens||0);break;case"error":return Pe.error("收到 error",e.error),void(yield Y(e.error??"未知错误"))}if(Pe.info(`第 ${u} 轮 for-await 循环结束`),Pe.debug("状态",{thinkingStarted:g,thinkingComplete:f}),x&&g&&!f&&(Pe.debug("补发 thinking_end"),f=!0,yield j(l)),S&&c.length>0){const e=c.map(e=>`${e.name}:${e.arguments}`).sort().join("|");if(e===k?_++:(_=0,k=e),_>=2){Pe.warn("检测到重复工具调用,注入终止提示",{signature:e.slice(0,200),count:_+1});c.map(e=>e.name).join(", ");r.push({role:"assistant",content:p,toolCalls:c});for(const e of c)r.push({role:"tool",content:`[系统提示] 你已经连续 ${_+1} 次使用相同参数调用 ${e.name},任务应已完成。请直接回复用户执行结果,不要再调用工具。`,toolCallId:e.id,toolName:e.name});yield se(u,i),p="";continue}const a=n.clientToolNames||this.config.clientToolNames,l=a?c.filter(e=>a.has(e.name)):[];if(l.length>0){Pe.info("检测到客户端工具调用,透传给客户端",l.map(e=>e.name));for(const e of l){let t;try{t=JSON.parse(e.arguments||"{}")}catch{t={}}yield B(e.id,e.name,t)}const e=Date.now()-s;return void(yield Q(p,void 0,e))}yield E(null);const g={role:"assistant",content:p,toolCalls:c};r.push(g);for(const e of c){const s=Date.now();let i;try{i=JSON.parse(e.arguments||"{}")}catch{r.push({role:"tool",content:"参数解析错误",toolCallId:e.id});continue}if(e.name===Ee){("string"==typeof i.query?i.query:"").trim()||(i.query=t)}const a=this.config.getAutoRunConfig?await this.config.getAutoRunConfig():o.autoRunConfig||this.config.autoRunConfig,l=this.config.tools?.get(e.name),c="manual"===a?.mode||!0===l?.requiresApproval;if(Pe.debug("检查工具批准",{toolName:e.name,autoRunConfigMode:a?.mode,requiresApproval:l?.requiresApproval,hasCallback:!!this.config.onToolApprovalRequest}),c&&this.config.onToolApprovalRequest){Pe.info("发送工具批准请求",e.name);const n={type:"tool_approval_request",data:{id:e.id,name:e.name,args:i,requestedAt:Date.now()}};yield n;if(!await this.config.onToolApprovalRequest({id:e.id,name:e.name,args:i})){const n=JSON.stringify({skipped:!0,message:"用户跳过了此工具"});if(e.name===Ee&&A){if(!h){h=!0,m=Date.now();const e="string"==typeof i.query?i.query:t;yield W(e)}y=!0,yield z(!1,m,`用户跳过了 ${Ee}`)}else yield V(e.id,e.name,n,!1,s);r.push({role:"tool",content:n,toolCallId:e.id,toolName:e.name});continue}}const u=e.name===Ee;if(u){if(A&&!h){h=!0,m=Date.now();const e="string"==typeof i.query?i.query:t;yield W(e)}}else yield F(e.id,e.name,i);const p=this.config.tools?.get(e.name);let g,f,k,_=n.signal;if(p?.timeout){const e=new AbortController;g=setTimeout(()=>e.abort(),p.timeout),n.signal.addEventListener("abort",()=>e.abort(),{once:!0}),_=e.signal}let b=!0;try{const t=[];let n=null;const o=()=>n?.(),s=e=>{t.push(e),o()};let r,a,l=!1;const c={toolCallId:e.id,toolName:e.name,onStdout:t=>{t&&s(G(e.id,e.name,"stdout",t))},onStderr:t=>{t&&s(G(e.id,e.name,"stderr",t))}};for(this.config.executeTool(e.name,i,_,c).then(e=>{r=e,l=!0,o()}).catch(e=>{a=e,l=!0,o()});!l||t.length>0;){for(;t.length>0;){const e=t.shift();e&&(yield e)}if(l)break;await new Promise(e=>n=e),n=null}if(a)throw a;f=JSON.stringify(r??{})}catch(e){if(b=!1,R(e))k=e.toolError,f=JSON.stringify({error:e.toolError.message});else{const t=e instanceof Error?e.message:String(e);k={message:t},f=JSON.stringify({error:t})}}void 0!==g&&clearTimeout(g);const w=this.config.tools?.get(e.name),T=b?w?.ui:void 0;if(u){if(A){let e,t=[];try{const n=JSON.parse(f||"{}");t=(Array.isArray(n?.results)?n.results:[]).map(e=>({title:"string"==typeof e?.title?e.title:"",url:"string"==typeof e?.url?e.url:"",snippet:"string"==typeof e?.snippet?e.snippet:""})).filter(e=>!!e.url),"string"==typeof n?.error&&n.error&&(e=n.error,b=!1)}catch{e=`${Ee} 返回结果解析失败`,b=!1}t.length>0&&(d=De(t),yield J(d,m)),y=!0,yield z(b,m,e)}}else yield V(e.id,e.name,f,b,s,k,T);if(r.push({role:"tool",content:f,toolCallId:e.id,toolName:e.name}),n.signal.aborted)return void(yield ne("请求已取消"))}yield se(u,i),p="";continue}yield se(u,i);break}catch(e){return yield se(u,i),void(n.signal.aborted?yield ne("请求已取消"):yield Y(e instanceof Error?e.message:String(e)))}}u>=i&&Pe.warn(`达到最大迭代次数 ${i},强制结束工具调用循环`),h&&!y&&(yield z(!0,m));const T=Date.now()-s,v=w?{promptTokens:b.promptTokens,completionTokens:b.completionTokens,totalTokens:b.totalTokens,...b.reasoningTokens>0?{reasoningTokens:b.reasoningTokens}:{},...b.cachedTokens>0?{cachedTokens:b.cachedTokens}:{}}:void 0;yield Q(p,v,T)}buildMessages(e,t){const n=[];e.systemPrompt&&n.push({role:"system",content:e.systemPrompt});for(const t of e.history){const e={role:t.role,content:t.content};t.tool_calls&&(e.toolCalls=t.tool_calls.map(e=>({id:e.id,name:e.function.name,arguments:e.function.arguments,thought_signature:e.thought_signature}))),"tool"===t.role&&t.tool_call_id&&(e.toolCallId=t.tool_call_id),n.push(e)}return t&&n.push({role:"user",content:t,images:e.images}),n}async*compactIfNeeded(e,t,n,o,s){if(!function(e,t){return Ne(e)>Ie(t)}(t,n))return t;const i=Date.now(),r=Ne(t),a=Ie(n),l=t.length;yield function(e,t){return{type:"compact_start",data:{estimatedTokens:e,budget:t,startedAt:Date.now()}}}(r,a);const{messages:c,success:u}=await this.aiSummarize(e,t,n,o,s);return yield function(e,t,n,o,s){const i=Date.now();return{type:"compact_end",data:{success:e,compressedTokens:t,originalMessageCount:n,compressedMessageCount:o,endedAt:i,duration:i-s}}}(u,Ne(c),l,c.length,i),c}async aiSummarize(e,t,n,o,s){const{summarizeMessages:i,keepMessages:r}=function(e,t){const n=t.keepRecentMessages??6;let o=0;"system"===e[0]?.role&&(o=1);let s=o;for(let t=o;t<e.length;t++)if("user"===e[t].role){s=t+1;break}const i=Math.max(s,e.length-n),r=e.slice(i),a=e.slice(s,i);if(a.length<2)return{summarizeMessages:[],keepMessages:e.slice(o)};const l=Ne(e),c=Ie(t);return $e.info(`准备 AI 总结: ~${l} tokens > budget ${c}, 总结 ${a.length} 条中间消息, 保留最近 ${r.length} 条`),{summarizeMessages:[{role:"system",content:Oe},{role:"user",content:qe(a)}],keepMessages:r}}(t,n);if(0===i.length)return Pe.info("中间历史太短,跳过 AI 总结"),{messages:t,success:!0};Pe.info("开始 AI 总结对话历史...");try{let n="";const a=e.streamOnce(i,[],{model:o.model,enableThinking:!1,enableSearch:!1,signal:s});for await(const e of a)if("text"===e.type&&e.text&&(n+=e.text),"error"===e.type)return Pe.error("AI 总结失败:",e.error),{messages:t,success:!1};return n.trim()?(Pe.info(`AI 总结完成: ${n.length} 字符`),{messages:Ke(t,n,r),success:!0}):(Pe.warn("AI 总结返回空内容,保持原消息"),{messages:t,success:!1})}catch(e){return Pe.error("AI 总结异常:",e),{messages:t,success:!1}}}};function je(e){return new Ue(e)}var We={400:"请求参数错误",401:"API 认证失败,请检查 API Key 配置",402:"账户余额不足,请充值后重试",403:"没有权限访问此模型",404:"请求的模型或接口不存在",429:"请求过于频繁,请稍后重试",500:"API 服务器内部错误,请稍后重试",502:"API 网关错误,请稍后重试",503:"API 服务暂时不可用,请稍后重试",504:"API 请求超时,请稍后重试"};function Je(e,t,n){const o=function(e){try{const t=JSON.parse(e);if(t?.error?.message)return{message:t.error.message,type:t.error.type};if("string"==typeof t?.error_msg)return{message:t.error_msg};if("string"==typeof t?.message)return{message:t.message}}catch{}return null}(t),s=o?.message,i=We[e];if(i)return s&&s.length<=100?`${i}(${s})`:i;if(s){return`${n} 错误 (${e}): ${s.length>200?s.slice(0,200)+"...":s}`}return`${n} 错误 (${e})`}var ze=Se.module("ArkProtocol"),Fe=class{name="ark";apiKey;apiUrl;constructor(e){this.apiKey=e.apiKey,this.apiUrl=e.apiUrl??fe}async*stream(e,t,n){const o=this.buildRequestBody(e,t,n);ze.debug("发送 ARK 请求",{url:`${this.apiUrl}/responses`,model:n.model,enableSearch:n.enableSearch,enableThinking:n.enableThinking,toolsCount:t.length});const s=await fetch(`${this.apiUrl}/responses`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify(o),signal:n.signal});if(!s.ok){const e=await s.text();return ze.error("ARK API 错误",{status:s.status,body:e.slice(0,500)}),void(yield{type:"error",error:Je(s.status,e,"ARK")})}const i=s.body?.getReader();i?yield*this.parseSSE(i):yield{type:"error",error:"无法获取响应流"}}buildRequestBody(e,t,n){const o=this.convertMessages(e),s={model:n.model,stream:!0,max_output_tokens:n.familyConfig.defaultMaxTokens??16384,input:o},i=[],r=t.some(e=>e.name===Ee);n.enableSearch&&!r&&i.push({type:"web_search",max_keyword:5,limit:20});for(const e of t)i.push({type:"function",name:e.name,description:e.description,parameters:e.parameters});return i.length>0&&(s.tools=i),n.enableThinking&&(s.thinking={type:"enabled"}),s}convertMessages(e){const t=[];for(const n of e)switch(n.role){case"system":t.push({role:"system",content:n.content});break;case"user":{const e=[{type:"input_text",text:n.content||(n.images?.length?"请分析这张图片":"")}];if(n.images?.length)for(const t of n.images)e.push({type:"input_image",image_url:t.startsWith("data:")?t:`data:image/jpeg;base64,${t}`});t.push({role:"user",content:e});break}case"assistant":if(n.toolCalls?.length){n.content&&t.push({type:"message",role:"assistant",content:[{type:"output_text",text:n.content}]});for(const e of n.toolCalls)t.push({type:"function_call",call_id:e.id,name:e.name,arguments:e.arguments})}else t.push({role:"developer",content:`[上一轮AI回复]: ${n.content}`});break;case"tool":t.push({type:"function_call_output",call_id:n.toolCallId,output:n.content})}return t}async*parseSSE(e){const t=new TextDecoder;let n="";const o=new Map;let s=null;const i=[];let r,a=!1,l=!1,c=!1;for(;;){const{done:u,value:p}=await e.read();if(u)break;n+=t.decode(p,{stream:!0});const d=n.split("\n");n=d.pop()||"";for(const e of d){if(a)continue;if(!e.startsWith("data:"))continue;const t=e.slice(5).trim();if("[DONE]"===t){if(a=!0,o.size>0){for(const e of o.values())yield{type:"tool_call_done",toolCall:e};yield{type:"done",finishReason:"tool_calls",usage:r}}else yield{type:"done",finishReason:"stop",usage:r};return}try{const e=JSON.parse(t),n=e.response?.usage||e.usage;switch(n&&(r={promptTokens:n.input_tokens||n.prompt_tokens||0,completionTokens:n.output_tokens||n.completion_tokens||0,totalTokens:(n.input_tokens||n.prompt_tokens||0)+(n.output_tokens||n.completion_tokens||0),reasoningTokens:n.output_tokens_details?.reasoning_tokens||0,cachedTokens:n.input_tokens_details?.cached_tokens||0}),e.type){case"response.output_item.added":{const t=e.item;"function_call"===t?.type&&t.call_id&&(s=t.call_id,o.set(t.call_id,{id:t.call_id,name:t.name||"",arguments:t.arguments||""}),yield{type:"tool_call_start",toolCall:{id:t.call_id,name:t.name||""}});break}case"response.function_call_arguments.delta":if(s){const t=o.get(s);t&&(t.arguments+=e.delta||"",yield{type:"tool_call_delta",toolCall:{id:s,arguments:e.delta||""}})}break;case"response.function_call_arguments.done":case"response.output_item.done":{const t=e.item;if("function_call"===t?.type&&t.call_id){const e=o.get(t.call_id);o.set(t.call_id,{id:t.call_id,name:t.name||e?.name||"",arguments:t.arguments||e?.arguments||"{}"})}break}case"response.output_text.annotation.added":{const t=e.annotation;if(t?.url){i.some(e=>e.url===t.url)||(i.push({title:t.title||t.text||"",url:t.url,snippet:t.summary||t.snippet||""}),yield{type:"search_result",searchResults:[...i]})}break}case"response.output_text.delta":e.delta&&(c||(c=!0,l||(l=!0,yield{type:"thinking_done"})),yield{type:"text_delta",delta:e.delta});break;case"response.reasoning_summary_text.delta":e.delta&&!l&&(yield{type:"thinking_delta",delta:e.delta})}}catch{}}}if(!a)if(o.size>0){for(const e of o.values())yield{type:"tool_call_done",toolCall:e};yield{type:"done",finishReason:"tool_calls",usage:r}}else yield{type:"done",finishReason:"stop",usage:r}}};function Ve(e){return new Fe(e)}var Ge=Se.module("DeepSeekProtocol"),Be=class{name="deepseek";apiKey;apiUrl;constructor(e){this.apiKey=e.apiKey,this.apiUrl=e.apiUrl??fe}async*stream(e,t,n){const o=this.buildRequestBody(e,t,n),s=`${this.apiUrl}/responses`;Ge.debug("发送 DeepSeek 请求",{url:s,model:n.model,enableSearch:n.enableSearch,enableThinking:n.enableThinking,toolsCount:t.length});const i=await fetch(s,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify(o),signal:n.signal});if(!i.ok){const e=await i.text();return Ge.error("DeepSeek API 错误",{status:i.status,body:e.slice(0,500)}),void(yield{type:"error",error:Je(i.status,e,"DeepSeek")})}const r=i.body?.getReader();r?yield*this.parseSSE(r,n.enableThinking):yield{type:"error",error:"无法获取响应流"}}buildRequestBody(e,t,n){const o=this.convertMessages(e),s={model:n.model,stream:!0,max_output_tokens:n.familyConfig.defaultMaxTokens??32768,input:o},i=[],r=t.some(e=>e.name===Ee);n.enableSearch&&!r&&i.push({type:"web_search",max_keyword:5,limit:20});for(const e of t)i.push({type:"function",name:e.name,description:e.description,parameters:e.parameters});return i.length>0&&(s.tools=i),n.enableThinking&&(s.thinking={type:"enabled"}),s}convertMessages(e){const t=[];for(const n of e)switch(n.role){case"system":t.push({role:"system",content:n.content});break;case"user":{const e=[{type:"input_text",text:n.content||(n.images?.length?"请分析这张图片":"")}];if(n.images?.length)for(const t of n.images)e.push({type:"input_image",image_url:t.startsWith("data:")?t:`data:image/jpeg;base64,${t}`});t.push({role:"user",content:e});break}case"assistant":if(n.toolCalls?.length)for(const e of n.toolCalls)t.push({type:"function_call",call_id:e.id,name:e.name,arguments:e.arguments});else t.push({role:"developer",content:`[上一轮AI回复]: ${n.content}`});break;case"tool":t.push({type:"function_call_output",call_id:n.toolCallId,output:n.content})}return t}async*parseSSE(e,t){const n=new TextDecoder;let o="";const s=new Map;let i=null;const r=[];let a,l=!1,c=!1,u=!1;for(;;){const{done:p,value:d}=await e.read();if(p)break;o+=n.decode(d,{stream:!0});const m=o.split("\n");o=m.pop()||"";for(const e of m){if(l)continue;if(!e.startsWith("data:"))continue;const n=e.slice(5).trim();if("[DONE]"===n){if(l=!0,s.size>0){for(const e of s.values())yield{type:"tool_call_done",toolCall:e};yield{type:"done",finishReason:"tool_calls",usage:a}}else yield{type:"done",finishReason:"stop",usage:a};return}try{const e=JSON.parse(n),o=e.response?.usage||e.usage;switch(o&&(a={promptTokens:o.input_tokens||o.prompt_tokens||0,completionTokens:o.output_tokens||o.completion_tokens||0,totalTokens:(o.input_tokens||o.prompt_tokens||0)+(o.output_tokens||o.completion_tokens||0),reasoningTokens:o.output_tokens_details?.reasoning_tokens||o.completion_tokens_details?.reasoning_tokens||0}),e.type){case"response.output_item.added":{const t=e.item;"function_call"===t?.type&&t.call_id&&(i=t.call_id,s.set(t.call_id,{id:t.call_id,name:t.name||"",arguments:t.arguments||""}),yield{type:"tool_call_start",toolCall:{id:t.call_id,name:t.name||""}});break}case"response.function_call_arguments.delta":if(i){const t=s.get(i);t&&(t.arguments+=e.delta||"",yield{type:"tool_call_delta",toolCall:{id:i,arguments:e.delta||""}})}break;case"response.function_call_arguments.done":case"response.output_item.done":{const t=e.item;if("function_call"===t?.type&&t.call_id){const e=s.get(t.call_id);s.set(t.call_id,{id:t.call_id,name:t.name||e?.name||"",arguments:t.arguments||e?.arguments||"{}"})}break}case"response.output_text.annotation.added":{const t=e.annotation;if(t?.url){r.some(e=>e.url===t.url)||(r.push({title:t.title||t.text||"",url:t.url,snippet:t.summary||t.snippet||""}),yield{type:"search_result",searchResults:[...r]})}break}case"response.output_text.delta":e.delta&&(u||(u=!0,t&&!c&&(c=!0,yield{type:"thinking_done"})),yield{type:"text_delta",delta:e.delta});break;case"response.reasoning_summary_text.delta":t&&e.delta&&!c&&(yield{type:"thinking_delta",delta:e.delta})}}catch{}}}if(!l)if(s.size>0){for(const e of s.values())yield{type:"tool_call_done",toolCall:e};yield{type:"done",finishReason:"tool_calls",usage:a}}else yield{type:"done",finishReason:"stop",usage:a}}};function Le(e){return new Be(e)}var Qe=Se.module("QwenProtocol"),He=class{name="qwen";apiKey;apiUrl;constructor(e){this.apiKey=e.apiKey,this.apiUrl=e.apiUrl??"https://dashscope.aliyuncs.com/compatible-mode/v1"}async*stream(e,t,n){const o=this.buildRequestBody(e,t,n),s=`${this.apiUrl}/chat/completions`;Qe.debug("发送 Qwen 请求(兼容模式)",{url:s,model:n.model,enableThinking:n.enableThinking,toolsCount:t.length});const i=await fetch(s,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify(o),signal:n.signal});if(!i.ok){const e=await i.text();return Qe.error("Qwen API 错误",{status:i.status,body:e.slice(0,500)}),void(yield{type:"error",error:Je(i.status,e,"Qwen")})}const r=i.body?.getReader();r?yield*this.parseSSE(r,n.enableThinking):yield{type:"error",error:"无法获取响应流"}}buildRequestBody(e,t,n){const o=this.convertMessages(e),s={model:n.model,messages:o,stream:!0,stream_options:{include_usage:!0}};return n.enableThinking&&(s.enable_thinking=!0,s.thinking_budget=38400),t.length>0&&(s.tools=t.map(e=>({type:"function",function:{name:e.name,description:e.description,parameters:e.parameters}}))),s}convertMessages(e){const t=[];for(const n of e)switch(n.role){case"system":t.push({role:"system",content:n.content});break;case"user":{const e=n.content||(n.images?.length?"请分析这张图片":"");if(n.images?.length){const o=[{type:"text",text:e}];for(const e of n.images)o.push({type:"image_url",image_url:{url:e.startsWith("data:")?e:`data:image/jpeg;base64,${e}`}});t.push({role:"user",content:o})}else t.push({role:"user",content:e});break}case"assistant":n.toolCalls?.length?t.push({role:"assistant",content:n.content||null,tool_calls:n.toolCalls.map(e=>({id:e.id,type:"function",function:{name:e.name,arguments:e.arguments}}))}):t.push({role:"assistant",content:n.content});break;case"tool":t.push({role:"tool",tool_call_id:n.toolCallId,content:n.content})}return t}async*parseSSE(e,t){const n=new TextDecoder;let o="";const s=new Map;let i,r,a=!1,l=!1;for(;;){const{done:c,value:u}=await e.read();if(c)break;o+=n.decode(u,{stream:!0});const p=o.split("\n");o=p.pop()||"";for(const e of p){if(!e.startsWith("data:"))continue;const n=e.slice(5).trim();if(n&&"[DONE]"!==n)try{const e=JSON.parse(n);e.usage&&(i={promptTokens:e.usage.prompt_tokens||0,completionTokens:e.usage.completion_tokens||0,totalTokens:e.usage.total_tokens||(e.usage.prompt_tokens||0)+(e.usage.completion_tokens||0)});const o=e.choices?.[0];if(!o)continue;const c=o.delta;if(!c)continue;if(t&&c.reasoning_content&&!l&&(yield{type:"thinking_delta",delta:c.reasoning_content}),c.content&&(!t||a||l||(l=!0,yield{type:"thinking_done"}),a=!0,yield{type:"text_delta",delta:c.content}),c.tool_calls?.length)for(const e of c.tool_calls){const t=e.index??0,n=s.get(t);n?e.function?.arguments&&(n.arguments+=e.function.arguments):(s.set(t,{id:e.id||`call_${t}`,name:e.function?.name||"",arguments:e.function?.arguments||""}),yield{type:"tool_call_start",toolCall:{id:e.id||`call_${t}`,name:e.function?.name||""}})}o.finish_reason&&(r=o.finish_reason)}catch{}else if("[DONE]"===n){const e=Array.from(s.values());if(e.length>0){for(const t of e)yield{type:"tool_call_done",toolCall:t};yield{type:"done",finishReason:"tool_calls",usage:i}}else{const e="tool_calls"===r||"length"===r||"error"===r?r:"stop";yield{type:"done",finishReason:e,usage:i}}return}}}const c=Array.from(s.values());if(c.length>0){for(const e of c)yield{type:"tool_call_done",toolCall:e};yield{type:"done",finishReason:"tool_calls",usage:i}}else{const e="tool_calls"===r||"length"===r||"error"===r?r:"stop";yield{type:"done",finishReason:e,usage:i}}}};function Ye(e){return new He(e)}var Ze=Se.module("GeminiProtocol"),Xe=class{name="gemini";apiKey;apiUrl;constructor(e){this.apiKey=e.apiKey,this.apiUrl=e.apiUrl??"https://generativelanguage.googleapis.com/v1beta"}async*stream(e,t,n){const o=this.buildRequestBody(e,t,n),s=`${this.apiUrl}/models/${n.model}:streamGenerateContent?key=${this.apiKey}&alt=sse`;Ze.debug("发送 Gemini 请求",{url:s.replace(this.apiKey,"***"),model:n.model,enableSearch:n.enableSearch,enableThinking:n.enableThinking,toolsCount:t.length});const i=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o),signal:n.signal});if(!i.ok){const e=await i.text();return Ze.error("Gemini API 错误",{status:i.status,body:e.slice(0,500)}),void(yield{type:"error",error:Je(i.status,e,"Gemini")})}const r=i.body?.getReader();r?yield*this.parseSSE(r):yield{type:"error",error:"无法获取响应流"}}buildRequestBody(e,t,n){const{systemInstruction:o,contents:s}=this.convertMessages(e),i={contents:s,generationConfig:{maxOutputTokens:n.familyConfig.defaultMaxTokens??65536}};o&&(i.systemInstruction=o),n.enableThinking&&(i.generationConfig.thinkingConfig={thinkingBudget:24576,includeThoughts:!0});const r=[];if(t.length>0){const e=t.map(e=>({name:e.name,description:e.description,parameters:e.parameters})),n=new Map;for(const t of e)n.has(t.name)||n.set(t.name,t);r.push({functionDeclarations:Array.from(n.values())})}else n.enableSearch&&r.push({googleSearch:{}});return r.length>0&&(i.tools=r),i}convertMessages(e){let t;const n=[];for(const o of e)switch(o.role){case"system":t={parts:[{text:o.content}]};break;case"user":{const e=[{text:o.content||(o.images?.length?"请分析这张图片":"")}];if(o.images?.length)for(const t of o.images)if(t.startsWith("data:")){const n=t.match(/^data:([^;]+);base64,(.+)$/);n&&e.push({inlineData:{mimeType:n[1],data:n[2]}})}else e.push({inlineData:{mimeType:"image/jpeg",data:t}});n.push({role:"user",parts:e});break}case"assistant":if(o.toolCalls?.length){const e=[];for(const t of o.toolCalls){const n={functionCall:{name:t.name,args:JSON.parse(t.arguments||"{}")}};n.thoughtSignature=t.thoughtSignature??"skip_thought_signature_validator",e.push(n)}n.push({role:"model",parts:e})}else n.push({role:"model",parts:[{text:o.content}]});break;case"tool":n.push({role:"user",parts:[{functionResponse:{name:o.toolName||"unknown",response:{result:o.content}}}]})}return{systemInstruction:t,contents:n}}async*parseSSE(e){const t=new TextDecoder;let n="";const o=new Map;let s=!1,i=0;for(;;){const{done:r,value:a}=await e.read();if(r)break;n+=t.decode(a,{stream:!0});const l=n.split("\n");n=l.pop()||"";for(const e of l){if(!e.startsWith("data:"))continue;const t=e.slice(5).trim();if(t)try{const e=JSON.parse(t),n=e.candidates?.[0];if(!n?.content?.parts)continue;for(const e of n.content.parts)if(e.text&&(!0===e.thought?yield{type:"thinking_delta",delta:e.text}:(s||(s=!0,yield{type:"thinking_done"}),yield{type:"text_delta",delta:e.text})),e.functionCall){const t="gemini-"+i++,n={id:t,name:e.functionCall.name,arguments:JSON.stringify(e.functionCall.args||{})};e.thoughtSignature&&(n.thoughtSignature=e.thoughtSignature),o.set(t,n),yield{type:"tool_call_start",toolCall:{id:t,name:n.name}},yield{type:"tool_call_done",toolCall:n}}const r=n.groundingMetadata;if(r?.groundingChunks?.length){const e=[];for(const t of r.groundingChunks)t.web?.uri&&e.push({title:t.web.title||"",url:t.web.uri,snippet:""});e.length>0&&(yield{type:"search_result",searchResults:e})}if(n.finishReason){const t=e.usageMetadata,n=t?{promptTokens:t.promptTokenCount||0,completionTokens:t.candidatesTokenCount||0,totalTokens:t.totalTokenCount||0,reasoningTokens:t.thoughtsTokenCount||0,cachedTokens:t.cachedContentTokenCount||0}:void 0;return void(o.size>0?yield{type:"done",finishReason:"tool_calls",usage:n}:yield{type:"done",finishReason:"stop",usage:n})}}catch{}}}o.size>0?yield{type:"done",finishReason:"tool_calls"}:yield{type:"done",finishReason:"stop"}}};function et(e){return new Xe(e)}var tt=Se.module("OpenAIProtocol"),nt=class{name="openai";apiKey;apiUrl;constructor(e){this.apiKey=e.apiKey,this.apiUrl=e.apiUrl??ye}async*stream(e,t,n){const o=this.buildRequestBody(e,t,n),s=`${this.apiUrl}/responses`;tt.debug("发送 OpenAI 请求",{url:s,model:n.model,toolsCount:t.length});const i=await fetch(s,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json","HTTP-Referer":"https://ai-chat.local","X-Title":"AI Chat"},body:JSON.stringify(o),signal:n.signal});if(!i.ok){const e=await i.text();return tt.error("OpenAI API 错误",{status:i.status,body:e.slice(0,500)}),void(yield{type:"error",error:Je(i.status,e,"OpenAI")})}const r=i.body?.getReader();r?yield*this.parseSSE(r,n.enableThinking):yield{type:"error",error:"无法获取响应流"}}buildRequestBody(e,t,n){const o=this.convertMessages(e),s={model:n.model,stream:!0,input:o};return n.enableThinking&&(s.reasoning={effort:"high"}),t.length>0&&(s.tools=t.map(e=>({type:"function",name:e.name,description:e.description,parameters:e.parameters}))),s}convertMessages(e){const t=[];for(const n of e)switch(n.role){case"system":t.push({role:"system",content:n.content});break;case"user":{const e=[{type:"input_text",text:n.content||(n.images?.length?"请分析这张图片":"")}];if(n.images?.length)for(const t of n.images)e.push({type:"input_image",image_url:t.startsWith("data:")?t:`data:image/jpeg;base64,${t}`,detail:"auto"});t.push({role:"user",content:e});break}case"assistant":if(n.toolCalls?.length)for(const e of n.toolCalls)t.push({type:"function_call",call_id:e.id,name:e.name,arguments:e.arguments});else t.push({role:"developer",content:`[上一轮AI回复]: ${n.content}`});break;case"tool":t.push({type:"function_call_output",call_id:n.toolCallId,output:n.content})}return t}async*parseSSE(e,t){const n=new TextDecoder;let o="";const s=new Map;let i=null;const r=[];let a,l=!1,c=!1,u=!1;for(;;){const{done:p,value:d}=await e.read();if(p)break;o+=n.decode(d,{stream:!0});const m=o.split("\n");o=m.pop()||"";for(const e of m){if(l)continue;if(!e.startsWith("data:"))continue;const n=e.slice(5).trim();if("[DONE]"===n){if(l=!0,s.size>0){for(const e of s.values())yield{type:"tool_call_done",toolCall:e};yield{type:"done",finishReason:"tool_calls",usage:a}}else yield{type:"done",finishReason:"stop",usage:a};return}try{const e=JSON.parse(n);tt.debug("SSE 事件",{type:e.type,event:JSON.stringify(e).slice(0,200)});const o=e.response?.usage||e.usage;switch(o&&(a={promptTokens:o.input_tokens??o.prompt_tokens??0,completionTokens:o.output_tokens??o.completion_tokens??0,totalTokens:(o.input_tokens??o.prompt_tokens??0)+(o.output_tokens??o.completion_tokens??0),reasoningTokens:o.output_tokens_details?.reasoning_tokens??0,cachedTokens:o.input_tokens_details?.cached_tokens??o.prompt_tokens_details?.cached_tokens??0}),e.type){case"response.output_item.added":{const t=e.item,n=t?.call_id||t?.id;if("function_call"===t?.type&&n){i=n;let e=t.arguments||t.input||"";"object"==typeof e&&(e=JSON.stringify(e)),s.set(n,{id:n,name:t.name||t.function?.name||"",arguments:e}),tt.debug("工具调用开始",{id:n,name:t.name,args:e.slice(0,100)}),yield{type:"tool_call_start",toolCall:{id:n,name:t.name||t.function?.name||""}}}break}case"response.function_call_arguments.delta":{const t=e.delta;if(i&&t){const e=s.get(i);e&&(e.arguments+=t,yield{type:"tool_call_delta",toolCall:{id:i,arguments:t}})}break}case"response.function_call_arguments.done":{const t=e.item_id||e.call_id||i;if(t){const n=s.get(t);if(n){e.arguments&&(n.arguments=e.arguments);try{JSON.parse(n.arguments)}catch{tt.warn("工具参数解析失败,使用空对象",{args:n.arguments.slice(0,100)}),n.arguments="{}"}}}break}case"response.output_item.done":{const t=e.item,n=t?.call_id||t?.id;if("function_call"===t?.type&&n){const e=s.get(n);let o=t.arguments||t.input||e?.arguments||"{}";"object"==typeof o&&(o=JSON.stringify(o)),s.set(n,{id:n,name:t.name||t.function?.name||e?.name||"",arguments:o}),tt.debug("工具调用完成",{id:n,name:t.name,args:o.slice(0,100)})}break}case"response.output_text.annotation.added":{const t=e.annotation;if(t?.url){r.some(e=>e.url===t.url)||(r.push({title:t.title||t.text||"",url:t.url,snippet:t.summary||t.snippet||""}),yield{type:"search_result",searchResults:[...r]})}break}case"response.output_text.delta":e.delta&&(u||(u=!0,t&&!c&&(c=!0,yield{type:"thinking_done"})),yield{type:"text_delta",delta:e.delta});break;case"response.reasoning_summary_text.delta":t&&e.delta&&!c&&(yield{type:"thinking_delta",delta:e.delta});break;case"response.done":case"response.completed":{const t=e.response;if(t?.output?.length)for(const e of t.output)if("function_call"===e.type&&e.call_id){const t=s.get(e.call_id);let n=e.arguments||t?.arguments||"{}";"object"==typeof n&&(n=JSON.stringify(n)),s.set(e.call_id,{id:e.call_id,name:e.name||t?.name||"",arguments:n}),tt.debug("response.completed: 更新工具参数",{id:e.call_id,args:n.slice(0,100)})}const n=t?.usage,o=n?{promptTokens:n.input_tokens||n.prompt_tokens||0,completionTokens:n.output_tokens||n.completion_tokens||0,totalTokens:(n.input_tokens||n.prompt_tokens||0)+(n.output_tokens||n.completion_tokens||0),reasoningTokens:n.output_tokens_details?.reasoning_tokens||0,cachedTokens:n.input_tokens_details?.cached_tokens||n.prompt_tokens_details?.cached_tokens||0}:void 0;if(a=o,l=!0,s.size>0){for(const e of s.values())tt.debug("response.completed: 发出 tool_call_done",e),yield{type:"tool_call_done",toolCall:e};yield{type:"done",finishReason:"tool_calls",usage:o}}else yield{type:"done",finishReason:"stop",usage:o};return}}}catch(t){tt.warn("SSE 解析错误",{line:e.slice(0,100),error:String(t)})}}}if(!l)if(tt.debug("流结束,执行兜底逻辑",{pendingToolCalls:s.size}),s.size>0){for(const e of s.values())yield{type:"tool_call_done",toolCall:e};yield{type:"done",finishReason:"tool_calls",usage:a}}else yield{type:"done",finishReason:"stop",usage:a}}};function ot(e){return new nt(e)}var st=Se.module("AnthropicProtocol"),it=class{name="anthropic";gateway;constructor(e){this.gateway=s({apiKey:e.apiKey})}async*stream(e,t,n){st.debug("使用 Vercel AI Gateway 调用 Claude",{model:n.model,enableThinking:n.enableThinking,toolsCount:t.length});try{const o=this.convertMessages(e),s={model:this.gateway(n.model),messages:o,maxOutputTokens:n.familyConfig.defaultMaxTokens,abortSignal:n.signal};t.length>0&&(s.tools=this.convertTools(t)),n.enableThinking&&(s.providerOptions={anthropic:{thinking:{type:"enabled",budgetTokens:1e4}}}),st.debug("发送请求到 Vercel AI Gateway",{model:n.model,messagesCount:o.length,toolsCount:t.length,enableThinking:n.enableThinking});const r=i(s);yield*this.parseStream(r)}catch(e){const t=rt(e);st.error("Vercel AI Gateway 错误",{error:t}),yield{type:"error",error:t}}}convertMessages(e){const t=[];for(const n of e)switch(n.role){case"system":t.push({role:"system",content:n.content});break;case"user":{const e=n.content||(n.images?.length?"请分析这张图片":"");if(n.images?.length){const o=[{type:"text",text:e}];for(const e of n.images)o.push({type:"image",image:e.startsWith("data:")?e:`data:image/jpeg;base64,${e}`});t.push({role:"user",content:o})}else t.push({role:"user",content:e});break}case"assistant":n.content&&t.push({role:"assistant",content:n.content});break;case"tool":t.push({role:"user",content:`[工具 ${n.toolName||"unknown"} 返回结果]: ${n.content}`})}return t}convertTools(e){const t={};for(const n of e){const e=this.jsonSchemaToZod(n.parameters);t[n.name]=r({description:n.description,inputSchema:e})}return t}jsonSchemaToZod(e){const t={};for(const[n,o]of Object.entries(e.properties)){let s;switch(o.type){case"string":s=o.enum?a.enum(o.enum):a.string();break;case"number":case"integer":s=a.number();break;case"boolean":s=a.boolean();break;case"array":s=a.array(a.string());break;default:s=a.unknown()}o.description&&(s=s.describe(o.description)),e.required?.includes(n)||(s=s.optional()),t[n]=s}return a.object(t)}async*parseStream(e){const t=new Map;let n=!1,o=!1;for await(const s of e.fullStream)switch(s.type){case"reasoning-delta":"text"in s&&s.text&&(n=!0,yield{type:"thinking_delta",delta:s.text});break;case"reasoning-end":n&&!o&&(o=!0,yield{type:"thinking_done"});break;case"text-delta":n&&!o&&(o=!0,yield{type:"thinking_done"}),"text"in s&&s.text&&(yield{type:"text_delta",delta:s.text});break;case"tool-call":if("toolCallId"in s&&"toolName"in s){const e=s.toolCallId,n=s.toolName,o="input"in s?s.input:null,i=o?"string"==typeof o?o:JSON.stringify(o):"{}";yield{type:"tool_call_start",toolCall:{id:e,name:n}},t.set(e,{id:e,name:n,arguments:i}),yield{type:"tool_call_done",toolCall:{id:e,name:n,arguments:i}}}break;case"error":{const e="error"in s?s.error:void 0,t=e?rt(e):"模型请求失败";return st.error("AI SDK stream error 事件",{error:t}),void(yield{type:"error",error:t})}case"finish":{const e=t.size>0?"tool_calls":"finishReason"in s&&"stop"===s.finishReason?"stop":"finishReason"in s&&"length"===s.finishReason?"length":"stop",n="totalUsage"in s?s.totalUsage:"usage"in s?s.usage:void 0,o=n?.promptTokens??n?.inputTokens??0,i=n?.completionTokens??n?.outputTokens??0,r=n?{promptTokens:o,completionTokens:i,totalTokens:n.totalTokens??o+i}:void 0;return void(yield{type:"done",finishReason:e,usage:r})}}yield{type:"done",finishReason:"stop"}}};function rt(e){if(!e||"object"!=typeof e)return"未知错误";const t=e,n=t.cause?.data?.error;if(n?.message){const e=t.cause?.statusCode||t.statusCode;return"insufficient_funds"===n.type||402===e?"账户余额不足,请充值后重试":401===e?"API 认证失败,请检查 API Key 配置":429===e?"请求过于频繁,请稍后重试":`API 错误: ${n.message}`}if(t.cause?.responseBody)try{const e=JSON.parse(t.cause.responseBody);if(e?.error?.message){const n=t.cause?.statusCode||t.statusCode;return"insufficient_funds"===e.error.type||402===n?"账户余额不足,请充值后重试":`API 错误: ${e.error.message}`}}catch{}const o=t.statusCode||t.cause?.statusCode;if(402===o)return"账户余额不足,请充值后重试";if(401===o)return"API 认证失败,请检查 API Key 配置";if(429===o)return"请求过于频繁,请稍后重试";if(503===o)return"服务暂时不可用,请稍后重试";const s=t.message||"未知错误";return s.length>200?s.slice(0,200)+"...":s}function at(e){return new it(e)}var lt=Se.module("UnifiedAdapter"),ct=class{name="unified";get supportedModels(){return _().map(e=>e.id)}protocols=new Map;constructor(e){e.arkApiKey&&(this.protocols.set("ark",Ve({apiKey:e.arkApiKey,apiUrl:e.arkApiUrl})),this.protocols.set("deepseek",Le({apiKey:e.arkApiKey,apiUrl:e.arkApiUrl}))),e.qwenApiKey&&this.protocols.set("qwen",Ye({apiKey:e.qwenApiKey,apiUrl:e.qwenApiUrl})),e.geminiApiKey&&this.protocols.set("gemini",et({apiKey:e.geminiApiKey,apiUrl:e.geminiApiUrl})),e.openrouterApiKey&&this.protocols.set("openai",ot({apiKey:e.openrouterApiKey,apiUrl:e.openrouterApiUrl})),e.vercelApiKey&&this.protocols.set("anthropic",at({apiKey:e.vercelApiKey}))}supportsModel(e){const t=k(e);return!!t&&this.protocols.has(t)}getModelFamilyConfig(e){return y(e)}async*streamOnce(e,t,n){const{model:o,enableThinking:s=!1,enableSearch:i=!1,signal:r}=n,a=e.map(e=>({role:e.role,content:e.content,images:e.images,toolCalls:e.toolCalls?.map(e=>({id:e.id,name:e.name,arguments:e.arguments,thoughtSignature:e.thought_signature})),toolCallId:e.toolCallId,toolName:e.toolName})),l=t;yield*this.stream(a,l,{model:o,enableThinking:s,enableSearch:i,signal:r})}async*stream(e,t,n){const{model:o,enableThinking:s=!1,enableSearch:i=!1,signal:r}=n,a=k(o),l=y(o);if(!a)return void(yield{type:"error",error:`未知模型: ${o}`});if(!l)return void(yield{type:"error",error:`模型 ${o} 缺少家族配置`});const c=this.protocols.get(a);if(!c)return void(yield{type:"error",error:`Protocol ${a} 未配置`});lt.debug("开始流式调用",{model:o,protocol:a,family:l.id,enableThinking:s,enableSearch:i});const u=c.stream(e,t,{model:o,familyConfig:l,enableThinking:s,enableSearch:i,signal:r});yield*this.transformEvents(u,l,s,i)}async*transformEvents(e,t,n,o){let s=!1;for await(const i of e)switch(i.type){case"thinking_delta":if(n&&t.supportsThinking&&i.delta){let e=i.delta;s||(e=e.replace(/^\n+/,""),e&&(s=!0)),e&&(yield{type:"thinking",thinking:e})}break;case"thinking_done":n&&t.supportsThinking&&(yield{type:"thinking_done"});break;case"text_delta":i.delta&&(yield{type:"text",text:i.delta});break;case"tool_call_done":if(i.toolCall){const e={id:i.toolCall.id||"",name:i.toolCall.name||"",arguments:i.toolCall.arguments||"{}"};i.toolCall.thoughtSignature&&(e.thought_signature=i.toolCall.thoughtSignature),yield{type:"tool_call",toolCall:e}}break;case"search_result":if(o&&i.searchResults){const e=i.searchResults.map(e=>({title:e.title,url:e.url,snippet:e.snippet}));yield{type:"search_result",searchResults:e}}break;case"done":yield{type:"done",finishReason:i.finishReason||"stop",usage:i.usage?{promptTokens:i.usage.promptTokens,completionTokens:i.usage.completionTokens,totalTokens:i.usage.totalTokens,reasoningTokens:i.usage.reasoningTokens,cachedTokens:i.usage.cachedTokens}:void 0};break;case"error":yield{type:"error",error:i.error||"未知错误"}}}};function ut(e){return new ct(e)}var pt=class{config;adapter;orchestrator;toolExecutor;abortController=null;tools=new Map;toolConfig;mcpManager=null;mcpConfigs;constructor(e,t){this.config={arkApiKey:e.arkApiKey,arkApiUrl:e.arkApiUrl||fe,qwenApiKey:e.qwenApiKey||"",qwenApiUrl:e.qwenApiUrl||"https://dashscope.aliyuncs.com/compatible-mode/v1",openrouterApiKey:e.openrouterApiKey||"",openrouterApiUrl:e.openrouterApiUrl||ye,vercelApiKey:e.vercelApiKey||"",tavilyApiKey:e.tavilyApiKey||"",geminiApiKey:e.geminiApiKey,cwd:e.cwd||process.cwd()},this.toolExecutor=t||he(this.config.cwd),this.toolConfig=e.tools,this.mcpConfigs=e.mcpServers,this.tools=new Map,this.adapter=new ct({arkApiKey:this.config.arkApiKey,arkApiUrl:this.config.arkApiUrl,qwenApiKey:this.config.qwenApiKey,qwenApiUrl:this.config.qwenApiUrl,geminiApiKey:this.config.geminiApiKey,openrouterApiKey:this.config.openrouterApiKey,openrouterApiUrl:this.config.openrouterApiUrl,vercelApiKey:this.config.vercelApiKey}),this.orchestrator=new Ue({executeTool:this.executeTool.bind(this),tools:this.tools,onToolApprovalRequest:e.onToolApprovalRequest,getAutoRunConfig:e.getAutoRunConfig})}async asyncInit(){if(this.toolConfig&&0===this.tools.size){const e=await q(this.toolConfig);for(const t of e)this.tools.set(t.name,t)}var e;if(this.config.tavilyApiKey&&!this.tools.has(Ee)&&this.tools.set(Ee,(e=this.config.tavilyApiKey,{name:Ee,description:"联网搜索工具。输入 query(搜索关键词/问题),返回搜索结果列表(title/url/snippet)。用于获取实时信息与可引用来源。",parameters:{type:"object",properties:{query:{type:"string",description:"搜索关键词或问题(必填)"},max_results:{type:"number",description:"最大返回结果数(可选,默认 5)"}},required:["query"]},execute:async(t,n)=>{const o="string"==typeof t.query?t.query:"",s="number"==typeof t.max_results&&Number.isFinite(t.max_results)?Math.max(1,Math.min(10,Math.floor(t.max_results))):5;if(!o.trim())return{query:"",results:[],error:"缺少 query"};if(!e)return{query:o,results:[],error:"缺少 Tavily API Key"};const i=await fetch("https://api.tavily.com/search",{method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({query:o,max_results:s,search_depth:"basic",include_answer:!1,include_raw_content:!1}),signal:n.signal});if(!i.ok){const e=await i.text().catch(()=>"");return{query:o,results:[],error:`Tavily /search 错误: ${i.status} ${e}`.trim()}}const r=await i.json().catch(()=>null),a=[],l=r&&"object"==typeof r&&Array.isArray(r.results)?r.results:[];for(const e of l){const t="string"==typeof e?.url?e.url:"";if(!t)continue;const n="string"==typeof e?.title?e.title:"",o="string"==typeof e?.content?e.content:"";a.push({title:n,url:t,snippet:o})}return{query:o,results:a}}})),this.mcpConfigs?.length&&!this.mcpManager){this.mcpManager=new Ae,await this.mcpManager.connectAll(this.mcpConfigs);for(const e of this.mcpManager.getAllTools())this.tools.has(e.name)||this.tools.set(e.name,e)}}getModelFamilyConfig(e){return y(e)}getModelProvider(e){return _e(e)}getModelRouteInfo(e){return{...be(e),available:this.adapter.supportsModel(e),familyConfig:y(e)}}buildSystemPrompt(e){const t=e.model||ke,n=y(t);let o="你是一个专业的 AI 助手,具备自主执行复杂任务的能力。\n\n## 工作方式\n1. **分析任务**:理解用户需求,拆解为可执行的步骤\n2. **逐步执行**:按步骤依次调用工具,检查每步结果\n3. **自我验证**:工具执行后检查结果是否符合预期\n4. **自动纠正**:发现问题时尝试替代方案,不要停下来问用户\n5. **总结汇报**:所有步骤完成后,给出简洁的结果总结\n\n## 输出规范\n- 不使用表情符号(emoji),除非用户要求\n- 使用 Markdown 格式组织内容\n- 代码块使用正确的语言标识";return e.platformPrompt&&(o+="\n\n"+e.platformPrompt),e.skillContents?.length&&(o+="\n\n【用户指令】\n"+e.skillContents.join("\n\n")),e.enableWebSearch&&n&&!v(t)&&(o+=`\n\n【联网搜索】当用户问题需要实时信息/最新事实/可引用来源时,请先调用 ${Ee} 工具获取结果,然后基于返回的 title/url/snippet 作答,并在回答中给出来源链接。`),o}getDefaultThinkingMode(){return"disabled"}createToolContext(e,t){const n=this.config.cwd,o=this.toolExecutor;return{cwd:n,exec:async(s,i)=>{const r=i?.length?`${s} ${i.join(" ")}`:s,a=await o.executeCommand(r,n,e,{onStdout:t?.onStdout,onStderr:t?.onStderr});return{stdout:a.output??"",stderr:a.error??"",exitCode:a.success?0:1}},signal:e}}async executeTool(e,t,n,o){const s=this.tools.get(e);return s?await s.execute(t,this.createToolContext(n,o)):{error:`未知工具: ${e}`}}getToolDefinitions(e,t){const n=Array.from(this.tools.values());let o=void 0!==e?n.filter(t=>e.includes(t.name)):n;if(t?.length)for(const e of t)if(!o.some(t=>t.name===e)){const t=this.tools.get(e);t&&(o=[...o,t])}return o.map(e=>({name:e.name,description:e.description,parameters:e.parameters}))}getAllTools(){return Array.from(this.tools.values()).map(e=>({name:e.name,description:e.description}))}async*chat(e,t={},n){await this.asyncInit(),this.abortController=new AbortController;const o=this.abortController.signal,s=t.model||ke;if(!this.adapter.supportsModel(s)){return void(y(s)?yield Y(`模型 ${s} 缺少 API Key 配置`,{code:"MISSING_API_KEY"}):yield Y(`未知模型: ${s}`,{code:"MODEL_NOT_SUPPORTED"}))}const i=y(s),r="enabled"===(t.thinkingMode??this.getDefaultThinkingMode())?"enabled":"disabled",a=this.buildSystemPrompt(t),l="ask"===t.mode,c=!l&&!!t.enableWebSearch,u=c&&i&&!v(s)?[Ee]:void 0,p=l?[]:this.getToolDefinitions(t.enabledTools,u),d=t.userTools||[],m=[...p,...d.map(e=>({name:e.name,description:e.description,parameters:{...e.parameters,required:e.parameters.required||[]}}))],g=d.length>0?new Set(d.map(e=>e.name)):void 0,h=!l&&"enabled"===r&&(i?.supportsThinking??!1),f={systemPrompt:a,history:t.history||[],tools:m,signal:o,images:n,clientToolNames:g};try{yield*this.orchestrator.chat(this.adapter,e,f,{model:s,enableThinking:h,enableSearch:c,autoRunConfig:t.autoRunConfig})}finally{this.abortController=null}}abort(){this.abortController&&this.abortController.abort()}setCwd(e){this.config.cwd=e}getConfig(){return{...this.config}}getSupportedModels(){return A}getMcpConnections(){return this.mcpManager?.getConnectionInfos()??[]}async destroy(){this.mcpManager&&(await this.mcpManager.disconnectAll(),this.mcpManager=null)}};export{it as AnthropicProtocol,Fe as ArkProtocol,P as CHAT_EVENT_TYPES,m as CLAUDE_FAMILY,Ue as ChatOrchestrator,c as DEEPSEEK_FAMILY,ke as DEFAULT_MODEL,l as DOUBAO_FAMILY,Se as DebugLogger,Be as DeepSeekProtocol,p as GEMINI_FAMILY,d as GPT_FAMILY,Xe as GeminiProtocol,pt as HybridAgent,A as MODELS,g as MODEL_FAMILIES,h as MODEL_REGISTRY,nt as OpenAIProtocol,u as QWEN_FAMILY,He as QwenProtocol,ct as UnifiedAdapter,ne as createAbort,at as createAnthropicProtocol,Y as createApiError,Ve as createArkProtocol,Le as createDeepSeekProtocol,he as createDefaultToolExecutor,Q as createDone,H as createError,et as createGeminiProtocol,ot as createOpenAIProtocol,je as createOrchestrator,te as createParseError,Ye as createQwenProtocol,Z as createRateLimitError,z as createSearchEnd,J as createSearchResult,W as createSearchStart,se as createStepEnd,oe as createStepStart,L as createTextDelta,U as createThinkingDelta,j as createThinkingEnd,D as createThinkingStart,ee as createTimeoutError,G as createToolCallOutput,B as createToolCallRequest,V as createToolCallResult,F as createToolCallStart,X as createToolError,ut as createUnifiedAdapter,I as getArg,we as getDefaultProvider,$ as getModelByModelId,f as getModelEntry,y as getModelFamily,k as getModelProtocol,S as getModelSearchStrategy,b as getModelsByFamily,w as getModelsByProtocol,_ as getVisibleModels,pe as isAbortEvent,ue as isErrorEvent,Te as isModelForProvider,me as isRetryableError,re as isSearchEvent,ce as isStatusEvent,de as isStepEvent,le as isTextEvent,ie as isThinkingEvent,R as isThrowableToolError,R as isToolError,ae as isToolEvent,v as modelSupportsNativeSearch,T as modelSupportsThinking,q as resolveTools,N as rethrowToolError,_e as routeModelToProvider,be as routeModelWithDetails,M as throwToolError,K as tool,O as tools};
1
+ import{Client as e}from"@modelcontextprotocol/sdk/client/index.js";import{StdioClientTransport as t}from"@modelcontextprotocol/sdk/client/stdio.js";import{SSEClientTransport as n}from"@modelcontextprotocol/sdk/client/sse.js";import{appendFileSync as o}from"fs";import{createGateway as s,streamText as i,tool as r}from"ai";import{z as a}from"zod";var l={id:"doubao",displayName:"豆包",supportsVision:!0,supportsThinking:!0,thinkingFormat:"reasoning",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"responses",defaultMaxTokens:16384},c={id:"deepseek",displayName:"DeepSeek",supportsVision:!1,supportsThinking:!0,thinkingFormat:"reasoning",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"responses",defaultMaxTokens:32768},u={id:"qwen",displayName:"通义千问",supportsVision:!1,supportsThinking:!0,thinkingFormat:"thinking_enabled",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"openai",defaultMaxTokens:32768},p={id:"gemini",displayName:"Gemini",supportsVision:!0,supportsThinking:!0,thinkingFormat:"thought_signature",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"gemini",defaultMaxTokens:65536,requiresSpecialHandling:["thought_signature"]},d={id:"gpt",displayName:"GPT",supportsVision:!0,supportsThinking:!0,thinkingFormat:"reasoning",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"openai",defaultMaxTokens:128e3},m={id:"claude",displayName:"Claude",supportsVision:!0,supportsThinking:!0,thinkingFormat:"reasoning",supportsNativeSearch:!1,searchStrategy:"tavily",toolCallFormat:"openai",defaultMaxTokens:64e3},g={doubao:l,deepseek:c,qwen:u,gemini:p,gpt:d,claude:m},h=[{id:"doubao-seed-1-6-250615",displayName:"豆包 Seed 1.6",family:"doubao",protocol:"ark",visible:!0,supportsVision:!0,contextWindow:"256K",contextWindowTokens:256e3,pricing:["输入 0.8 元/百万tokens","输出 2-8 元/百万tokens"]},{id:"doubao-seed-1-8-251215",displayName:"豆包 Seed 1.8",family:"doubao",protocol:"ark",contextWindow:"256K",contextWindowTokens:256e3,pricing:["输入 0.8 元/百万tokens","输出 2-8 元/百万tokens"]},{id:"deepseek-v3-2-251201",displayName:"DeepSeek V3.2",family:"deepseek",protocol:"deepseek",visible:!0,supportsVision:!1,contextWindow:"128K",contextWindowTokens:128e3,pricing:["输入 2 元/百万tokens","输出 3 元/百万tokens"]},{id:"qwen3-vl-plus",displayName:"通义千问 3 VL",family:"qwen",protocol:"qwen",visible:!0,supportsVision:!0,contextWindow:"262K",contextWindowTokens:262144,pricing:["输入 1 元/百万tokens","输出 10 元/百万tokens"]},{id:"qwen3.5-plus",displayName:"通义千问 3.5 Plus",family:"qwen",protocol:"qwen",contextWindow:"1M",contextWindowTokens:1e6,pricing:["输入 0.8 元/百万tokens","输出 4.8 元/百万tokens"]},{id:"qwen-long",displayName:"通义千问 Long",family:"qwen",protocol:"qwen",contextWindow:"10M",contextWindowTokens:1e7,pricing:["输入 0.5 元/百万tokens","输出 2 元/百万tokens"]},{id:"gemini-3-pro-preview",displayName:"Gemini 3 Pro",family:"gemini",protocol:"gemini",visible:!0,supportsVision:!0,contextWindow:"1M",contextWindowTokens:1e6,pricing:["输入 1.25 元/百万tokens","输出 10 元/百万tokens"]},{id:"gemini-2.5-flash-preview-05-20",displayName:"Gemini 2.5 Flash",family:"gemini",protocol:"gemini",contextWindow:"1M",contextWindowTokens:1e6,pricing:["输入 0.15 元/百万tokens","输出 0.6 元/百万tokens"]},{id:"gemini-2.5-pro-preview-05-06",displayName:"Gemini 2.5 Pro",family:"gemini",protocol:"gemini",contextWindow:"1M",contextWindowTokens:1e6,pricing:["输入 1.25 元/百万tokens","输出 10 元/百万tokens"]},{id:"openai/gpt-5.2",displayName:"GPT-5.2",family:"gpt",protocol:"openai",visible:!0,supportsVision:!0,contextWindow:"400K",contextWindowTokens:4e5,pricing:["输入 12.6 元/百万tokens","输出 100.8 元/百万tokens"]},{id:"anthropic/claude-opus-4.5",displayName:"Claude Opus 4.5",family:"claude",protocol:"anthropic",visible:!0,supportsVision:!0,contextWindow:"200K",contextWindowTokens:2e5,pricing:["输入 36 元/百万tokens","输出 180 元/百万tokens"]}];function f(e){return h.find(t=>t.id===e||e.includes(t.id))}function y(e){const t=f(e);if(t)return g[t.family]}function k(e){const t=f(e);return t?.protocol}function _(){return h.filter(e=>e.visible)}function b(e){return h.filter(t=>t.family===e)}function w(e){return h.filter(t=>t.protocol===e)}function T(e){const t=y(e);return t?.supportsThinking??!1}function v(e){const t=y(e);return t?.supportsNativeSearch??!1}function C(e){const t=f(e);if(!t)return!1;if("boolean"==typeof t.supportsVision)return t.supportsVision;const n=y(e);return n?.supportsVision??!1}function x(e){const t=y(e);return t?.searchStrategy??"tavily"}function S(e){const t=y(e.id),n=C(e.id),o=t?.supportsThinking??!1,s=t?.supportsNativeSearch??!1,i=[];return n&&i.push("多模态"),o&&i.push("深度思考"),e.contextWindow&&i.push(`长上下文(${e.contextWindow})`),s&&i.push("联网搜索"),i}var A=_().map(e=>{const t=y(e.id),n=t?.supportsThinking??!1,o=C(e.id);return{modelId:e.id,displayName:e.displayName,supportsThinking:n,supportsVision:o,tooltip:{features:S(e),cost:e.pricing}}});function $(e){return A.find(t=>t.modelId===e)}function R(e){return e instanceof Error&&"object"==typeof e.toolError&&null!==e.toolError&&"string"==typeof e.toolError.message}function M(e,t,n){const o={message:e,code:t,...n},s=new Error(e);throw Object.defineProperty(s,"toolError",{value:o,enumerable:!0}),s}function N(e,t,n){if(R(e))throw e;M(e instanceof Error?e.message:String(e),t,n)}function I(e,t){return e[t]}function K(e){return{tools:[e]}}function q(e){return{tools:e}}async function O(e){const t=[];for(const n of e){const e=await n;"tools"in e&&Array.isArray(e.tools)?t.push(...e.tools):"name"in e&&"execute"in e&&t.push(e)}return t}function E(e){return{type:"agent_status",data:{phase:e}}}var P=["thinking_start","thinking_delta","thinking_end","search_start","search_result","search_end","tool_call_start","tool_call_result","tool_call_output","tool_approval_request","tool_call_request","text_delta","done","error","abort","step_start","step_end","compact_start","compact_end","agent_status"];function D(){return{type:"thinking_start",data:{startedAt:Date.now()}}}function U(e){return{type:"thinking_delta",data:{content:e}}}function W(e){const t=Date.now();return{type:"thinking_end",data:{endedAt:t,duration:t-e}}}function j(e){return{type:"search_start",data:{query:e,startedAt:Date.now()}}}function J(e,t){const n=Date.now();return{type:"search_result",data:{results:e,endedAt:n,duration:n-t}}}function z(e,t,n){const o=Date.now();return{type:"search_end",data:{success:e,error:n,endedAt:o,duration:o-t}}}function F(e,t,n){return{type:"tool_call_start",data:{id:e,name:t,args:n,startedAt:Date.now()}}}function V(e,t,n,o,s,i,r){const a=Date.now();return{type:"tool_call_result",data:{id:e,name:t,result:n,success:o,error:i,endedAt:a,duration:a-s,ui:r}}}function G(e,t,n,o){return{type:"tool_call_output",data:{id:e,name:t,stream:n,chunk:o,at:Date.now()}}}function L(e,t,n){return{type:"tool_call_request",data:{id:e,name:t,args:n,requestedAt:Date.now()}}}function B(e){return{type:"text_delta",data:{content:e}}}function Q(e,t,n){return{type:"done",data:{text:e,usage:t,duration:n}}}function H(e){return{type:"error",data:e}}function Y(e,t={}){return H({category:"api",message:e,...t})}function Z(e,t,n){return H({category:"rate_limit",message:e,code:"RATE_LIMIT",statusCode:429,retryable:!0,retryAfter:t,context:n})}function X(e,t,n){return H({category:"tool",message:e,code:"TOOL_ERROR",context:t,cause:n,retryable:!1})}function ee(e,t){return H({category:"timeout",message:e,code:"TIMEOUT",retryable:!0,context:t})}function te(e,t){return H({category:"parse",message:e,code:"PARSE_ERROR",cause:t,retryable:!1})}function ne(e){return{type:"abort",data:{reason:e,abortedAt:Date.now()}}}function oe(e,t){return{type:"step_start",data:{stepNumber:e,description:t,startedAt:Date.now()}}}function se(e,t){const n=Date.now();return{type:"step_end",data:{stepNumber:e,endedAt:n,duration:n-t}}}function ie(e){return e.type.startsWith("thinking_")}function re(e){return e.type.startsWith("search_")}function ae(e){return e.type.startsWith("tool_")}function le(e){return"text_delta"===e.type}function ce(e){return"done"===e.type||"error"===e.type||"abort"===e.type}function ue(e){return"error"===e.type}function pe(e){return"abort"===e.type}function de(e){return e.type.startsWith("step_")}function me(e){return"error"===e.type&&!0===e.data.retryable}var ge=["rm -rf /","rm -rf ~","format","mkfs","dd if=","shutdown","reboot","sudo rm","sudo format"];function he(e=process.cwd()){return{async executeCommand(t,n,o,s){if(o?.aborted)return{success:!1,error:"操作已取消"};if(function(e){const t=e.toLowerCase().trim();return ge.some(e=>t.includes(e.toLowerCase()))}(t))return{success:!1,error:"该命令被安全策略阻止"};try{const{spawn:i}=await import("child_process");return new Promise(r=>{let a="",l="",c=!1,u=null;const p=i("sh",["-c",t],{cwd:n||e,env:process.env,detached:"win32"!==process.platform}),d=e=>{if(!c){c=!0;try{"win32"!==process.platform&&"number"==typeof p.pid?process.kill(-p.pid,e):p.kill(e)}catch{try{p.kill(e)}catch{}}u&&clearTimeout(u),u=setTimeout(()=>{try{"win32"!==process.platform&&"number"==typeof p.pid?process.kill(-p.pid,"SIGKILL"):p.kill("SIGKILL")}catch{}},1500)}},m=setTimeout(()=>{c||(d("SIGTERM"),r({success:!1,error:"命令执行超时(30秒)"}))},3e4),g=()=>{c||(d("SIGTERM"),clearTimeout(m),r({success:!1,error:"操作已取消"}))};o?.addEventListener("abort",g),p.stdout?.on("data",e=>{const t=e.toString();a+=t,s?.onStdout?.(t)}),p.stderr?.on("data",e=>{const t=e.toString();l+=t,s?.onStderr?.(t)}),p.on("close",e=>{if(clearTimeout(m),o?.removeEventListener("abort",g),u&&(clearTimeout(u),u=null),c)return;const t=a.trim(),n=l.trim();if(0===e)r({success:!0,output:t||n||"执行成功"});else if(t){r({success:!0,output:t+(n?`\n[警告: ${n}]`:"")})}else r(n?{success:!1,error:n}:{success:!1,error:`命令退出码: ${e}`})}),p.on("error",e=>{clearTimeout(m),o?.removeEventListener("abort",g),u&&(clearTimeout(u),u=null),c||r({success:!1,error:e.message})})})}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}}}var fe="https://ark.cn-beijing.volces.com/api/v3",ye="https://openrouter.ai/api/v1",ke="doubao-seed-1-6-250615";function _e(e){return be(e).provider}function be(e){const t=f(e);return t?{provider:t.protocol,registryEntry:t,familyConfig:y(e),isDefault:!1}:{provider:"ark",isDefault:!0}}function we(){return"ark"}function Te(e,t){return _e(e)===t}var ve=!1,Ce=null,xe=class e{prefix;constructor(e){this.prefix=e}static enable(e){ve=e}static isEnabled(){return ve}static setLogFile(e){Ce=e}static module(t){return new e(`[${t}]`)}debug(...e){ve&&this.writeToFile("debug",e)}info(...e){ve&&this.writeToFile("info",e)}warn(...e){ve&&this.writeToFile("warn",e)}error(...e){ve&&this.writeToFile("error",e)}writeToFile(e,t){if(Ce)try{const n=JSON.stringify({t:Date.now(),level:e,module:this.prefix,args:t.map(e=>{try{return"string"==typeof e?e:JSON.parse(JSON.stringify(e))}catch{return String(e)}})});o(Ce,n+"\n")}catch{}}},Se=xe.module("MCP"),Ae=class{connections=new Map;async connectAll(e){const t=await Promise.allSettled(e.map(e=>this.connect(e)));for(let n=0;n<t.length;n++){const o=t[n],s=e[n].name;"rejected"===o.status&&Se.error(`[${s}] 连接失败:`,o.reason)}}async connect(o){const{name:s}=o;this.connections.has(s)&&await this.disconnect(s),Se.info(`[${s}] 正在连接...`);const i=new e({name:"ai-chat-mcp-client",version:"1.0.0"});let r;if("stdio"===o.transport){if(!o.command)throw new Error(`[${s}] stdio 模式必须指定 command`);r=new t({command:o.command,args:o.args,env:o.env,cwd:o.cwd})}else{if("sse"!==o.transport)throw new Error(`[${s}] 不支持的传输方式: ${o.transport}`);if(!o.url)throw new Error(`[${s}] sse 模式必须指定 url`);r=new n(new URL(o.url))}const a={config:o,client:i,transport:r,status:"connecting",tools:[]};this.connections.set(s,a);try{await i.connect(r),a.status="connected",Se.info(`[${s}] 已连接`);const e=await this.discoverTools(a);a.tools=e,Se.info(`[${s}] 发现 ${e.length} 个工具:`,e.map(e=>e.name))}catch(e){throw a.status="error",a.error=e instanceof Error?e.message:String(e),Se.error(`[${s}] 连接失败:`,a.error),e}}async discoverTools(e){const{client:t,config:n}=e,{tools:o}=await t.listTools();return o.map(e=>this.adaptTool(e,n.name,t))}adaptTool(e,t,n){const o=this.convertSchema(e.inputSchema);return{name:e.name,description:e.description||`MCP tool from ${t}`,parameters:o,execute:async t=>{const o=await n.callTool({name:e.name,arguments:t}),s=[];if(Array.isArray(o.content))for(const e of o.content)if("object"==typeof e&&null!==e){const t=e;"text"===t.type&&"string"==typeof t.text?s.push(t.text):"image"===t.type?s.push(`[image: ${t.mimeType||"unknown"}]`):"resource"===t.type&&s.push(JSON.stringify(t))}return{text:s.join("\n")||JSON.stringify(o.content)}}}}convertSchema(e){const t={},n=[],o=e.properties;if(o)for(const[e,n]of Object.entries(o))t[e]=this.convertProperty(n);return Array.isArray(e.required)&&n.push(...e.required.filter(e=>"string"==typeof e)),{type:"object",properties:t,required:n.length>0?n:void 0}}convertProperty(e){const t={type:"string"==typeof e.type?e.type:"string"};if("string"==typeof e.description&&(t.description=e.description),Array.isArray(e.enum)&&(t.enum=e.enum),e.items&&"object"==typeof e.items&&(t.items=this.convertProperty(e.items)),e.properties&&"object"==typeof e.properties){t.properties={};for(const[n,o]of Object.entries(e.properties))t.properties[n]=this.convertProperty(o)}return Array.isArray(e.required)&&(t.required=e.required.filter(e=>"string"==typeof e)),t}getAllTools(){const e=[];for(const t of this.connections.values())"connected"===t.status&&e.push(...t.tools);return e}getConnectionInfos(){return Array.from(this.connections.values()).map(e=>({name:e.config.name,status:e.status,toolCount:e.tools.length,error:e.error}))}async disconnect(e){const t=this.connections.get(e);if(t)try{await t.client.close(),Se.info(`[${e}] 已断开`)}catch(t){Se.error(`[${e}] 断开失败:`,t)}finally{t.status="disconnected",t.tools=[],this.connections.delete(e)}}async disconnectAll(){const e=Array.from(this.connections.keys());await Promise.allSettled(e.map(e=>this.disconnect(e)))}},$e=xe.module("ContextCompressor");function Re(e){return e?Math.ceil(e.length/3.2):0}function Me(e){let t=4;if(t+=Re(e.content),e.toolCalls)for(const n of e.toolCalls)t+=Re(n.name),t+=Re(n.arguments),t+=10;return e.images&&(t+=85*e.images.length),t}function Ne(e){let t=3;for(const n of e)t+=Me(n);return t}function Ie(e){const t=e.compactThresholdRatio??.8;return Math.floor(e.contextWindowTokens*t)-e.maxOutputTokens}var Ke='你是一个对话历史压缩助手。请总结以下对话历史,保留所有关键信息:\n\n要求:\n1. 保留所有文件修改记录(哪些文件被创建/修改/删除了,具体改了什么)\n2. 保留所有关键决策和结论\n3. 保留错误信息和解决方案\n4. 保留用户的明确要求和偏好\n5. 用简洁的条目列表格式输出\n6. 不要遗漏任何可能影响后续工作的信息\n\n直接输出摘要,不要开头说"以下是摘要"之类的话。';function qe(e){const t=[];for(const n of e){const e="assistant"===n.role?"AI":"user"===n.role?"用户":"工具";if("assistant"===n.role&&n.toolCalls&&n.toolCalls.length>0){const o=n.toolCalls.map(e=>{const t=e.arguments.length>200?e.arguments.slice(0,200)+"...":e.arguments;return` 调用 ${e.name}(${t})`}).join("\n"),s=n.content?`${n.content}\n${o}`:o;t.push(`[${e}]\n${s}`)}else if("tool"===n.role){const o=n.content.length>1e3?n.content.slice(0,1e3)+`... (共 ${n.content.length} 字符)`:n.content;t.push(`[${e}: ${n.toolName??"unknown"}]\n${o}`)}else n.content&&t.push(`[${e}]\n${n.content}`)}return t.join("\n\n---\n\n")}var Oe=xe.module("ContextSummarizer");async function Ee(e,t,n){const{summarizeMessages:o,keepMessages:s}=function(e,t){const n=t.keepRecentMessages??6;let o=0;"system"===e[0]?.role&&(o=1);let s=o;for(let t=o;t<e.length;t++)if("user"===e[t].role){s=t+1;break}const i=Math.max(s,e.length-n),r=e.slice(i),a=e.slice(s,i);if(a.length<2)return{summarizeMessages:[],keepMessages:e.slice(o)};const l=Ne(e),c=Ie(t);return $e.info(`准备 AI 总结: ~${l} tokens > budget ${c}, 总结 ${a.length} 条中间消息, 保留最近 ${r.length} 条`),{summarizeMessages:[{role:"system",content:Ke},{role:"user",content:qe(a)}],keepMessages:r}}(t,n);if(0===o.length)return Oe.info("中间历史太短,跳过 AI 总结"),{messages:t,success:!0};const i=o[0].content,r=o[1].content;Oe.info(`开始 AI 总结: ~${Ne(o)} tokens, ${t.length} 条消息`);try{const n=await e(i,r);if(!n.trim())return Oe.warn("AI 总结返回空内容"),{messages:t,success:!1};const o=function(e,t,n){const o="system"===e[0]?.role?e[0]:null;let s=null;for(let t=o?1:0;t<e.length;t++)if("user"===e[t].role){s=e[t];break}const i=[];o&&i.push(o),s&&i.push(s),i.push({role:"system",content:`[对话历史摘要]\n${t}`}),i.push(...n);const r=Ne(i);return $e.info(`AI 总结应用完成: ${e.length} → ${i.length} 条消息, ~${r} tokens`),i}(t,n,s);return Oe.info(`AI 总结完成: ${t.length} → ${o.length} 条消息, ~${Ne(o)} tokens`),{messages:o,success:!0}}catch(e){return Oe.error("AI 总结异常:",e),{messages:t,success:!1}}}var Pe="web_search_ai";var De=xe.module("Orchestrator");function Ue(e){const t=new Map;for(const n of e){const e=String(n?.url??"").trim();if(!e)continue;const o=String(n?.snippet??"").trim();let s=String(n?.title??"").trim();if(!s)try{s=new URL(e).hostname}catch{s=e}const i=t.get(e);i?(!i.snippet&&o&&(i.snippet=o),!i.title&&s&&(i.title=s)):t.set(e,{title:s,url:e,snippet:o})}return Array.from(t.values())}var We=class{config;constructor(e){this.config={maxIterations:25,...e}}async*chat(e,t,n,o){const s=Date.now(),i=this.config.maxIterations??25;let r=this.buildMessages(n,t);const{contextWindowTokens:a,maxOutputTokens:l}=function(e){const t=f(e);if(!t)throw new Error(`模型 ${e} 未在 MODEL_REGISTRY 中注册`);const n=g[t.family];if(!n)throw new Error(`模型 ${e} 的家族 ${t.family} 未定义`);if(!t.contextWindowTokens)throw new Error(`模型 ${e} 缺少 contextWindowTokens 配置`);if(!n.defaultMaxTokens)throw new Error(`模型家族 ${t.family} 缺少 defaultMaxTokens 配置`);return{contextWindowTokens:t.contextWindowTokens,maxOutputTokens:n.defaultMaxTokens}}(o.model),c={contextWindowTokens:a,maxOutputTokens:l};{const e=this.compactIfNeeded(r,c);let t=await e.next();for(;!t.done;)yield t.value,t=await e.next();r=t.value}let u=0,p="",d=[],m=0,h=!1,y=!1,k="",_=0,b={promptTokens:0,completionTokens:0,totalTokens:0,reasoningTokens:0,cachedTokens:0},w=!1;for(;u<i;){if(n.signal.aborted)return void(yield ne("请求已取消"));if(u++,u>1){const e=this.compactIfNeeded(r,c);let t=await e.next();for(;!t.done;)yield t.value,t=await e.next();r=t.value}const i=Date.now();De.info(`======= 第 ${u} 轮开始 =======`),yield oe(u),yield E("thinking");let a="",l=0,g=!1,f=!1;const T={};let v=!1;const C=e=>{T[e]=(T[e]||0)+1};try{const c=[];let x=!1;const S=!0===o.enableThinking,A=!0===o.enableSearch;De.debug("调用 adapter.streamOnce",{enableThinking:S,enableSearch:A});const $=e.streamOnce(r,n.tools,{model:o.model,enableThinking:S,enableSearch:A,signal:n.signal});for await(const e of $)switch(C(e.type),e.type){case"text":e.text&&(v||(v=!0,De.debug("首次收到 text",{thinkingStarted:g,thinkingComplete:f}),yield E(null)),S&&g&&!f&&(De.debug("text 触发 thinking_end"),f=!0,yield W(l)),p+=e.text,yield B(e.text));break;case"thinking":if(!S)break;if(e.thinking)if(f)De.warn("⚠️ thinkingComplete=true 但收到 thinking",e.thinking.slice(0,30)),De.warn("当前状态",{textStarted:v,chunkCounts:T});else if(v)De.warn("⚠️ text 开始后收到 thinking",e.thinking.slice(0,30));else{let t=e.thinking;if(!g&&(t=t.replace(/^(?:\r?\n)+/,""),!t))break;g||(g=!0,l=Date.now(),De.debug("发送 thinking_start"),yield E(null),yield D()),a+=t,yield U(t)}break;case"thinking_done":if(!S)break;De.info("收到 thinking_done",{thinkingStarted:g,thinkingComplete:f}),g&&!f?(f=!0,De.debug("发送 thinking_end"),yield W(l)):g||De.warn("⚠️ 收到 thinking_done 但 thinkingStarted=false");break;case"tool_call":if(e.toolCall){if(!n.tools||0===n.tools.length){De.warn("收到 tool_call 但当前未注入工具,已忽略",{toolName:e.toolCall.name});break}c.push(e.toolCall),x=!0}break;case"search_result":if(!A)break;e.searchResults&&(h||(h=!0,m=Date.now(),yield E(null),yield j(t)),d=Ue(e.searchResults),yield J(d,m));break;case"done":De.info("收到 done",{finishReason:e.finishReason,usage:e.usage}),De.info(`第 ${u} 轮 chunk 统计`,T),"tool_calls"===e.finishReason&&(x=!0),e.usage&&(w=!0,b.promptTokens+=e.usage.promptTokens||0,b.completionTokens+=e.usage.completionTokens||0,b.totalTokens+=e.usage.totalTokens||0,b.reasoningTokens+=e.usage.reasoningTokens||0,b.cachedTokens+=e.usage.cachedTokens||0);break;case"error":return De.error("收到 error",e.error),void(yield Y(e.error??"未知错误"))}if(De.info(`第 ${u} 轮 for-await 循环结束`),De.debug("状态",{thinkingStarted:g,thinkingComplete:f}),S&&g&&!f&&(De.debug("补发 thinking_end"),f=!0,yield W(l)),x&&c.length>0){const e=c.map(e=>`${e.name}:${e.arguments}`).sort().join("|");if(e===k?_++:(_=0,k=e),_>=2){De.warn("检测到重复工具调用,注入终止提示",{signature:e.slice(0,200),count:_+1});c.map(e=>e.name).join(", ");r.push({role:"assistant",content:p,toolCalls:c});for(const e of c)r.push({role:"tool",content:`[系统提示] 你已经连续 ${_+1} 次使用相同参数调用 ${e.name},任务应已完成。请直接回复用户执行结果,不要再调用工具。`,toolCallId:e.id,toolName:e.name});yield se(u,i),p="";continue}const a=n.clientToolNames||this.config.clientToolNames,l=a?c.filter(e=>a.has(e.name)):[];if(l.length>0){De.info("检测到客户端工具调用,透传给客户端",l.map(e=>e.name));for(const e of l){let t;try{t=JSON.parse(e.arguments||"{}")}catch{t={}}yield L(e.id,e.name,t)}const e=Date.now()-s;return void(yield Q(p,void 0,e))}yield E(null);const g={role:"assistant",content:p,toolCalls:c};r.push(g);for(const e of c){const s=Date.now();let i;try{i=JSON.parse(e.arguments||"{}")}catch{r.push({role:"tool",content:"参数解析错误",toolCallId:e.id});continue}if(e.name===Pe){("string"==typeof i.query?i.query:"").trim()||(i.query=t)}const a=this.config.getAutoRunConfig?await this.config.getAutoRunConfig():o.autoRunConfig||this.config.autoRunConfig,l=this.config.tools?.get(e.name),c="manual"===a?.mode||!0===l?.requiresApproval;if(De.debug("检查工具批准",{toolName:e.name,autoRunConfigMode:a?.mode,requiresApproval:l?.requiresApproval,hasCallback:!!this.config.onToolApprovalRequest}),c&&this.config.onToolApprovalRequest){De.info("发送工具批准请求",e.name);const n={type:"tool_approval_request",data:{id:e.id,name:e.name,args:i,requestedAt:Date.now()}};yield n;if(!await this.config.onToolApprovalRequest({id:e.id,name:e.name,args:i})){const n=JSON.stringify({skipped:!0,message:"用户跳过了此工具"});if(e.name===Pe&&A){if(!h){h=!0,m=Date.now();const e="string"==typeof i.query?i.query:t;yield j(e)}y=!0,yield z(!1,m,`用户跳过了 ${Pe}`)}else yield V(e.id,e.name,n,!1,s);r.push({role:"tool",content:n,toolCallId:e.id,toolName:e.name});continue}}const u=e.name===Pe;if(u){if(A&&!h){h=!0,m=Date.now();const e="string"==typeof i.query?i.query:t;yield j(e)}}else yield F(e.id,e.name,i);const p=this.config.tools?.get(e.name);let g,f,k,_=n.signal;if(p?.timeout){const e=new AbortController;g=setTimeout(()=>e.abort(),p.timeout),n.signal.addEventListener("abort",()=>e.abort(),{once:!0}),_=e.signal}let b=!0;try{const t=[];let n=null;const o=()=>n?.(),s=e=>{t.push(e),o()};let r,a,l=!1;const c={toolCallId:e.id,toolName:e.name,onStdout:t=>{t&&s(G(e.id,e.name,"stdout",t))},onStderr:t=>{t&&s(G(e.id,e.name,"stderr",t))}};for(this.config.executeTool(e.name,i,_,c).then(e=>{r=e,l=!0,o()}).catch(e=>{a=e,l=!0,o()});!l||t.length>0;){for(;t.length>0;){const e=t.shift();e&&(yield e)}if(l)break;await new Promise(e=>n=e),n=null}if(a)throw a;f=JSON.stringify(r??{})}catch(e){if(b=!1,R(e))k=e.toolError,f=JSON.stringify({error:e.toolError.message});else{const t=e instanceof Error?e.message:String(e);k={message:t},f=JSON.stringify({error:t})}}void 0!==g&&clearTimeout(g);const w=this.config.tools?.get(e.name),T=b?w?.ui:void 0;if(u){if(A){let e,t=[];try{const n=JSON.parse(f||"{}");t=(Array.isArray(n?.results)?n.results:[]).map(e=>({title:"string"==typeof e?.title?e.title:"",url:"string"==typeof e?.url?e.url:"",snippet:"string"==typeof e?.snippet?e.snippet:""})).filter(e=>!!e.url),"string"==typeof n?.error&&n.error&&(e=n.error,b=!1)}catch{e=`${Pe} 返回结果解析失败`,b=!1}t.length>0&&(d=Ue(t),yield J(d,m)),y=!0,yield z(b,m,e)}}else yield V(e.id,e.name,f,b,s,k,T);if(r.push({role:"tool",content:f,toolCallId:e.id,toolName:e.name}),n.signal.aborted)return void(yield ne("请求已取消"))}yield se(u,i),p="";continue}yield se(u,i);break}catch(e){return yield se(u,i),void(n.signal.aborted?yield ne("请求已取消"):yield Y(e instanceof Error?e.message:String(e)))}}u>=i&&De.warn(`达到最大迭代次数 ${i},强制结束工具调用循环`),h&&!y&&(yield z(!0,m));const T=Date.now()-s,v=w?{promptTokens:b.promptTokens,completionTokens:b.completionTokens,totalTokens:b.totalTokens,...b.reasoningTokens>0?{reasoningTokens:b.reasoningTokens}:{},...b.cachedTokens>0?{cachedTokens:b.cachedTokens}:{}}:void 0;yield Q(p,v,T)}buildMessages(e,t){const n=[];e.systemPrompt&&n.push({role:"system",content:e.systemPrompt});for(const t of e.history){const e={role:t.role,content:t.content};t.tool_calls&&(e.toolCalls=t.tool_calls.map(e=>({id:e.id,name:e.function.name,arguments:e.function.arguments,thought_signature:e.thought_signature}))),"tool"===t.role&&t.tool_call_id&&(e.toolCallId=t.tool_call_id),n.push(e)}return t&&n.push({role:"user",content:t,images:e.images}),n}async*compactIfNeeded(e,t){if(!function(e,t){return Ne(e)>Ie(t)}(e,t))return e;const n=this.config.summarize;if(!n)return De.warn("上下文超限但未配置 summarize 回调,跳过压缩"),e;const o=Date.now(),s=Ne(e),i=Ie(t),r=e.length;yield function(e,t){return{type:"compact_start",data:{estimatedTokens:e,budget:t,startedAt:Date.now()}}}(s,i);const{messages:a,success:l}=await Ee(n,e,t);return yield function(e,t,n,o,s){const i=Date.now();return{type:"compact_end",data:{success:e,compressedTokens:t,originalMessageCount:n,compressedMessageCount:o,endedAt:i,duration:i-s}}}(l,Ne(a),r,a.length,o),a}};function je(e){return new We(e)}var Je={400:"请求参数错误",401:"API 认证失败,请检查 API Key 配置",402:"账户余额不足,请充值后重试",403:"没有权限访问此模型",404:"请求的模型或接口不存在",429:"请求过于频繁,请稍后重试",500:"API 服务器内部错误,请稍后重试",502:"API 网关错误,请稍后重试",503:"API 服务暂时不可用,请稍后重试",504:"API 请求超时,请稍后重试"};function ze(e,t,n){const o=function(e){try{const t=JSON.parse(e);if(t?.error?.message)return{message:t.error.message,type:t.error.type};if("string"==typeof t?.error_msg)return{message:t.error_msg};if("string"==typeof t?.message)return{message:t.message}}catch{}return null}(t),s=o?.message,i=Je[e];if(i)return s&&s.length<=100?`${i}(${s})`:i;if(s){return`${n} 错误 (${e}): ${s.length>200?s.slice(0,200)+"...":s}`}return`${n} 错误 (${e})`}var Fe=xe.module("ArkProtocol"),Ve=class{name="ark";apiKey;apiUrl;constructor(e){this.apiKey=e.apiKey,this.apiUrl=e.apiUrl??fe}async*stream(e,t,n){const o=this.buildRequestBody(e,t,n);Fe.debug("发送 ARK 请求",{url:`${this.apiUrl}/responses`,model:n.model,enableSearch:n.enableSearch,enableThinking:n.enableThinking,toolsCount:t.length});const s=await fetch(`${this.apiUrl}/responses`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify(o),signal:n.signal});if(!s.ok){const e=await s.text();return Fe.error("ARK API 错误",{status:s.status,body:e.slice(0,500)}),void(yield{type:"error",error:ze(s.status,e,"ARK")})}const i=s.body?.getReader();i?yield*this.parseSSE(i):yield{type:"error",error:"无法获取响应流"}}buildRequestBody(e,t,n){const o=this.convertMessages(e),s={model:n.model,stream:!0,max_output_tokens:n.familyConfig.defaultMaxTokens??16384,input:o},i=[],r=t.some(e=>e.name===Pe);n.enableSearch&&!r&&i.push({type:"web_search",max_keyword:5,limit:20});for(const e of t)i.push({type:"function",name:e.name,description:e.description,parameters:e.parameters});return i.length>0&&(s.tools=i),n.enableThinking&&(s.thinking={type:"enabled"}),s}convertMessages(e){const t=[];for(const n of e)switch(n.role){case"system":t.push({role:"system",content:n.content});break;case"user":{const e=[{type:"input_text",text:n.content||(n.images?.length?"请分析这张图片":"")}];if(n.images?.length)for(const t of n.images)e.push({type:"input_image",image_url:t.startsWith("data:")?t:`data:image/jpeg;base64,${t}`});t.push({role:"user",content:e});break}case"assistant":if(n.toolCalls?.length){n.content&&t.push({type:"message",role:"assistant",content:[{type:"output_text",text:n.content}]});for(const e of n.toolCalls)t.push({type:"function_call",call_id:e.id,name:e.name,arguments:e.arguments})}else t.push({role:"developer",content:`[上一轮AI回复]: ${n.content}`});break;case"tool":t.push({type:"function_call_output",call_id:n.toolCallId,output:n.content})}return t}async*parseSSE(e){const t=new TextDecoder;let n="";const o=new Map;let s=null;const i=[];let r,a=!1,l=!1,c=!1;for(;;){const{done:u,value:p}=await e.read();if(u)break;n+=t.decode(p,{stream:!0});const d=n.split("\n");n=d.pop()||"";for(const e of d){if(a)continue;if(!e.startsWith("data:"))continue;const t=e.slice(5).trim();if("[DONE]"===t){if(a=!0,o.size>0){for(const e of o.values())yield{type:"tool_call_done",toolCall:e};yield{type:"done",finishReason:"tool_calls",usage:r}}else yield{type:"done",finishReason:"stop",usage:r};return}try{const e=JSON.parse(t),n=e.response?.usage||e.usage;switch(n&&(r={promptTokens:n.input_tokens||n.prompt_tokens||0,completionTokens:n.output_tokens||n.completion_tokens||0,totalTokens:(n.input_tokens||n.prompt_tokens||0)+(n.output_tokens||n.completion_tokens||0),reasoningTokens:n.output_tokens_details?.reasoning_tokens||0,cachedTokens:n.input_tokens_details?.cached_tokens||0}),e.type){case"response.output_item.added":{const t=e.item;"function_call"===t?.type&&t.call_id&&(s=t.call_id,o.set(t.call_id,{id:t.call_id,name:t.name||"",arguments:t.arguments||""}),yield{type:"tool_call_start",toolCall:{id:t.call_id,name:t.name||""}});break}case"response.function_call_arguments.delta":if(s){const t=o.get(s);t&&(t.arguments+=e.delta||"",yield{type:"tool_call_delta",toolCall:{id:s,arguments:e.delta||""}})}break;case"response.function_call_arguments.done":case"response.output_item.done":{const t=e.item;if("function_call"===t?.type&&t.call_id){const e=o.get(t.call_id);o.set(t.call_id,{id:t.call_id,name:t.name||e?.name||"",arguments:t.arguments||e?.arguments||"{}"})}break}case"response.output_text.annotation.added":{const t=e.annotation;if(t?.url){i.some(e=>e.url===t.url)||(i.push({title:t.title||t.text||"",url:t.url,snippet:t.summary||t.snippet||""}),yield{type:"search_result",searchResults:[...i]})}break}case"response.output_text.delta":e.delta&&(c||(c=!0,l||(l=!0,yield{type:"thinking_done"})),yield{type:"text_delta",delta:e.delta});break;case"response.reasoning_summary_text.delta":e.delta&&!l&&(yield{type:"thinking_delta",delta:e.delta})}}catch{}}}if(!a)if(o.size>0){for(const e of o.values())yield{type:"tool_call_done",toolCall:e};yield{type:"done",finishReason:"tool_calls",usage:r}}else yield{type:"done",finishReason:"stop",usage:r}}};function Ge(e){return new Ve(e)}var Le=xe.module("DeepSeekProtocol"),Be=class{name="deepseek";apiKey;apiUrl;constructor(e){this.apiKey=e.apiKey,this.apiUrl=e.apiUrl??fe}async*stream(e,t,n){const o=this.buildRequestBody(e,t,n),s=`${this.apiUrl}/responses`;Le.debug("发送 DeepSeek 请求",{url:s,model:n.model,enableSearch:n.enableSearch,enableThinking:n.enableThinking,toolsCount:t.length});const i=await fetch(s,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify(o),signal:n.signal});if(!i.ok){const e=await i.text();return Le.error("DeepSeek API 错误",{status:i.status,body:e.slice(0,500)}),void(yield{type:"error",error:ze(i.status,e,"DeepSeek")})}const r=i.body?.getReader();r?yield*this.parseSSE(r,n.enableThinking):yield{type:"error",error:"无法获取响应流"}}buildRequestBody(e,t,n){const o=this.convertMessages(e),s={model:n.model,stream:!0,max_output_tokens:n.familyConfig.defaultMaxTokens??32768,input:o},i=[],r=t.some(e=>e.name===Pe);n.enableSearch&&!r&&i.push({type:"web_search",max_keyword:5,limit:20});for(const e of t)i.push({type:"function",name:e.name,description:e.description,parameters:e.parameters});return i.length>0&&(s.tools=i),n.enableThinking&&(s.thinking={type:"enabled"}),s}convertMessages(e){const t=[];for(const n of e)switch(n.role){case"system":t.push({role:"system",content:n.content});break;case"user":{const e=[{type:"input_text",text:n.content||(n.images?.length?"请分析这张图片":"")}];if(n.images?.length)for(const t of n.images)e.push({type:"input_image",image_url:t.startsWith("data:")?t:`data:image/jpeg;base64,${t}`});t.push({role:"user",content:e});break}case"assistant":if(n.toolCalls?.length)for(const e of n.toolCalls)t.push({type:"function_call",call_id:e.id,name:e.name,arguments:e.arguments});else t.push({role:"developer",content:`[上一轮AI回复]: ${n.content}`});break;case"tool":t.push({type:"function_call_output",call_id:n.toolCallId,output:n.content})}return t}async*parseSSE(e,t){const n=new TextDecoder;let o="";const s=new Map;let i=null;const r=[];let a,l=!1,c=!1,u=!1;for(;;){const{done:p,value:d}=await e.read();if(p)break;o+=n.decode(d,{stream:!0});const m=o.split("\n");o=m.pop()||"";for(const e of m){if(l)continue;if(!e.startsWith("data:"))continue;const n=e.slice(5).trim();if("[DONE]"===n){if(l=!0,s.size>0){for(const e of s.values())yield{type:"tool_call_done",toolCall:e};yield{type:"done",finishReason:"tool_calls",usage:a}}else yield{type:"done",finishReason:"stop",usage:a};return}try{const e=JSON.parse(n),o=e.response?.usage||e.usage;switch(o&&(a={promptTokens:o.input_tokens||o.prompt_tokens||0,completionTokens:o.output_tokens||o.completion_tokens||0,totalTokens:(o.input_tokens||o.prompt_tokens||0)+(o.output_tokens||o.completion_tokens||0),reasoningTokens:o.output_tokens_details?.reasoning_tokens||o.completion_tokens_details?.reasoning_tokens||0}),e.type){case"response.output_item.added":{const t=e.item;"function_call"===t?.type&&t.call_id&&(i=t.call_id,s.set(t.call_id,{id:t.call_id,name:t.name||"",arguments:t.arguments||""}),yield{type:"tool_call_start",toolCall:{id:t.call_id,name:t.name||""}});break}case"response.function_call_arguments.delta":if(i){const t=s.get(i);t&&(t.arguments+=e.delta||"",yield{type:"tool_call_delta",toolCall:{id:i,arguments:e.delta||""}})}break;case"response.function_call_arguments.done":case"response.output_item.done":{const t=e.item;if("function_call"===t?.type&&t.call_id){const e=s.get(t.call_id);s.set(t.call_id,{id:t.call_id,name:t.name||e?.name||"",arguments:t.arguments||e?.arguments||"{}"})}break}case"response.output_text.annotation.added":{const t=e.annotation;if(t?.url){r.some(e=>e.url===t.url)||(r.push({title:t.title||t.text||"",url:t.url,snippet:t.summary||t.snippet||""}),yield{type:"search_result",searchResults:[...r]})}break}case"response.output_text.delta":e.delta&&(u||(u=!0,t&&!c&&(c=!0,yield{type:"thinking_done"})),yield{type:"text_delta",delta:e.delta});break;case"response.reasoning_summary_text.delta":t&&e.delta&&!c&&(yield{type:"thinking_delta",delta:e.delta})}}catch{}}}if(!l)if(s.size>0){for(const e of s.values())yield{type:"tool_call_done",toolCall:e};yield{type:"done",finishReason:"tool_calls",usage:a}}else yield{type:"done",finishReason:"stop",usage:a}}};function Qe(e){return new Be(e)}var He=xe.module("QwenProtocol"),Ye=class{name="qwen";apiKey;apiUrl;constructor(e){this.apiKey=e.apiKey,this.apiUrl=e.apiUrl??"https://dashscope.aliyuncs.com/compatible-mode/v1"}async*stream(e,t,n){const o=this.buildRequestBody(e,t,n),s=`${this.apiUrl}/chat/completions`;He.debug("发送 Qwen 请求(兼容模式)",{url:s,model:n.model,enableThinking:n.enableThinking,toolsCount:t.length});const i=await fetch(s,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify(o),signal:n.signal});if(!i.ok){const e=await i.text();return He.error("Qwen API 错误",{status:i.status,body:e.slice(0,500)}),void(yield{type:"error",error:ze(i.status,e,"Qwen")})}const r=i.body?.getReader();r?yield*this.parseSSE(r,n.enableThinking):yield{type:"error",error:"无法获取响应流"}}buildRequestBody(e,t,n){const o=this.convertMessages(e),s={model:n.model,messages:o,stream:!0,stream_options:{include_usage:!0}};return n.enableThinking&&(s.enable_thinking=!0,s.thinking_budget=38400),t.length>0&&(s.tools=t.map(e=>({type:"function",function:{name:e.name,description:e.description,parameters:e.parameters}}))),s}convertMessages(e){const t=[];for(const n of e)switch(n.role){case"system":t.push({role:"system",content:n.content});break;case"user":{const e=n.content||(n.images?.length?"请分析这张图片":"");if(n.images?.length){const o=[{type:"text",text:e}];for(const e of n.images)o.push({type:"image_url",image_url:{url:e.startsWith("data:")?e:`data:image/jpeg;base64,${e}`}});t.push({role:"user",content:o})}else t.push({role:"user",content:e});break}case"assistant":n.toolCalls?.length?t.push({role:"assistant",content:n.content||null,tool_calls:n.toolCalls.map(e=>({id:e.id,type:"function",function:{name:e.name,arguments:e.arguments}}))}):t.push({role:"assistant",content:n.content});break;case"tool":t.push({role:"tool",tool_call_id:n.toolCallId,content:n.content})}return t}async*parseSSE(e,t){const n=new TextDecoder;let o="";const s=new Map;let i,r,a=!1,l=!1;for(;;){const{done:c,value:u}=await e.read();if(c)break;o+=n.decode(u,{stream:!0});const p=o.split("\n");o=p.pop()||"";for(const e of p){if(!e.startsWith("data:"))continue;const n=e.slice(5).trim();if(n&&"[DONE]"!==n)try{const e=JSON.parse(n);e.usage&&(i={promptTokens:e.usage.prompt_tokens||0,completionTokens:e.usage.completion_tokens||0,totalTokens:e.usage.total_tokens||(e.usage.prompt_tokens||0)+(e.usage.completion_tokens||0)});const o=e.choices?.[0];if(!o)continue;const c=o.delta;if(!c)continue;if(t&&c.reasoning_content&&!l&&(yield{type:"thinking_delta",delta:c.reasoning_content}),c.content&&(!t||a||l||(l=!0,yield{type:"thinking_done"}),a=!0,yield{type:"text_delta",delta:c.content}),c.tool_calls?.length)for(const e of c.tool_calls){const t=e.index??0,n=s.get(t);n?e.function?.arguments&&(n.arguments+=e.function.arguments):(s.set(t,{id:e.id||`call_${t}`,name:e.function?.name||"",arguments:e.function?.arguments||""}),yield{type:"tool_call_start",toolCall:{id:e.id||`call_${t}`,name:e.function?.name||""}})}o.finish_reason&&(r=o.finish_reason)}catch{}else if("[DONE]"===n){const e=Array.from(s.values());if(e.length>0){for(const t of e)yield{type:"tool_call_done",toolCall:t};yield{type:"done",finishReason:"tool_calls",usage:i}}else{const e="tool_calls"===r||"length"===r||"error"===r?r:"stop";yield{type:"done",finishReason:e,usage:i}}return}}}const c=Array.from(s.values());if(c.length>0){for(const e of c)yield{type:"tool_call_done",toolCall:e};yield{type:"done",finishReason:"tool_calls",usage:i}}else{const e="tool_calls"===r||"length"===r||"error"===r?r:"stop";yield{type:"done",finishReason:e,usage:i}}}};function Ze(e){return new Ye(e)}var Xe=xe.module("GeminiProtocol"),et=class{name="gemini";apiKey;apiUrl;constructor(e){this.apiKey=e.apiKey,this.apiUrl=e.apiUrl??"https://generativelanguage.googleapis.com/v1beta"}async*stream(e,t,n){const o=this.buildRequestBody(e,t,n),s=`${this.apiUrl}/models/${n.model}:streamGenerateContent?key=${this.apiKey}&alt=sse`;Xe.debug("发送 Gemini 请求",{url:s.replace(this.apiKey,"***"),model:n.model,enableSearch:n.enableSearch,enableThinking:n.enableThinking,toolsCount:t.length});const i=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o),signal:n.signal});if(!i.ok){const e=await i.text();return Xe.error("Gemini API 错误",{status:i.status,body:e.slice(0,500)}),void(yield{type:"error",error:ze(i.status,e,"Gemini")})}const r=i.body?.getReader();r?yield*this.parseSSE(r):yield{type:"error",error:"无法获取响应流"}}buildRequestBody(e,t,n){const{systemInstruction:o,contents:s}=this.convertMessages(e),i={contents:s,generationConfig:{maxOutputTokens:n.familyConfig.defaultMaxTokens??65536}};o&&(i.systemInstruction=o),n.enableThinking&&(i.generationConfig.thinkingConfig={thinkingBudget:24576,includeThoughts:!0});const r=[];if(t.length>0){const e=t.map(e=>({name:e.name,description:e.description,parameters:e.parameters})),n=new Map;for(const t of e)n.has(t.name)||n.set(t.name,t);r.push({functionDeclarations:Array.from(n.values())})}else n.enableSearch&&r.push({googleSearch:{}});return r.length>0&&(i.tools=r),i}convertMessages(e){let t;const n=[];for(const o of e)switch(o.role){case"system":t={parts:[{text:o.content}]};break;case"user":{const e=[{text:o.content||(o.images?.length?"请分析这张图片":"")}];if(o.images?.length)for(const t of o.images)if(t.startsWith("data:")){const n=t.match(/^data:([^;]+);base64,(.+)$/);n&&e.push({inlineData:{mimeType:n[1],data:n[2]}})}else e.push({inlineData:{mimeType:"image/jpeg",data:t}});n.push({role:"user",parts:e});break}case"assistant":if(o.toolCalls?.length){const e=[];for(const t of o.toolCalls){const n={functionCall:{name:t.name,args:JSON.parse(t.arguments||"{}")}};n.thoughtSignature=t.thoughtSignature??"skip_thought_signature_validator",e.push(n)}n.push({role:"model",parts:e})}else n.push({role:"model",parts:[{text:o.content}]});break;case"tool":n.push({role:"user",parts:[{functionResponse:{name:o.toolName||"unknown",response:{result:o.content}}}]})}return{systemInstruction:t,contents:n}}async*parseSSE(e){const t=new TextDecoder;let n="";const o=new Map;let s=!1,i=0;for(;;){const{done:r,value:a}=await e.read();if(r)break;n+=t.decode(a,{stream:!0});const l=n.split("\n");n=l.pop()||"";for(const e of l){if(!e.startsWith("data:"))continue;const t=e.slice(5).trim();if(t)try{const e=JSON.parse(t),n=e.candidates?.[0];if(!n?.content?.parts)continue;for(const e of n.content.parts)if(e.text&&(!0===e.thought?yield{type:"thinking_delta",delta:e.text}:(s||(s=!0,yield{type:"thinking_done"}),yield{type:"text_delta",delta:e.text})),e.functionCall){const t="gemini-"+i++,n={id:t,name:e.functionCall.name,arguments:JSON.stringify(e.functionCall.args||{})};e.thoughtSignature&&(n.thoughtSignature=e.thoughtSignature),o.set(t,n),yield{type:"tool_call_start",toolCall:{id:t,name:n.name}},yield{type:"tool_call_done",toolCall:n}}const r=n.groundingMetadata;if(r?.groundingChunks?.length){const e=[];for(const t of r.groundingChunks)t.web?.uri&&e.push({title:t.web.title||"",url:t.web.uri,snippet:""});e.length>0&&(yield{type:"search_result",searchResults:e})}if(n.finishReason){const t=e.usageMetadata,n=t?{promptTokens:t.promptTokenCount||0,completionTokens:t.candidatesTokenCount||0,totalTokens:t.totalTokenCount||0,reasoningTokens:t.thoughtsTokenCount||0,cachedTokens:t.cachedContentTokenCount||0}:void 0;return void(o.size>0?yield{type:"done",finishReason:"tool_calls",usage:n}:yield{type:"done",finishReason:"stop",usage:n})}}catch{}}}o.size>0?yield{type:"done",finishReason:"tool_calls"}:yield{type:"done",finishReason:"stop"}}};function tt(e){return new et(e)}var nt=xe.module("OpenAIProtocol"),ot=class{name="openai";apiKey;apiUrl;constructor(e){this.apiKey=e.apiKey,this.apiUrl=e.apiUrl??ye}async*stream(e,t,n){const o=this.buildRequestBody(e,t,n),s=`${this.apiUrl}/responses`;nt.debug("发送 OpenAI 请求",{url:s,model:n.model,toolsCount:t.length});const i=await fetch(s,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json","HTTP-Referer":"https://ai-chat.local","X-Title":"AI Chat"},body:JSON.stringify(o),signal:n.signal});if(!i.ok){const e=await i.text();return nt.error("OpenAI API 错误",{status:i.status,body:e.slice(0,500)}),void(yield{type:"error",error:ze(i.status,e,"OpenAI")})}const r=i.body?.getReader();r?yield*this.parseSSE(r,n.enableThinking):yield{type:"error",error:"无法获取响应流"}}buildRequestBody(e,t,n){const o=this.convertMessages(e),s={model:n.model,stream:!0,input:o};return n.enableThinking&&(s.reasoning={effort:"high"}),t.length>0&&(s.tools=t.map(e=>({type:"function",name:e.name,description:e.description,parameters:e.parameters}))),s}convertMessages(e){const t=[];for(const n of e)switch(n.role){case"system":t.push({role:"system",content:n.content});break;case"user":{const e=[{type:"input_text",text:n.content||(n.images?.length?"请分析这张图片":"")}];if(n.images?.length)for(const t of n.images)e.push({type:"input_image",image_url:t.startsWith("data:")?t:`data:image/jpeg;base64,${t}`,detail:"auto"});t.push({role:"user",content:e});break}case"assistant":if(n.toolCalls?.length)for(const e of n.toolCalls)t.push({type:"function_call",call_id:e.id,name:e.name,arguments:e.arguments});else t.push({role:"developer",content:`[上一轮AI回复]: ${n.content}`});break;case"tool":t.push({type:"function_call_output",call_id:n.toolCallId,output:n.content})}return t}async*parseSSE(e,t){const n=new TextDecoder;let o="";const s=new Map;let i=null;const r=[];let a,l=!1,c=!1,u=!1;for(;;){const{done:p,value:d}=await e.read();if(p)break;o+=n.decode(d,{stream:!0});const m=o.split("\n");o=m.pop()||"";for(const e of m){if(l)continue;if(!e.startsWith("data:"))continue;const n=e.slice(5).trim();if("[DONE]"===n){if(l=!0,s.size>0){for(const e of s.values())yield{type:"tool_call_done",toolCall:e};yield{type:"done",finishReason:"tool_calls",usage:a}}else yield{type:"done",finishReason:"stop",usage:a};return}try{const e=JSON.parse(n);nt.debug("SSE 事件",{type:e.type,event:JSON.stringify(e).slice(0,200)});const o=e.response?.usage||e.usage;switch(o&&(a={promptTokens:o.input_tokens??o.prompt_tokens??0,completionTokens:o.output_tokens??o.completion_tokens??0,totalTokens:(o.input_tokens??o.prompt_tokens??0)+(o.output_tokens??o.completion_tokens??0),reasoningTokens:o.output_tokens_details?.reasoning_tokens??0,cachedTokens:o.input_tokens_details?.cached_tokens??o.prompt_tokens_details?.cached_tokens??0}),e.type){case"response.output_item.added":{const t=e.item,n=t?.call_id||t?.id;if("function_call"===t?.type&&n){i=n;let e=t.arguments||t.input||"";"object"==typeof e&&(e=JSON.stringify(e)),s.set(n,{id:n,name:t.name||t.function?.name||"",arguments:e}),nt.debug("工具调用开始",{id:n,name:t.name,args:e.slice(0,100)}),yield{type:"tool_call_start",toolCall:{id:n,name:t.name||t.function?.name||""}}}break}case"response.function_call_arguments.delta":{const t=e.delta;if(i&&t){const e=s.get(i);e&&(e.arguments+=t,yield{type:"tool_call_delta",toolCall:{id:i,arguments:t}})}break}case"response.function_call_arguments.done":{const t=e.item_id||e.call_id||i;if(t){const n=s.get(t);if(n){e.arguments&&(n.arguments=e.arguments);try{JSON.parse(n.arguments)}catch{nt.warn("工具参数解析失败,使用空对象",{args:n.arguments.slice(0,100)}),n.arguments="{}"}}}break}case"response.output_item.done":{const t=e.item,n=t?.call_id||t?.id;if("function_call"===t?.type&&n){const e=s.get(n);let o=t.arguments||t.input||e?.arguments||"{}";"object"==typeof o&&(o=JSON.stringify(o)),s.set(n,{id:n,name:t.name||t.function?.name||e?.name||"",arguments:o}),nt.debug("工具调用完成",{id:n,name:t.name,args:o.slice(0,100)})}break}case"response.output_text.annotation.added":{const t=e.annotation;if(t?.url){r.some(e=>e.url===t.url)||(r.push({title:t.title||t.text||"",url:t.url,snippet:t.summary||t.snippet||""}),yield{type:"search_result",searchResults:[...r]})}break}case"response.output_text.delta":e.delta&&(u||(u=!0,t&&!c&&(c=!0,yield{type:"thinking_done"})),yield{type:"text_delta",delta:e.delta});break;case"response.reasoning_summary_text.delta":t&&e.delta&&!c&&(yield{type:"thinking_delta",delta:e.delta});break;case"response.done":case"response.completed":{const t=e.response;if(t?.output?.length)for(const e of t.output)if("function_call"===e.type&&e.call_id){const t=s.get(e.call_id);let n=e.arguments||t?.arguments||"{}";"object"==typeof n&&(n=JSON.stringify(n)),s.set(e.call_id,{id:e.call_id,name:e.name||t?.name||"",arguments:n}),nt.debug("response.completed: 更新工具参数",{id:e.call_id,args:n.slice(0,100)})}const n=t?.usage,o=n?{promptTokens:n.input_tokens||n.prompt_tokens||0,completionTokens:n.output_tokens||n.completion_tokens||0,totalTokens:(n.input_tokens||n.prompt_tokens||0)+(n.output_tokens||n.completion_tokens||0),reasoningTokens:n.output_tokens_details?.reasoning_tokens||0,cachedTokens:n.input_tokens_details?.cached_tokens||n.prompt_tokens_details?.cached_tokens||0}:void 0;if(a=o,l=!0,s.size>0){for(const e of s.values())nt.debug("response.completed: 发出 tool_call_done",e),yield{type:"tool_call_done",toolCall:e};yield{type:"done",finishReason:"tool_calls",usage:o}}else yield{type:"done",finishReason:"stop",usage:o};return}}}catch(t){nt.warn("SSE 解析错误",{line:e.slice(0,100),error:String(t)})}}}if(!l)if(nt.debug("流结束,执行兜底逻辑",{pendingToolCalls:s.size}),s.size>0){for(const e of s.values())yield{type:"tool_call_done",toolCall:e};yield{type:"done",finishReason:"tool_calls",usage:a}}else yield{type:"done",finishReason:"stop",usage:a}}};function st(e){return new ot(e)}var it=xe.module("AnthropicProtocol"),rt=class{name="anthropic";gateway;constructor(e){this.gateway=s({apiKey:e.apiKey})}async*stream(e,t,n){it.debug("使用 Vercel AI Gateway 调用 Claude",{model:n.model,enableThinking:n.enableThinking,toolsCount:t.length});try{const o=this.convertMessages(e),s={model:this.gateway(n.model),messages:o,maxOutputTokens:n.familyConfig.defaultMaxTokens,abortSignal:n.signal};t.length>0&&(s.tools=this.convertTools(t)),n.enableThinking&&(s.providerOptions={anthropic:{thinking:{type:"enabled",budgetTokens:1e4}}}),it.debug("发送请求到 Vercel AI Gateway",{model:n.model,messagesCount:o.length,toolsCount:t.length,enableThinking:n.enableThinking});const r=i(s);yield*this.parseStream(r)}catch(e){const t=at(e);it.error("Vercel AI Gateway 错误",{error:t}),yield{type:"error",error:t}}}convertMessages(e){const t=[];for(const n of e)switch(n.role){case"system":t.push({role:"system",content:n.content});break;case"user":{const e=n.content||(n.images?.length?"请分析这张图片":"");if(n.images?.length){const o=[{type:"text",text:e}];for(const e of n.images)o.push({type:"image",image:e.startsWith("data:")?e:`data:image/jpeg;base64,${e}`});t.push({role:"user",content:o})}else t.push({role:"user",content:e});break}case"assistant":n.content&&t.push({role:"assistant",content:n.content});break;case"tool":t.push({role:"user",content:`[工具 ${n.toolName||"unknown"} 返回结果]: ${n.content}`})}return t}convertTools(e){const t={};for(const n of e){const e=this.jsonSchemaToZod(n.parameters);t[n.name]=r({description:n.description,inputSchema:e})}return t}jsonSchemaToZod(e){const t={};for(const[n,o]of Object.entries(e.properties)){let s;switch(o.type){case"string":s=o.enum?a.enum(o.enum):a.string();break;case"number":case"integer":s=a.number();break;case"boolean":s=a.boolean();break;case"array":s=a.array(a.string());break;default:s=a.unknown()}o.description&&(s=s.describe(o.description)),e.required?.includes(n)||(s=s.optional()),t[n]=s}return a.object(t)}async*parseStream(e){const t=new Map;let n=!1,o=!1;for await(const s of e.fullStream)switch(s.type){case"reasoning-delta":"text"in s&&s.text&&(n=!0,yield{type:"thinking_delta",delta:s.text});break;case"reasoning-end":n&&!o&&(o=!0,yield{type:"thinking_done"});break;case"text-delta":n&&!o&&(o=!0,yield{type:"thinking_done"}),"text"in s&&s.text&&(yield{type:"text_delta",delta:s.text});break;case"tool-call":if("toolCallId"in s&&"toolName"in s){const e=s.toolCallId,n=s.toolName,o="input"in s?s.input:null,i=o?"string"==typeof o?o:JSON.stringify(o):"{}";yield{type:"tool_call_start",toolCall:{id:e,name:n}},t.set(e,{id:e,name:n,arguments:i}),yield{type:"tool_call_done",toolCall:{id:e,name:n,arguments:i}}}break;case"error":{const e="error"in s?s.error:void 0,t=e?at(e):"模型请求失败";return it.error("AI SDK stream error 事件",{error:t}),void(yield{type:"error",error:t})}case"finish":{const e=t.size>0?"tool_calls":"finishReason"in s&&"stop"===s.finishReason?"stop":"finishReason"in s&&"length"===s.finishReason?"length":"stop",n="totalUsage"in s?s.totalUsage:"usage"in s?s.usage:void 0,o=n?.promptTokens??n?.inputTokens??0,i=n?.completionTokens??n?.outputTokens??0,r=n?{promptTokens:o,completionTokens:i,totalTokens:n.totalTokens??o+i}:void 0;return void(yield{type:"done",finishReason:e,usage:r})}}yield{type:"done",finishReason:"stop"}}};function at(e){if(!e||"object"!=typeof e)return"未知错误";const t=e,n=t.cause?.data?.error;if(n?.message){const e=t.cause?.statusCode||t.statusCode;return"insufficient_funds"===n.type||402===e?"账户余额不足,请充值后重试":401===e?"API 认证失败,请检查 API Key 配置":429===e?"请求过于频繁,请稍后重试":`API 错误: ${n.message}`}if(t.cause?.responseBody)try{const e=JSON.parse(t.cause.responseBody);if(e?.error?.message){const n=t.cause?.statusCode||t.statusCode;return"insufficient_funds"===e.error.type||402===n?"账户余额不足,请充值后重试":`API 错误: ${e.error.message}`}}catch{}const o=t.statusCode||t.cause?.statusCode;if(402===o)return"账户余额不足,请充值后重试";if(401===o)return"API 认证失败,请检查 API Key 配置";if(429===o)return"请求过于频繁,请稍后重试";if(503===o)return"服务暂时不可用,请稍后重试";const s=t.message||"未知错误";return s.length>200?s.slice(0,200)+"...":s}function lt(e){return new rt(e)}var ct=xe.module("UnifiedAdapter"),ut=class{name="unified";get supportedModels(){return _().map(e=>e.id)}protocols=new Map;constructor(e){e.arkApiKey&&(this.protocols.set("ark",Ge({apiKey:e.arkApiKey,apiUrl:e.arkApiUrl})),this.protocols.set("deepseek",Qe({apiKey:e.arkApiKey,apiUrl:e.arkApiUrl}))),e.qwenApiKey&&this.protocols.set("qwen",Ze({apiKey:e.qwenApiKey,apiUrl:e.qwenApiUrl})),e.geminiApiKey&&this.protocols.set("gemini",tt({apiKey:e.geminiApiKey,apiUrl:e.geminiApiUrl})),e.openrouterApiKey&&this.protocols.set("openai",st({apiKey:e.openrouterApiKey,apiUrl:e.openrouterApiUrl})),e.vercelApiKey&&this.protocols.set("anthropic",lt({apiKey:e.vercelApiKey}))}supportsModel(e){const t=k(e);return!!t&&this.protocols.has(t)}getModelFamilyConfig(e){return y(e)}async*streamOnce(e,t,n){const{model:o,enableThinking:s=!1,enableSearch:i=!1,signal:r}=n,a=e.map(e=>({role:e.role,content:e.content,images:e.images,toolCalls:e.toolCalls?.map(e=>({id:e.id,name:e.name,arguments:e.arguments,thoughtSignature:e.thought_signature})),toolCallId:e.toolCallId,toolName:e.toolName})),l=t;yield*this.stream(a,l,{model:o,enableThinking:s,enableSearch:i,signal:r})}async*stream(e,t,n){const{model:o,enableThinking:s=!1,enableSearch:i=!1,signal:r}=n,a=k(o),l=y(o);if(!a)return void(yield{type:"error",error:`未知模型: ${o}`});if(!l)return void(yield{type:"error",error:`模型 ${o} 缺少家族配置`});const c=this.protocols.get(a);if(!c)return void(yield{type:"error",error:`Protocol ${a} 未配置`});ct.debug("开始流式调用",{model:o,protocol:a,family:l.id,enableThinking:s,enableSearch:i});const u=c.stream(e,t,{model:o,familyConfig:l,enableThinking:s,enableSearch:i,signal:r});yield*this.transformEvents(u,l,s,i)}async*transformEvents(e,t,n,o){let s=!1;for await(const i of e)switch(i.type){case"thinking_delta":if(n&&t.supportsThinking&&i.delta){let e=i.delta;s||(e=e.replace(/^\n+/,""),e&&(s=!0)),e&&(yield{type:"thinking",thinking:e})}break;case"thinking_done":n&&t.supportsThinking&&(yield{type:"thinking_done"});break;case"text_delta":i.delta&&(yield{type:"text",text:i.delta});break;case"tool_call_done":if(i.toolCall){const e={id:i.toolCall.id||"",name:i.toolCall.name||"",arguments:i.toolCall.arguments||"{}"};i.toolCall.thoughtSignature&&(e.thought_signature=i.toolCall.thoughtSignature),yield{type:"tool_call",toolCall:e}}break;case"search_result":if(o&&i.searchResults){const e=i.searchResults.map(e=>({title:e.title,url:e.url,snippet:e.snippet}));yield{type:"search_result",searchResults:e}}break;case"done":yield{type:"done",finishReason:i.finishReason||"stop",usage:i.usage?{promptTokens:i.usage.promptTokens,completionTokens:i.usage.completionTokens,totalTokens:i.usage.totalTokens,reasoningTokens:i.usage.reasoningTokens,cachedTokens:i.usage.cachedTokens}:void 0};break;case"error":yield{type:"error",error:i.error||"未知错误"}}}};function pt(e){return new ut(e)}var dt=class{config;adapter;orchestrator;toolExecutor;abortController=null;tools=new Map;toolConfig;mcpManager=null;mcpConfigs;constructor(e,t){this.config={arkApiKey:e.arkApiKey,arkApiUrl:e.arkApiUrl||fe,qwenApiKey:e.qwenApiKey||"",qwenApiUrl:e.qwenApiUrl||"https://dashscope.aliyuncs.com/compatible-mode/v1",openrouterApiKey:e.openrouterApiKey||"",openrouterApiUrl:e.openrouterApiUrl||ye,vercelApiKey:e.vercelApiKey||"",tavilyApiKey:e.tavilyApiKey||"",geminiApiKey:e.geminiApiKey,cwd:e.cwd||process.cwd()},this.toolExecutor=t||he(this.config.cwd),this.toolConfig=e.tools,this.mcpConfigs=e.mcpServers,this.tools=new Map,this.adapter=new ut({arkApiKey:this.config.arkApiKey,arkApiUrl:this.config.arkApiUrl,qwenApiKey:this.config.qwenApiKey,qwenApiUrl:this.config.qwenApiUrl,geminiApiKey:this.config.geminiApiKey,openrouterApiKey:this.config.openrouterApiKey,openrouterApiUrl:this.config.openrouterApiUrl,vercelApiKey:this.config.vercelApiKey}),this.orchestrator=new We({executeTool:this.executeTool.bind(this),tools:this.tools,onToolApprovalRequest:e.onToolApprovalRequest,getAutoRunConfig:e.getAutoRunConfig,summarize:e.summarize})}async asyncInit(){if(this.toolConfig&&0===this.tools.size){const e=await O(this.toolConfig);for(const t of e)this.tools.set(t.name,t)}var e;if(this.config.tavilyApiKey&&!this.tools.has(Pe)&&this.tools.set(Pe,(e=this.config.tavilyApiKey,{name:Pe,description:"联网搜索工具。输入 query(搜索关键词/问题),返回搜索结果列表(title/url/snippet)。用于获取实时信息与可引用来源。",parameters:{type:"object",properties:{query:{type:"string",description:"搜索关键词或问题(必填)"},max_results:{type:"number",description:"最大返回结果数(可选,默认 5)"}},required:["query"]},execute:async(t,n)=>{const o="string"==typeof t.query?t.query:"",s="number"==typeof t.max_results&&Number.isFinite(t.max_results)?Math.max(1,Math.min(10,Math.floor(t.max_results))):5;if(!o.trim())return{query:"",results:[],error:"缺少 query"};if(!e)return{query:o,results:[],error:"缺少 Tavily API Key"};const i=await fetch("https://api.tavily.com/search",{method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify({query:o,max_results:s,search_depth:"basic",include_answer:!1,include_raw_content:!1}),signal:n.signal});if(!i.ok){const e=await i.text().catch(()=>"");return{query:o,results:[],error:`Tavily /search 错误: ${i.status} ${e}`.trim()}}const r=await i.json().catch(()=>null),a=[],l=r&&"object"==typeof r&&Array.isArray(r.results)?r.results:[];for(const e of l){const t="string"==typeof e?.url?e.url:"";if(!t)continue;const n="string"==typeof e?.title?e.title:"",o="string"==typeof e?.content?e.content:"";a.push({title:n,url:t,snippet:o})}return{query:o,results:a}}})),this.mcpConfigs?.length&&!this.mcpManager){this.mcpManager=new Ae,await this.mcpManager.connectAll(this.mcpConfigs);for(const e of this.mcpManager.getAllTools())this.tools.has(e.name)||this.tools.set(e.name,e)}}getModelFamilyConfig(e){return y(e)}getModelProvider(e){return _e(e)}getModelRouteInfo(e){return{...be(e),available:this.adapter.supportsModel(e),familyConfig:y(e)}}buildSystemPrompt(e){const t=e.model||ke,n=y(t);let o="你是一个专业的 AI 助手,具备自主执行复杂任务的能力。\n\n## 工作方式\n1. **分析任务**:理解用户需求,拆解为可执行的步骤\n2. **逐步执行**:按步骤依次调用工具,检查每步结果\n3. **自我验证**:工具执行后检查结果是否符合预期\n4. **自动纠正**:发现问题时尝试替代方案,不要停下来问用户\n5. **总结汇报**:所有步骤完成后,给出简洁的结果总结\n\n## 输出规范\n- 不使用表情符号(emoji),除非用户要求\n- 使用 Markdown 格式组织内容\n- 代码块使用正确的语言标识";return e.platformPrompt&&(o+="\n\n"+e.platformPrompt),e.skillContents?.length&&(o+="\n\n【用户指令】\n"+e.skillContents.join("\n\n")),e.enableWebSearch&&n&&!v(t)&&(o+=`\n\n【联网搜索】当用户问题需要实时信息/最新事实/可引用来源时,请先调用 ${Pe} 工具获取结果,然后基于返回的 title/url/snippet 作答,并在回答中给出来源链接。`),o}getDefaultThinkingMode(){return"disabled"}createToolContext(e,t){const n=this.config.cwd,o=this.toolExecutor;return{cwd:n,exec:async(s,i)=>{const r=i?.length?`${s} ${i.join(" ")}`:s,a=await o.executeCommand(r,n,e,{onStdout:t?.onStdout,onStderr:t?.onStderr});return{stdout:a.output??"",stderr:a.error??"",exitCode:a.success?0:1}},signal:e}}async executeTool(e,t,n,o){const s=this.tools.get(e);return s?await s.execute(t,this.createToolContext(n,o)):{error:`未知工具: ${e}`}}getToolDefinitions(e,t){const n=Array.from(this.tools.values());let o=void 0!==e?n.filter(t=>e.includes(t.name)):n;if(t?.length)for(const e of t)if(!o.some(t=>t.name===e)){const t=this.tools.get(e);t&&(o=[...o,t])}return o.map(e=>({name:e.name,description:e.description,parameters:e.parameters}))}getAllTools(){return Array.from(this.tools.values()).map(e=>({name:e.name,description:e.description}))}async*chat(e,t={},n){await this.asyncInit(),this.abortController=new AbortController;const o=this.abortController.signal,s=t.model||ke;if(!this.adapter.supportsModel(s)){return void(y(s)?yield Y(`模型 ${s} 缺少 API Key 配置`,{code:"MISSING_API_KEY"}):yield Y(`未知模型: ${s}`,{code:"MODEL_NOT_SUPPORTED"}))}const i=y(s),r="enabled"===(t.thinkingMode??this.getDefaultThinkingMode())?"enabled":"disabled",a=this.buildSystemPrompt(t),l="ask"===t.mode,c=!l&&!!t.enableWebSearch,u=c&&i&&!v(s)?[Pe]:void 0,p=l?[]:this.getToolDefinitions(t.enabledTools,u),d=t.userTools||[],m=[...p,...d.map(e=>({name:e.name,description:e.description,parameters:{...e.parameters,required:e.parameters.required||[]}}))],g=d.length>0?new Set(d.map(e=>e.name)):void 0,h=!l&&"enabled"===r&&(i?.supportsThinking??!1),f={systemPrompt:a,history:t.history||[],tools:m,signal:o,images:n,clientToolNames:g};try{yield*this.orchestrator.chat(this.adapter,e,f,{model:s,enableThinking:h,enableSearch:c,autoRunConfig:t.autoRunConfig})}finally{this.abortController=null}}abort(){this.abortController&&this.abortController.abort()}setCwd(e){this.config.cwd=e}getConfig(){return{...this.config}}getSupportedModels(){return A}getMcpConnections(){return this.mcpManager?.getConnectionInfos()??[]}async destroy(){this.mcpManager&&(await this.mcpManager.disconnectAll(),this.mcpManager=null)}};export{rt as AnthropicProtocol,Ve as ArkProtocol,P as CHAT_EVENT_TYPES,m as CLAUDE_FAMILY,We as ChatOrchestrator,c as DEEPSEEK_FAMILY,ke as DEFAULT_MODEL,l as DOUBAO_FAMILY,xe as DebugLogger,Be as DeepSeekProtocol,p as GEMINI_FAMILY,d as GPT_FAMILY,et as GeminiProtocol,dt as HybridAgent,A as MODELS,g as MODEL_FAMILIES,h as MODEL_REGISTRY,ot as OpenAIProtocol,u as QWEN_FAMILY,Ye as QwenProtocol,ut as UnifiedAdapter,ne as createAbort,lt as createAnthropicProtocol,Y as createApiError,Ge as createArkProtocol,Qe as createDeepSeekProtocol,he as createDefaultToolExecutor,Q as createDone,H as createError,tt as createGeminiProtocol,st as createOpenAIProtocol,je as createOrchestrator,te as createParseError,Ze as createQwenProtocol,Z as createRateLimitError,z as createSearchEnd,J as createSearchResult,j as createSearchStart,se as createStepEnd,oe as createStepStart,B as createTextDelta,U as createThinkingDelta,W as createThinkingEnd,D as createThinkingStart,ee as createTimeoutError,G as createToolCallOutput,L as createToolCallRequest,V as createToolCallResult,F as createToolCallStart,X as createToolError,pt as createUnifiedAdapter,I as getArg,we as getDefaultProvider,$ as getModelByModelId,f as getModelEntry,y as getModelFamily,k as getModelProtocol,x as getModelSearchStrategy,b as getModelsByFamily,w as getModelsByProtocol,_ as getVisibleModels,pe as isAbortEvent,ue as isErrorEvent,Te as isModelForProvider,me as isRetryableError,re as isSearchEvent,ce as isStatusEvent,de as isStepEvent,le as isTextEvent,ie as isThinkingEvent,R as isThrowableToolError,R as isToolError,ae as isToolEvent,v as modelSupportsNativeSearch,T as modelSupportsThinking,O as resolveTools,N as rethrowToolError,_e as routeModelToProvider,be as routeModelWithDetails,M as throwToolError,K as tool,q as tools};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huyooo/ai-chat-core",
3
- "version": "0.2.42",
3
+ "version": "0.2.44",
4
4
  "description": "AI Chat Core - HybridAgent with Doubao + Gemini",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/agent.ts CHANGED
@@ -116,6 +116,7 @@ export class HybridAgent {
116
116
  tools: this.tools,
117
117
  onToolApprovalRequest: config.onToolApprovalRequest,
118
118
  getAutoRunConfig: config.getAutoRunConfig,
119
+ summarize: config.summarize,
119
120
  });
120
121
  }
121
122
 
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Context Summarizer — 专用上下文总结模块
3
+ *
4
+ * 当对话历史超过当前模型的 context window 时,通过外部注入的 summarize 回调执行 AI 总结。
5
+ * 回调由宿主提供(如 smart-finder 走 ai-server 的 toolAI),ai-chat-core 不关心具体调用方式。
6
+ */
7
+
8
+ import type { StandardMessage } from './types';
9
+ import {
10
+ buildSummarizeRequest,
11
+ applySummary,
12
+ estimateTotalTokens,
13
+ type CompactConfig,
14
+ } from './context-compressor';
15
+ import { DebugLogger } from '../utils';
16
+
17
+ const logger = DebugLogger.module('ContextSummarizer');
18
+
19
+ // ==================== 类型 ====================
20
+
21
+ /** 外部注入的 AI 总结函数 */
22
+ export type SummarizeFn = (systemPrompt: string, userPrompt: string) => Promise<string>;
23
+
24
+ export interface SummarizeResult {
25
+ messages: StandardMessage[];
26
+ success: boolean;
27
+ }
28
+
29
+ // ==================== 核心函数 ====================
30
+
31
+ /**
32
+ * 使用 AI 总结对话历史
33
+ *
34
+ * 1. 用 buildSummarizeRequest 分离「待总结的中间历史」和「保留的最近消息」
35
+ * 2. 调用外部注入的 summarizeFn 执行总结(走 ai-server 等)
36
+ * 3. 用 applySummary 组装压缩后的消息列表
37
+ */
38
+ export async function summarizeHistory(
39
+ summarizeFn: SummarizeFn,
40
+ messages: StandardMessage[],
41
+ config: CompactConfig,
42
+ ): Promise<SummarizeResult> {
43
+ const { summarizeMessages, keepMessages } = buildSummarizeRequest(messages, config);
44
+
45
+ if (summarizeMessages.length === 0) {
46
+ logger.info('中间历史太短,跳过 AI 总结');
47
+ return { messages, success: true };
48
+ }
49
+
50
+ const systemPrompt = summarizeMessages[0].content;
51
+ const userPrompt = summarizeMessages[1].content;
52
+
53
+ logger.info(`开始 AI 总结: ~${estimateTotalTokens(summarizeMessages)} tokens, ${messages.length} 条消息`);
54
+
55
+ try {
56
+ const summary = await summarizeFn(systemPrompt, userPrompt);
57
+
58
+ if (!summary.trim()) {
59
+ logger.warn('AI 总结返回空内容');
60
+ return { messages, success: false };
61
+ }
62
+
63
+ const compressed = applySummary(messages, summary, keepMessages);
64
+ logger.info(`AI 总结完成: ${messages.length} → ${compressed.length} 条消息, ~${estimateTotalTokens(compressed)} tokens`);
65
+ return { messages: compressed, success: true };
66
+ } catch (err) {
67
+ logger.error('AI 总结异常:', err);
68
+ return { messages, success: false };
69
+ }
70
+ }
@@ -79,6 +79,11 @@ export type {
79
79
 
80
80
  export { ChatOrchestrator, createOrchestrator } from './orchestrator';
81
81
 
82
+ // ==================== Context 压缩与总结 ====================
83
+
84
+ export { summarizeHistory } from './context-summarizer';
85
+ export type { SummarizeFn, SummarizeResult } from './context-summarizer';
86
+
82
87
  // ==================== UnifiedAdapter(新架构) ====================
83
88
 
84
89
  export { UnifiedAdapter, createUnifiedAdapter } from './unified-adapter';
@@ -225,8 +225,10 @@ export const MODEL_REGISTRY: ModelRegistryEntry[] = [
225
225
  // DeepSeek(价格为输入<=32k档)
226
226
  { id: 'deepseek-v3-2-251201', displayName: 'DeepSeek V3.2', family: 'deepseek', protocol: 'deepseek', visible: true, supportsVision: false, contextWindow: '128K', contextWindowTokens: 128_000, pricing: ['输入 2 元/百万tokens', '输出 3 元/百万tokens'] },
227
227
 
228
- // 通义千问(官方 2025.09 确认 262K context / 32K output)
228
+ // 通义千问
229
229
  { id: 'qwen3-vl-plus', displayName: '通义千问 3 VL', family: 'qwen', protocol: 'qwen', visible: true, supportsVision: true, contextWindow: '262K', contextWindowTokens: 262_144, pricing: ['输入 1 元/百万tokens', '输出 10 元/百万tokens'] },
230
+ { id: 'qwen3.5-plus', displayName: '通义千问 3.5 Plus', family: 'qwen', protocol: 'qwen', contextWindow: '1M', contextWindowTokens: 1_000_000, pricing: ['输入 0.8 元/百万tokens', '输出 4.8 元/百万tokens'] },
231
+ { id: 'qwen-long', displayName: '通义千问 Long', family: 'qwen', protocol: 'qwen', contextWindow: '10M', contextWindowTokens: 10_000_000, pricing: ['输入 0.5 元/百万tokens', '输出 2 元/百万tokens'] },
230
232
 
231
233
  // Gemini
232
234
  { id: 'gemini-3-pro-preview', displayName: 'Gemini 3 Pro', family: 'gemini', protocol: 'gemini', visible: true, supportsVision: true, contextWindow: '1M', contextWindowTokens: 1_000_000, pricing: ['输入 1.25 元/百万tokens', '输出 10 元/百万tokens'] },
@@ -51,10 +51,9 @@ import {
51
51
  needsCompaction,
52
52
  estimateTotalTokens,
53
53
  getPromptBudget,
54
- buildSummarizeRequest,
55
- applySummary,
56
54
  type CompactConfig,
57
55
  } from './context-compressor';
56
+ import { summarizeHistory } from './context-summarizer';
58
57
  import { getModelContextConfig } from './model-registry';
59
58
  import { WEB_SEARCH_TOOL_NAME } from '../internal/web-search';
60
59
 
@@ -153,7 +152,7 @@ export class ChatOrchestrator {
153
152
 
154
153
  // 初始压缩:前端传入的历史可能就已经超长
155
154
  {
156
- const gen = this.compactIfNeeded(adapter, messages, compactConfig, options, context.signal);
155
+ const gen = this.compactIfNeeded(messages, compactConfig);
157
156
  let step = await gen.next();
158
157
  while (!step.done) {
159
158
  yield step.value;
@@ -191,7 +190,7 @@ export class ChatOrchestrator {
191
190
 
192
191
  // 每轮迭代前检查是否需要压缩
193
192
  if (iterations > 1) {
194
- const gen = this.compactIfNeeded(adapter, messages, compactConfig, options, context.signal);
193
+ const gen = this.compactIfNeeded(messages, compactConfig);
195
194
  let step = await gen.next();
196
195
  while (!step.done) {
197
196
  yield step.value;
@@ -794,22 +793,21 @@ export class ChatOrchestrator {
794
793
  return messages;
795
794
  }
796
795
 
797
- /**
798
- * 检测并执行上下文压缩,yield 结构化事件
799
- *
800
- * 返回(可能已压缩的)消息列表。如果不需要压缩则直接返回原消息。
801
- */
796
+ /** 检测并执行上下文压缩,通过注入的 summarize 回调走 ai-server */
802
797
  private async *compactIfNeeded(
803
- adapter: ProviderAdapter,
804
798
  messages: StandardMessage[],
805
799
  compactConfig: CompactConfig,
806
- options: OrchestratorOptions,
807
- signal: AbortSignal,
808
800
  ): AsyncGenerator<CompactStartEvent | CompactEndEvent, StandardMessage[]> {
809
801
  if (!needsCompaction(messages, compactConfig)) {
810
802
  return messages;
811
803
  }
812
804
 
805
+ const summarizeFn = this.config.summarize;
806
+ if (!summarizeFn) {
807
+ logger.warn('上下文超限但未配置 summarize 回调,跳过压缩');
808
+ return messages;
809
+ }
810
+
813
811
  const compactStartedAt = Date.now();
814
812
  const tokensBeforeCompact = estimateTotalTokens(messages);
815
813
  const budget = getPromptBudget(compactConfig);
@@ -817,8 +815,8 @@ export class ChatOrchestrator {
817
815
 
818
816
  yield createCompactStart(tokensBeforeCompact, budget);
819
817
 
820
- const { messages: result, success } = await this.aiSummarize(
821
- adapter, messages, compactConfig, options, signal,
818
+ const { messages: result, success } = await summarizeHistory(
819
+ summarizeFn, messages, compactConfig,
822
820
  );
823
821
 
824
822
  yield createCompactEnd(
@@ -831,61 +829,6 @@ export class ChatOrchestrator {
831
829
 
832
830
  return result;
833
831
  }
834
-
835
- /**
836
- * 用当前模型总结对话历史
837
- *
838
- * 把中间历史交给同一个 adapter/model,让 AI 自己生成摘要,
839
- * 然后用 摘要 + 最近几条消息 替换原消息列表。
840
- */
841
- private async aiSummarize(
842
- adapter: ProviderAdapter,
843
- messages: StandardMessage[],
844
- config: CompactConfig,
845
- options: OrchestratorOptions,
846
- signal: AbortSignal,
847
- ): Promise<{ messages: StandardMessage[]; success: boolean }> {
848
- const { summarizeMessages, keepMessages } = buildSummarizeRequest(messages, config);
849
-
850
- if (summarizeMessages.length === 0) {
851
- logger.info('中间历史太短,跳过 AI 总结');
852
- return { messages, success: true };
853
- }
854
-
855
- logger.info('开始 AI 总结对话历史...');
856
-
857
- try {
858
- let summary = '';
859
-
860
- const stream = adapter.streamOnce(summarizeMessages, [], {
861
- model: options.model,
862
- enableThinking: false,
863
- enableSearch: false,
864
- signal,
865
- });
866
-
867
- for await (const chunk of stream) {
868
- if (chunk.type === 'text' && chunk.text) {
869
- summary += chunk.text;
870
- }
871
- if (chunk.type === 'error') {
872
- logger.error('AI 总结失败:', chunk.error);
873
- return { messages, success: false };
874
- }
875
- }
876
-
877
- if (!summary.trim()) {
878
- logger.warn('AI 总结返回空内容,保持原消息');
879
- return { messages, success: false };
880
- }
881
-
882
- logger.info(`AI 总结完成: ${summary.length} 字符`);
883
- return { messages: applySummary(messages, summary, keepMessages), success: true };
884
- } catch (err) {
885
- logger.error('AI 总结异常:', err);
886
- return { messages, success: false };
887
- }
888
- }
889
832
  }
890
833
 
891
834
  /**
@@ -227,6 +227,8 @@ export interface OrchestratorConfig {
227
227
  * 3. 客户端执行后,发新请求继续对话
228
228
  */
229
229
  clientToolNames?: Set<string>;
230
+ /** 上下文总结回调(走 ai-server 等外部服务) */
231
+ summarize?: (systemPrompt: string, userPrompt: string) => Promise<string>;
230
232
  }
231
233
 
232
234
  /** Orchestrator 上下文 */
package/src/types.ts CHANGED
@@ -160,6 +160,17 @@ export interface AgentConfig {
160
160
  * ```
161
161
  */
162
162
  mcpServers?: McpServerConfig[];
163
+ /**
164
+ * 上下文总结回调(走 ai-server 等外部服务)
165
+ *
166
+ * 当对话历史超过模型 context window 时,orchestrator 调用此函数执行 AI 总结。
167
+ * 宿主提供实现(如 smart-finder 的 toolAI),ai-chat-core 不关心具体调用方式。
168
+ *
169
+ * @param systemPrompt 总结指令
170
+ * @param userPrompt 格式化后的中间对话历史
171
+ * @returns 总结后的文本
172
+ */
173
+ summarize?: (systemPrompt: string, userPrompt: string) => Promise<string>;
163
174
  }
164
175
 
165
176
  /** 深度思考模式 */