/** * Agnes AI Provider Adapter * * OpenAI 兼容 API。支持 Tool Calling、Thinking 模式、多模态(图片 — URL + Base64)。 * * v0.6.4 P3-1: 继承 OpenAICompatibleAdapter —— 传输/组装/回退链收敛到共享基类, * 本文件只保留 Agnes 差异点:chat_template_kwargs 思考开关(v0.6.4 对称性修复)、 * 无条件 includeImages、非流式默认超时 300s。 * 注:Agnes API 未提供 /models 端点,listModels 使用基类默认实现。 * * @see apis/agnes-ai-api-docs-20260625.html */ import log from 'electron-log'; import type { MetonaRequest } from '../types'; import type { MetonaModelInfo } from '../types/metona-adapter'; import { buildOpenAICompatibleMessages, buildOpenAICompatibleTools } from './shared/openai-format'; import { OpenAICompatibleAdapter } from './shared/openai-compatible-base'; export class AgnesAdapter extends OpenAICompatibleAdapter { override readonly providerId: string = 'agnes'; readonly supportedModels = ['agnes-2.0-flash']; readonly supportsToolCalling = true; readonly supportsThinking = true; // H-2 修复: Agnes 模型元信息(1M 上下文,65.5K 最大输出) private static readonly MODEL_INFO: Record = { 'agnes-2.0-flash': { id: 'agnes-2.0-flash', name: 'Agnes 2.0 Flash', contextWindow: 1_000_000, maxOutputTokens: 65_536, supportsToolCalling: true, supportsThinking: true, description: 'Agnes AI 快速版,1M 上下文,支持多模态图片(URL + Base64)与思考模式', }, }; // ===== 共享基类差异声明 ===== protected override chatCompletionsUrl(): string { return `${this.config.baseURL}/chat/completions`; } protected override sendTimeoutMs(): number { return 300_000; } protected override modelInfoTable(): Record { return AgnesAdapter.MODEL_INFO; } protected override providerLabel(): string { return 'Agnes AI'; } // ========== 协议参数映射(Agnes 差异点) ========== protected override toNativeRequest(request: MetonaRequest, stream: boolean): Record { // v0.6.2: images 处理收敛至共享层(原索引对齐循环在孤立 tool 过滤后会错位) const messages = buildOpenAICompatibleMessages(request, true); const tools = buildOpenAICompatibleTools(request.tools); const imageCount = request.messages.reduce((n, m) => n + (m.images?.length ?? 0), 0); if (imageCount > 0) { const firstUrl = request.messages.find((m) => m.images?.length)?.images?.[0]?.url ?? ''; log.info( `[Agnes] Processing ${imageCount} image(s), first URL prefix: ${firstUrl.slice(0, 50)}`, ); } // v0.5.3: max_tokens 按模型上限钳制(agnes-2.0-flash 上限 65536) const modelInfo = AgnesAdapter.MODEL_INFO[this.config.defaultModel]; const maxOutput = modelInfo?.maxOutputTokens ?? 65_536; const maxTokens = Math.min(request.params.maxTokens ?? maxOutput, maxOutput); const body: Record = { model: this.config.defaultModel, messages, temperature: request.params.temperature, max_tokens: maxTokens, stream, }; if (stream) { body.stream_options = { include_usage: true }; } if (tools) { body.tools = tools; } // C-3 修复 + v0.6.4 对称性修复: Thinking 模式 — Agnes 使用 chat_template_kwargs // Agnes API 仅支持 enable_thinking: true/false,不支持 effort 级别 // thinkingEffort === 'low' 时映射为 false;thinkingEnabled 为 false 或未配置时 // 显式发送 enable_thinking:false —— 原实现只在 thinkingEnabled===true 时写该字段, // 若服务端默认开启思考,客户端没有任何路径把它关掉(DeepSeek/MiMo 均显式发送 // disabled 保持对称,唯独此处漏了)。 { const effort = request.params.thinkingEffort ?? 'high'; // 未配置 thinkingEnabled 一律显式关闭 —— 与 DeepSeek/MiMo 的"服务端默认开启, // 必须显式发送 disabled"口径对齐,让行为确定性不依赖服务端隐式默认。 const wantThinking = request.params.thinkingEnabled === true && effort !== 'low'; body.chat_template_kwargs = { enable_thinking: wantThinking }; } // 停止序列 if (request.params.stopSequences?.length) { body.stop = request.params.stopSequences; } return body; } }