@weisiren000/oiiai 0.1.2 → 0.1.3
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.
- package/README.md +165 -201
- package/dist/index.d.mts +220 -11
- package/dist/index.d.ts +220 -11
- package/dist/index.js +874 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +866 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +57 -55
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/providers/__base__.ts","../src/providers/openrouter.ts"],"sourcesContent":["// 从 providers 模块导出所有内容\r\nexport {\r\n // 基类和接口\r\n BaseProvider,\r\n // Provider 实现\r\n OpenRouterProvider,\r\n} from './providers/__index__';\r\n\r\nexport type {\r\n // 接口\r\n AIProvider,\r\n // 类型\r\n ChatMessage,\r\n ChatOptions,\r\n ChatResult,\r\n ReasoningConfig,\r\n StreamChunk,\r\n TokenUsage,\r\n ModelInfo,\r\n ModelPricing,\r\n // Provider 特定类型\r\n OpenRouterModelInfo,\r\n} from './providers/__index__';\r\n","/**\r\n * AI Provider 接口和基类\r\n */\r\n\r\nimport type { ChatOptions, ChatResult, StreamChunk, ModelInfo } from './__types__';\r\n\r\n/**\r\n * AI Provider 基础接口\r\n * 所有 provider 实现都需要实现这个接口\r\n */\r\nexport interface AIProvider {\r\n /** Provider 名称 */\r\n readonly name: string;\r\n\r\n /**\r\n * 发送聊天请求(非流式)\r\n */\r\n chat(options: ChatOptions): Promise<ChatResult>;\r\n\r\n /**\r\n * 发送流式聊天请求\r\n */\r\n chatStream(options: ChatOptions): AsyncGenerator<StreamChunk, void, unknown>;\r\n\r\n /**\r\n * 简单对话:单轮问答\r\n */\r\n ask(model: string, question: string, options?: Omit<ChatOptions, 'model' | 'messages'>): Promise<string>;\r\n\r\n /**\r\n * 带系统提示的对话\r\n */\r\n askWithSystem(\r\n model: string,\r\n systemPrompt: string,\r\n userMessage: string,\r\n options?: Omit<ChatOptions, 'model' | 'messages'>\r\n ): Promise<string>;\r\n\r\n /**\r\n * 获取可用模型列表(可选实现)\r\n */\r\n listModels?(): Promise<ModelInfo[]>;\r\n}\r\n\r\n/**\r\n * AI Provider 基础抽象类\r\n * 提供一些通用实现,子类只需实现核心方法\r\n */\r\nexport abstract class BaseProvider implements AIProvider {\r\n abstract readonly name: string;\r\n\r\n abstract chat(options: ChatOptions): Promise<ChatResult>;\r\n\r\n abstract chatStream(options: ChatOptions): AsyncGenerator<StreamChunk, void, unknown>;\r\n\r\n /**\r\n * 简单对话:单轮问答(默认实现)\r\n * 对于思考模型,如果 content 为空则返回 reasoning\r\n */\r\n async ask(model: string, question: string, options?: Omit<ChatOptions, 'model' | 'messages'>): Promise<string> {\r\n const result = await this.chat({\r\n model,\r\n messages: [{ role: 'user', content: question }],\r\n ...options,\r\n });\r\n return result.content || result.reasoning || '';\r\n }\r\n\r\n /**\r\n * 带系统提示的对话(默认实现)\r\n * 对于思考模型,如果 content 为空则返回 reasoning\r\n */\r\n async askWithSystem(\r\n model: string,\r\n systemPrompt: string,\r\n userMessage: string,\r\n options?: Omit<ChatOptions, 'model' | 'messages'>\r\n ): Promise<string> {\r\n const result = await this.chat({\r\n model,\r\n messages: [\r\n { role: 'system', content: systemPrompt },\r\n { role: 'user', content: userMessage },\r\n ],\r\n ...options,\r\n });\r\n return result.content || result.reasoning || '';\r\n }\r\n}\r\n","/**\r\n * OpenRouter Provider 实现\r\n */\r\n\r\nimport { OpenRouter } from '@openrouter/sdk';\r\nimport { BaseProvider } from './__base__';\r\nimport type { ChatOptions, ChatResult, StreamChunk, ModelInfo, ReasoningConfig } from './__types__';\r\n\r\n/**\r\n * OpenRouter 扩展的模型信息\r\n */\r\nexport interface OpenRouterModelInfo extends ModelInfo {\r\n /** 规范化的 slug */\r\n canonicalSlug: string;\r\n /** 创建时间戳 */\r\n created: number;\r\n /** 架构信息 */\r\n architecture: {\r\n modality: string;\r\n inputModalities: string[];\r\n outputModalities: string[];\r\n tokenizer: string;\r\n instructType: string;\r\n };\r\n}\r\n\r\n/**\r\n * 从 SDK 返回的 content 中提取文本\r\n */\r\nfunction extractTextContent(content: unknown): string {\r\n if (typeof content === 'string') {\r\n return content;\r\n }\r\n if (Array.isArray(content)) {\r\n return content\r\n .filter(\r\n (item): item is { type: 'text'; text: string } =>\r\n typeof item === 'object' && item !== null && item.type === 'text' && typeof item.text === 'string'\r\n )\r\n .map((item) => item.text)\r\n .join('');\r\n }\r\n return '';\r\n}\r\n\r\n/**\r\n * 构建 reasoning 参数(转换为 API 需要的 snake_case 格式)\r\n */\r\nfunction buildReasoningParam(config?: ReasoningConfig): Record<string, unknown> | undefined {\r\n if (!config) return undefined;\r\n\r\n const param: Record<string, unknown> = {};\r\n\r\n if (config.effort !== undefined) {\r\n param.effort = config.effort;\r\n }\r\n if (config.maxTokens !== undefined) {\r\n param.max_tokens = config.maxTokens;\r\n }\r\n if (config.exclude !== undefined) {\r\n param.exclude = config.exclude;\r\n }\r\n if (config.enabled !== undefined) {\r\n param.enabled = config.enabled;\r\n }\r\n\r\n return Object.keys(param).length > 0 ? param : undefined;\r\n}\r\n\r\n\r\n/**\r\n * OpenRouter Provider\r\n */\r\nexport class OpenRouterProvider extends BaseProvider {\r\n readonly name = 'openrouter';\r\n private client: OpenRouter;\r\n\r\n constructor(apiKey: string) {\r\n super();\r\n this.client = new OpenRouter({ apiKey });\r\n }\r\n\r\n /**\r\n * 发送聊天请求(非流式)\r\n */\r\n async chat(options: ChatOptions): Promise<ChatResult> {\r\n const { model, messages, temperature = 0.7, maxTokens, reasoning } = options;\r\n\r\n const reasoningParam = buildReasoningParam(reasoning);\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const requestParams: any = {\r\n model,\r\n messages,\r\n temperature,\r\n maxTokens,\r\n stream: false,\r\n };\r\n\r\n if (reasoningParam) {\r\n requestParams.reasoning = reasoningParam;\r\n }\r\n\r\n const result = await this.client.chat.send(requestParams);\r\n\r\n const choice = result.choices[0];\r\n if (!choice) {\r\n throw new Error('No response from model');\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const msg = choice.message as any;\r\n const reasoningContent = msg.reasoning_content ?? msg.reasoning ?? null;\r\n\r\n return {\r\n content: extractTextContent(msg.content),\r\n reasoning: reasoningContent ? extractTextContent(reasoningContent) : null,\r\n model: result.model,\r\n usage: {\r\n promptTokens: result.usage?.promptTokens ?? 0,\r\n completionTokens: result.usage?.completionTokens ?? 0,\r\n totalTokens: result.usage?.totalTokens ?? 0,\r\n },\r\n finishReason: choice.finishReason,\r\n };\r\n }\r\n\r\n /**\r\n * 发送流式聊天请求\r\n */\r\n async *chatStream(options: ChatOptions): AsyncGenerator<StreamChunk, void, unknown> {\r\n const { model, messages, temperature = 0.7, maxTokens, reasoning } = options;\r\n\r\n const reasoningParam = buildReasoningParam(reasoning);\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const requestParams: any = {\r\n model,\r\n messages,\r\n temperature,\r\n maxTokens,\r\n stream: true,\r\n };\r\n\r\n if (reasoningParam) {\r\n requestParams.reasoning = reasoningParam;\r\n }\r\n\r\n const stream = (await this.client.chat.send(requestParams)) as unknown as AsyncIterable<{\r\n choices?: Array<{ delta?: unknown }>;\r\n }>;\r\n\r\n for await (const chunk of stream) {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const delta = chunk.choices?.[0]?.delta as any;\r\n if (!delta) continue;\r\n\r\n const reasoningContent = delta.reasoning_content ?? delta.reasoning;\r\n if (reasoningContent) {\r\n yield { type: 'reasoning', text: extractTextContent(reasoningContent) };\r\n }\r\n\r\n if (delta.content) {\r\n yield { type: 'content', text: extractTextContent(delta.content) };\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * 获取可用模型列表\r\n */\r\n async listModels(): Promise<OpenRouterModelInfo[]> {\r\n const result = await this.client.models.list();\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n return (result.data ?? []).map((m: any) => ({\r\n id: m.id,\r\n canonicalSlug: m.canonical_slug ?? m.id,\r\n name: m.name,\r\n description: m.description ?? '',\r\n created: m.created ?? 0,\r\n pricing: {\r\n prompt: m.pricing?.prompt ?? '0',\r\n completion: m.pricing?.completion ?? '0',\r\n request: m.pricing?.request ?? '0',\r\n image: m.pricing?.image ?? '0',\r\n },\r\n contextLength: m.context_length ?? 0,\r\n architecture: {\r\n modality: m.architecture?.modality ?? '',\r\n inputModalities: m.architecture?.input_modalities ?? [],\r\n outputModalities: m.architecture?.output_modalities ?? [],\r\n tokenizer: m.architecture?.tokenizer ?? '',\r\n instructType: m.architecture?.instruct_type ?? '',\r\n },\r\n supportedParameters: m.supported_parameters ?? [],\r\n }));\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACiDO,IAAe,eAAf,MAAkD;AAAA;AAAA;AAAA;AAAA;AAAA,EAWvD,MAAM,IAAI,OAAe,UAAkB,SAAoE;AAC7G,UAAM,SAAS,MAAM,KAAK,KAAK;AAAA,MAC7B;AAAA,MACA,UAAU,CAAC,EAAE,MAAM,QAAQ,SAAS,SAAS,CAAC;AAAA,MAC9C,GAAG;AAAA,IACL,CAAC;AACD,WAAO,OAAO,WAAW,OAAO,aAAa;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,cACJ,OACA,cACA,aACA,SACiB;AACjB,UAAM,SAAS,MAAM,KAAK,KAAK;AAAA,MAC7B;AAAA,MACA,UAAU;AAAA,QACR,EAAE,MAAM,UAAU,SAAS,aAAa;AAAA,QACxC,EAAE,MAAM,QAAQ,SAAS,YAAY;AAAA,MACvC;AAAA,MACA,GAAG;AAAA,IACL,CAAC;AACD,WAAO,OAAO,WAAW,OAAO,aAAa;AAAA,EAC/C;AACF;;;ACrFA,iBAA2B;AAyB3B,SAAS,mBAAmB,SAA0B;AACpD,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,WAAO,QACJ;AAAA,MACC,CAAC,SACC,OAAO,SAAS,YAAY,SAAS,QAAQ,KAAK,SAAS,UAAU,OAAO,KAAK,SAAS;AAAA,IAC9F,EACC,IAAI,CAAC,SAAS,KAAK,IAAI,EACvB,KAAK,EAAE;AAAA,EACZ;AACA,SAAO;AACT;AAKA,SAAS,oBAAoB,QAA+D;AAC1F,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,QAAiC,CAAC;AAExC,MAAI,OAAO,WAAW,QAAW;AAC/B,UAAM,SAAS,OAAO;AAAA,EACxB;AACA,MAAI,OAAO,cAAc,QAAW;AAClC,UAAM,aAAa,OAAO;AAAA,EAC5B;AACA,MAAI,OAAO,YAAY,QAAW;AAChC,UAAM,UAAU,OAAO;AAAA,EACzB;AACA,MAAI,OAAO,YAAY,QAAW;AAChC,UAAM,UAAU,OAAO;AAAA,EACzB;AAEA,SAAO,OAAO,KAAK,KAAK,EAAE,SAAS,IAAI,QAAQ;AACjD;AAMO,IAAM,qBAAN,cAAiC,aAAa;AAAA,EAC1C,OAAO;AAAA,EACR;AAAA,EAER,YAAY,QAAgB;AAC1B,UAAM;AACN,SAAK,SAAS,IAAI,sBAAW,EAAE,OAAO,CAAC;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAK,SAA2C;AACpD,UAAM,EAAE,OAAO,UAAU,cAAc,KAAK,WAAW,UAAU,IAAI;AAErE,UAAM,iBAAiB,oBAAoB,SAAS;AAGpD,UAAM,gBAAqB;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,IACV;AAEA,QAAI,gBAAgB;AAClB,oBAAc,YAAY;AAAA,IAC5B;AAEA,UAAM,SAAS,MAAM,KAAK,OAAO,KAAK,KAAK,aAAa;AAExD,UAAM,SAAS,OAAO,QAAQ,CAAC;AAC/B,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,wBAAwB;AAAA,IAC1C;AAGA,UAAM,MAAM,OAAO;AACnB,UAAM,mBAAmB,IAAI,qBAAqB,IAAI,aAAa;AAEnE,WAAO;AAAA,MACL,SAAS,mBAAmB,IAAI,OAAO;AAAA,MACvC,WAAW,mBAAmB,mBAAmB,gBAAgB,IAAI;AAAA,MACrE,OAAO,OAAO;AAAA,MACd,OAAO;AAAA,QACL,cAAc,OAAO,OAAO,gBAAgB;AAAA,QAC5C,kBAAkB,OAAO,OAAO,oBAAoB;AAAA,QACpD,aAAa,OAAO,OAAO,eAAe;AAAA,MAC5C;AAAA,MACA,cAAc,OAAO;AAAA,IACvB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,WAAW,SAAkE;AAClF,UAAM,EAAE,OAAO,UAAU,cAAc,KAAK,WAAW,UAAU,IAAI;AAErE,UAAM,iBAAiB,oBAAoB,SAAS;AAGpD,UAAM,gBAAqB;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,IACV;AAEA,QAAI,gBAAgB;AAClB,oBAAc,YAAY;AAAA,IAC5B;AAEA,UAAM,SAAU,MAAM,KAAK,OAAO,KAAK,KAAK,aAAa;AAIzD,qBAAiB,SAAS,QAAQ;AAEhC,YAAM,QAAQ,MAAM,UAAU,CAAC,GAAG;AAClC,UAAI,CAAC,MAAO;AAEZ,YAAM,mBAAmB,MAAM,qBAAqB,MAAM;AAC1D,UAAI,kBAAkB;AACpB,cAAM,EAAE,MAAM,aAAa,MAAM,mBAAmB,gBAAgB,EAAE;AAAA,MACxE;AAEA,UAAI,MAAM,SAAS;AACjB,cAAM,EAAE,MAAM,WAAW,MAAM,mBAAmB,MAAM,OAAO,EAAE;AAAA,MACnE;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA6C;AACjD,UAAM,SAAS,MAAM,KAAK,OAAO,OAAO,KAAK;AAG7C,YAAQ,OAAO,QAAQ,CAAC,GAAG,IAAI,CAAC,OAAY;AAAA,MAC1C,IAAI,EAAE;AAAA,MACN,eAAe,EAAE,kBAAkB,EAAE;AAAA,MACrC,MAAM,EAAE;AAAA,MACR,aAAa,EAAE,eAAe;AAAA,MAC9B,SAAS,EAAE,WAAW;AAAA,MACtB,SAAS;AAAA,QACP,QAAQ,EAAE,SAAS,UAAU;AAAA,QAC7B,YAAY,EAAE,SAAS,cAAc;AAAA,QACrC,SAAS,EAAE,SAAS,WAAW;AAAA,QAC/B,OAAO,EAAE,SAAS,SAAS;AAAA,MAC7B;AAAA,MACA,eAAe,EAAE,kBAAkB;AAAA,MACnC,cAAc;AAAA,QACZ,UAAU,EAAE,cAAc,YAAY;AAAA,QACtC,iBAAiB,EAAE,cAAc,oBAAoB,CAAC;AAAA,QACtD,kBAAkB,EAAE,cAAc,qBAAqB,CAAC;AAAA,QACxD,WAAW,EAAE,cAAc,aAAa;AAAA,QACxC,cAAc,EAAE,cAAc,iBAAiB;AAAA,MACjD;AAAA,MACA,qBAAqB,EAAE,wBAAwB,CAAC;AAAA,IAClD,EAAE;AAAA,EACJ;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/providers/openrouter.ts","../src/providers/__base__.ts","../src/providers/__types__.ts","../src/providers/gemini.ts","../src/providers/groq.ts","../src/providers/huggingface.ts","../src/providers/modelscope.ts","../src/providers/deepseek.ts","../src/providers/__factory__.ts"],"sourcesContent":["// 统一工厂(推荐)\nexport { createProvider, ai } from './providers/__index__';\nexport type { ProviderType, ProviderConfig } from './providers/__index__';\n\n// 基类和接口\nexport { BaseProvider } from './providers/__index__';\nexport type { AIProvider } from './providers/__index__';\n\n// 类型\nexport type {\n ChatMessage,\n ChatOptions,\n ChatResult,\n ReasoningConfig,\n ReasoningEffort,\n StreamChunk,\n TokenUsage,\n ModelInfo,\n ModelPricing,\n} from './providers/__index__';\n\nexport { EFFORT_TOKEN_MAP } from './providers/__index__';\n\n// Provider 实现(直接使用)\nexport {\n OpenRouterProvider,\n GeminiProvider,\n GroqProvider,\n HuggingFaceProvider,\n ModelScopeProvider,\n} from './providers/__index__';\n\nexport type { OpenRouterModelInfo } from './providers/__index__';\n","/**\n * OpenRouter Provider 实现\n */\n\nimport { OpenRouter } from '@openrouter/sdk';\nimport { BaseProvider } from './__base__';\nimport type {\n ChatOptions,\n ChatResult,\n StreamChunk,\n ModelInfo,\n ReasoningConfig,\n} from './__types__';\nimport { EFFORT_TOKEN_MAP } from './__types__';\n\n/**\n * OpenRouter 扩展的模型信息\n */\nexport interface OpenRouterModelInfo extends ModelInfo {\n /** 规范化的 slug */\n canonicalSlug: string;\n /** 创建时间戳 */\n created: number;\n /** 架构信息 */\n architecture: {\n modality: string;\n inputModalities: string[];\n outputModalities: string[];\n tokenizer: string;\n instructType: string;\n };\n}\n\n/**\n * 从 SDK 返回的 content 中提取文本\n */\nfunction extractTextContent(content: unknown): string {\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n return content\n .filter(\n (item): item is { type: 'text'; text: string } =>\n typeof item === 'object' &&\n item !== null &&\n item.type === 'text' &&\n typeof item.text === 'string'\n )\n .map(item => item.text)\n .join('');\n }\n return '';\n}\n\n/**\n * 构建 reasoning 参数(统一配置转换为 OpenRouter API 格式)\n */\nfunction buildReasoningParam(\n config?: ReasoningConfig\n): Record<string, unknown> | undefined {\n if (!config) return undefined;\n if (config.effort === 'off') return undefined;\n\n const param: Record<string, unknown> = {};\n\n // 设置 effort\n if (config.effort) {\n param.effort = config.effort;\n }\n\n // budgetTokens 优先,否则使用 effort 对应的默认值\n if (config.budgetTokens !== undefined) {\n param.max_tokens = config.budgetTokens;\n } else if (config.effort && EFFORT_TOKEN_MAP[config.effort]) {\n param.max_tokens = EFFORT_TOKEN_MAP[config.effort];\n }\n\n if (config.exclude !== undefined) {\n param.exclude = config.exclude;\n }\n\n return Object.keys(param).length > 0 ? param : undefined;\n}\n\n/**\n * OpenRouter Provider\n */\nexport class OpenRouterProvider extends BaseProvider {\n readonly name = 'openrouter';\n private client: OpenRouter;\n\n constructor(apiKey: string) {\n super();\n this.client = new OpenRouter({ apiKey });\n }\n\n /**\n * 发送聊天请求(非流式)\n */\n async chat(options: ChatOptions): Promise<ChatResult> {\n const {\n model,\n messages,\n temperature = 0.7,\n maxTokens,\n reasoning,\n } = options;\n\n const reasoningParam = buildReasoningParam(reasoning);\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const requestParams: any = {\n model,\n messages,\n temperature,\n maxTokens,\n stream: false,\n };\n\n if (reasoningParam) {\n requestParams.reasoning = reasoningParam;\n }\n\n const result = await this.client.chat.send(requestParams);\n\n const choice = result.choices[0];\n if (!choice) {\n throw new Error('No response from model');\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const msg = choice.message as any;\n const reasoningContent = msg.reasoning_content ?? msg.reasoning ?? null;\n\n return {\n content: extractTextContent(msg.content),\n reasoning: reasoningContent ? extractTextContent(reasoningContent) : null,\n model: result.model,\n usage: {\n promptTokens: result.usage?.promptTokens ?? 0,\n completionTokens: result.usage?.completionTokens ?? 0,\n totalTokens: result.usage?.totalTokens ?? 0,\n },\n finishReason: choice.finishReason,\n };\n }\n\n /**\n * 发送流式聊天请求\n */\n async *chatStream(\n options: ChatOptions\n ): AsyncGenerator<StreamChunk, void, unknown> {\n const {\n model,\n messages,\n temperature = 0.7,\n maxTokens,\n reasoning,\n } = options;\n\n const reasoningParam = buildReasoningParam(reasoning);\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const requestParams: any = {\n model,\n messages,\n temperature,\n maxTokens,\n stream: true,\n };\n\n if (reasoningParam) {\n requestParams.reasoning = reasoningParam;\n }\n\n const stream = (await this.client.chat.send(\n requestParams\n )) as unknown as AsyncIterable<{\n choices?: Array<{ delta?: unknown }>;\n }>;\n\n for await (const chunk of stream) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const delta = chunk.choices?.[0]?.delta as any;\n if (!delta) continue;\n\n const reasoningContent = delta.reasoning_content ?? delta.reasoning;\n if (reasoningContent) {\n yield { type: 'reasoning', text: extractTextContent(reasoningContent) };\n }\n\n if (delta.content) {\n yield { type: 'content', text: extractTextContent(delta.content) };\n }\n }\n }\n\n /**\n * 获取可用模型列表\n */\n async listModels(): Promise<OpenRouterModelInfo[]> {\n const result = await this.client.models.list();\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (result.data ?? []).map((m: any) => ({\n id: m.id,\n canonicalSlug: m.canonical_slug ?? m.id,\n name: m.name,\n description: m.description ?? '',\n created: m.created ?? 0,\n pricing: {\n prompt: m.pricing?.prompt ?? '0',\n completion: m.pricing?.completion ?? '0',\n request: m.pricing?.request ?? '0',\n image: m.pricing?.image ?? '0',\n },\n contextLength: m.context_length ?? 0,\n architecture: {\n modality: m.architecture?.modality ?? '',\n inputModalities: m.architecture?.input_modalities ?? [],\n outputModalities: m.architecture?.output_modalities ?? [],\n tokenizer: m.architecture?.tokenizer ?? '',\n instructType: m.architecture?.instruct_type ?? '',\n },\n supportedParameters: m.supported_parameters ?? [],\n }));\n }\n}\n","/**\n * AI Provider 接口和基类\n */\n\nimport type {\n ChatOptions,\n ChatResult,\n StreamChunk,\n ModelInfo,\n} from './__types__';\n\n/**\n * AI Provider 基础接口\n * 所有 provider 实现都需要实现这个接口\n */\nexport interface AIProvider {\n /** Provider 名称 */\n readonly name: string;\n\n /**\n * 发送聊天请求(非流式)\n */\n chat(options: ChatOptions): Promise<ChatResult>;\n\n /**\n * 发送流式聊天请求\n */\n chatStream(options: ChatOptions): AsyncGenerator<StreamChunk, void, unknown>;\n\n /**\n * 简单对话:单轮问答\n */\n ask(\n model: string,\n question: string,\n options?: Omit<ChatOptions, 'model' | 'messages'>\n ): Promise<string>;\n\n /**\n * 带系统提示的对话\n */\n askWithSystem(\n model: string,\n systemPrompt: string,\n userMessage: string,\n options?: Omit<ChatOptions, 'model' | 'messages'>\n ): Promise<string>;\n\n /**\n * 获取可用模型列表(可选实现)\n */\n listModels?(): Promise<ModelInfo[]>;\n}\n\n/**\n * AI Provider 基础抽象类\n * 提供一些通用实现,子类只需实现核心方法\n */\nexport abstract class BaseProvider implements AIProvider {\n abstract readonly name: string;\n\n abstract chat(options: ChatOptions): Promise<ChatResult>;\n\n abstract chatStream(\n options: ChatOptions\n ): AsyncGenerator<StreamChunk, void, unknown>;\n\n /**\n * 简单对话:单轮问答(默认实现)\n * 对于思考模型,如果 content 为空则返回 reasoning\n */\n async ask(\n model: string,\n question: string,\n options?: Omit<ChatOptions, 'model' | 'messages'>\n ): Promise<string> {\n const result = await this.chat({\n model,\n messages: [{ role: 'user', content: question }],\n ...options,\n });\n return result.content || result.reasoning || '';\n }\n\n /**\n * 带系统提示的对话(默认实现)\n * 对于思考模型,如果 content 为空则返回 reasoning\n */\n async askWithSystem(\n model: string,\n systemPrompt: string,\n userMessage: string,\n options?: Omit<ChatOptions, 'model' | 'messages'>\n ): Promise<string> {\n const result = await this.chat({\n model,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: userMessage },\n ],\n ...options,\n });\n return result.content || result.reasoning || '';\n }\n}\n","/**\n * AI Provider 统一类型定义\n */\n\n// ============ 消息类型 ============\n\nexport interface ChatMessage {\n role: 'system' | 'user' | 'assistant';\n content: string;\n}\n\n// ============ 思考/推理配置 ============\n\n/**\n * 统一的思考努力程度\n * - off: 关闭思考\n * - low: 快速思考,适合简单问题\n * - medium: 平衡模式(默认)\n * - high: 深度思考,适合复杂问题\n */\nexport type ReasoningEffort = 'off' | 'low' | 'medium' | 'high';\n\n/**\n * 统一的思考/推理配置\n *\n * 只需设置 effort,库会自动转换为各 Provider 需要的格式:\n * - OpenRouter: effort 参数\n * - Gemini: reasoning_effort 参数\n * - Groq: reasoning_effort 参数\n * - ModelScope: enable_thinking 参数\n *\n * @example\n * ```ts\n * // 简单用法 - 只设置 effort\n * { effort: 'high' }\n *\n * // 高级用法 - 精细控制\n * { effort: 'high', budgetTokens: 8000 }\n * ```\n */\nexport interface ReasoningConfig {\n /**\n * 思考努力程度(推荐使用)\n * - 'off': 关闭思考\n * - 'low': 快速思考\n * - 'medium': 平衡模式\n * - 'high': 深度思考\n */\n effort?: ReasoningEffort;\n\n /**\n * 思考 token 预算(可选,精细控制)\n * 设置后会覆盖 effort 对应的默认值\n * 仅部分 Provider 支持(OpenRouter)\n */\n budgetTokens?: number;\n\n /**\n * 是否在响应中排除思考内容\n * 仅部分 Provider 支持(OpenRouter)\n */\n exclude?: boolean;\n}\n\n/**\n * effort 到 token 预算的默认映射\n */\nexport const EFFORT_TOKEN_MAP: Record<ReasoningEffort, number> = {\n off: 0,\n low: 1024,\n medium: 4096,\n high: 16384,\n};\n\n// ============ 请求/响应类型 ============\n\nexport interface ChatOptions {\n /** 模型 ID */\n model: string;\n /** 对话消息列表 */\n messages: ChatMessage[];\n /** 温度参数 0-2 */\n temperature?: number;\n /** 最大输出 token 数 */\n maxTokens?: number;\n /** 思考/推理配置 */\n reasoning?: ReasoningConfig;\n}\n\nexport interface ChatResult {\n /** 最终回答内容 */\n content: string;\n /** 思考过程(仅 reasoning 模型有) */\n reasoning: string | null;\n /** 使用的模型 */\n model: string;\n /** Token 使用情况 */\n usage: TokenUsage;\n /** 完成原因 */\n finishReason: string | null;\n}\n\nexport interface TokenUsage {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n}\n\n// ============ 流式输出类型 ============\n\nexport interface StreamChunk {\n type: 'reasoning' | 'content';\n text: string;\n}\n\n// ============ 模型信息类型 ============\n\nexport interface ModelPricing {\n /** 输入 token 单价 ($/token) */\n prompt: string;\n /** 输出 token 单价 ($/token) */\n completion: string;\n /** 请求单价 */\n request: string;\n /** 图片单价 */\n image: string;\n}\n\nexport interface ModelInfo {\n /** 模型 ID */\n id: string;\n /** 模型名称 */\n name: string;\n /** 模型描述 */\n description: string;\n /** 定价信息 */\n pricing: ModelPricing;\n /** 上下文长度 */\n contextLength: number;\n /** 支持的参数 */\n supportedParameters: string[];\n}\n","/**\n * Gemini Provider 实现\n * 使用 Google Gemini API (OpenAI 兼容格式)\n * https://ai.google.dev/gemini-api/docs/openai\n */\n\nimport { BaseProvider } from './__base__';\nimport type { ChatOptions, ChatResult, StreamChunk } from './__types__';\n\nconst BASE_URL = 'https://generativelanguage.googleapis.com/v1beta/openai';\n\n/**\n * Gemini Provider 配置\n */\nexport interface GeminiConfig {\n apiKey: string;\n baseUrl?: string;\n}\n\n/**\n * 从 content 中提取文本\n */\nfunction extractTextContent(content: unknown): string {\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n return content\n .filter(\n (item): item is { type: 'text'; text: string } =>\n typeof item === 'object' &&\n item !== null &&\n item.type === 'text' &&\n typeof item.text === 'string'\n )\n .map(item => item.text)\n .join('');\n }\n return '';\n}\n\n/**\n * Gemini Provider\n * 使用 Google Gemini API,兼容 OpenAI 格式\n */\nexport class GeminiProvider extends BaseProvider {\n readonly name = 'gemini';\n private apiKey: string;\n private baseUrl: string;\n\n constructor(config: GeminiConfig | string) {\n super();\n if (typeof config === 'string') {\n this.apiKey = config;\n this.baseUrl = BASE_URL;\n } else {\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl ?? BASE_URL;\n }\n }\n\n /**\n * 发送聊天请求(非流式)\n */\n async chat(options: ChatOptions): Promise<ChatResult> {\n const {\n model,\n messages,\n temperature = 0.7,\n maxTokens,\n reasoning,\n } = options;\n\n const body: Record<string, unknown> = {\n model,\n messages,\n temperature,\n stream: false,\n };\n\n if (maxTokens) {\n body.max_tokens = maxTokens;\n }\n\n // Gemini 2.5+ 模型使用 reasoning_effort 控制思考\n // 参考: https://ai.google.dev/gemini-api/docs/text-generation\n // 支持的值: 'low', 'medium', 'high'\n if (reasoning?.effort && reasoning.effort !== 'off') {\n body.reasoning_effort = reasoning.effort;\n }\n\n const response = await fetch(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Gemini API error: ${response.status} ${error}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result: any = await response.json();\n const choice = result.choices?.[0];\n\n if (!choice) {\n throw new Error('No response from model');\n }\n\n const msg = choice.message;\n const reasoningContent = msg?.reasoning_content ?? null;\n\n return {\n content: extractTextContent(msg?.content),\n reasoning: reasoningContent ? extractTextContent(reasoningContent) : null,\n model: result.model ?? model,\n usage: {\n promptTokens: result.usage?.prompt_tokens ?? 0,\n completionTokens: result.usage?.completion_tokens ?? 0,\n totalTokens: result.usage?.total_tokens ?? 0,\n },\n finishReason: choice.finish_reason ?? null,\n };\n }\n\n /**\n * 发送流式聊天请求\n */\n async *chatStream(\n options: ChatOptions\n ): AsyncGenerator<StreamChunk, void, unknown> {\n const {\n model,\n messages,\n temperature = 0.7,\n maxTokens,\n reasoning,\n } = options;\n\n const body: Record<string, unknown> = {\n model,\n messages,\n temperature,\n stream: true,\n };\n\n if (maxTokens) {\n body.max_tokens = maxTokens;\n }\n\n // Gemini 2.5+ 模型使用 reasoning_effort 控制思考\n if (reasoning?.effort && reasoning.effort !== 'off') {\n body.reasoning_effort = reasoning.effort;\n }\n\n const response = await fetch(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Gemini API error: ${response.status} ${error}`);\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error('No response body');\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed === 'data: [DONE]') continue;\n if (!trimmed.startsWith('data: ')) continue;\n\n try {\n const data = JSON.parse(trimmed.slice(6));\n const delta = data.choices?.[0]?.delta;\n if (!delta) continue;\n\n // 思考内容 (Gemini 可能用 reasoning_content 或 thoughts)\n const thought = delta.reasoning_content ?? delta.thoughts;\n if (thought) {\n yield {\n type: 'reasoning',\n text: extractTextContent(thought),\n };\n }\n\n // 回答内容\n if (delta.content) {\n yield {\n type: 'content',\n text: extractTextContent(delta.content),\n };\n }\n } catch {\n // 忽略解析错误\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n}\n","/**\n * Groq Provider 实现\n * 使用 Groq API (OpenAI 兼容)\n */\n\nimport { BaseProvider } from './__base__';\nimport type { ChatOptions, ChatResult, StreamChunk } from './__types__';\n\nconst BASE_URL = 'https://api.groq.com/openai/v1';\n\n/**\n * Groq Provider 配置\n */\nexport interface GroqConfig {\n apiKey: string;\n baseUrl?: string;\n}\n\n/**\n * 从 content 中提取文本\n */\nfunction extractTextContent(content: unknown): string {\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n return content\n .filter(\n (item): item is { type: 'text'; text: string } =>\n typeof item === 'object' &&\n item !== null &&\n item.type === 'text' &&\n typeof item.text === 'string'\n )\n .map(item => item.text)\n .join('');\n }\n return '';\n}\n\n/**\n * Groq Provider\n * 兼容 OpenAI API 格式,支持 reasoning_effort 参数\n */\nexport class GroqProvider extends BaseProvider {\n readonly name = 'groq';\n private apiKey: string;\n private baseUrl: string;\n\n constructor(config: GroqConfig | string) {\n super();\n if (typeof config === 'string') {\n this.apiKey = config;\n this.baseUrl = BASE_URL;\n } else {\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl ?? BASE_URL;\n }\n }\n\n /**\n * 发送聊天请求(非流式)\n */\n async chat(options: ChatOptions): Promise<ChatResult> {\n const { model, messages, temperature = 1, maxTokens, reasoning } = options;\n\n const body: Record<string, unknown> = {\n model,\n messages,\n temperature,\n stream: false,\n top_p: 1,\n };\n\n if (maxTokens) {\n body.max_completion_tokens = maxTokens;\n }\n\n // Groq 使用 reasoning_format 参数控制推理输出\n // 参考: https://console.groq.com/docs/reasoning\n // reasoning_format: \"raw\" | \"parsed\" - 控制推理输出格式\n // 注意: 不能同时使用 include_reasoning 和 reasoning_format\n if (reasoning?.effort && reasoning.effort !== 'off') {\n body.reasoning_format = 'parsed';\n } else if (reasoning?.effort === 'off') {\n body.include_reasoning = false;\n }\n\n const response = await fetch(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Groq API error: ${response.status} ${error}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result: any = await response.json();\n const choice = result.choices?.[0];\n\n if (!choice) {\n throw new Error('No response from model');\n }\n\n const msg = choice.message;\n const reasoningContent = msg?.reasoning_content ?? msg?.reasoning ?? null;\n\n return {\n content: extractTextContent(msg?.content),\n reasoning: reasoningContent ? extractTextContent(reasoningContent) : null,\n model: result.model ?? model,\n usage: {\n promptTokens: result.usage?.prompt_tokens ?? 0,\n completionTokens: result.usage?.completion_tokens ?? 0,\n totalTokens: result.usage?.total_tokens ?? 0,\n },\n finishReason: choice.finish_reason ?? null,\n };\n }\n\n /**\n * 发送流式聊天请求\n */\n async *chatStream(\n options: ChatOptions\n ): AsyncGenerator<StreamChunk, void, unknown> {\n const { model, messages, temperature = 1, maxTokens, reasoning } = options;\n\n const body: Record<string, unknown> = {\n model,\n messages,\n temperature,\n stream: true,\n top_p: 1,\n };\n\n if (maxTokens) {\n body.max_completion_tokens = maxTokens;\n }\n\n // Groq 使用 reasoning_format 参数控制推理输出\n // 注意: 不能同时使用 include_reasoning 和 reasoning_format\n if (reasoning?.effort && reasoning.effort !== 'off') {\n body.reasoning_format = 'parsed';\n } else if (reasoning?.effort === 'off') {\n body.include_reasoning = false;\n }\n\n const response = await fetch(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Groq API error: ${response.status} ${error}`);\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error('No response body');\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed === 'data: [DONE]') continue;\n if (!trimmed.startsWith('data: ')) continue;\n\n try {\n const data = JSON.parse(trimmed.slice(6));\n const delta = data.choices?.[0]?.delta;\n if (!delta) continue;\n\n // 思考内容\n const reasoningContent = delta.reasoning_content ?? delta.reasoning;\n if (reasoningContent) {\n yield {\n type: 'reasoning',\n text: extractTextContent(reasoningContent),\n };\n }\n\n // 回答内容\n if (delta.content) {\n yield {\n type: 'content',\n text: extractTextContent(delta.content),\n };\n }\n } catch {\n // 忽略解析错误\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n}\n","/**\n * HuggingFace Provider 实现\n * 使用 HuggingFace Router API (OpenAI 兼容)\n */\n\nimport { BaseProvider } from './__base__';\nimport type { ChatOptions, ChatResult, StreamChunk } from './__types__';\n\nconst BASE_URL = 'https://router.huggingface.co/v1';\n\n/**\n * HuggingFace Provider 配置\n */\nexport interface HuggingFaceConfig {\n apiKey: string;\n baseUrl?: string;\n}\n\n/**\n * 从 content 中提取文本\n */\nfunction extractTextContent(content: unknown): string {\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n return content\n .filter(\n (item): item is { type: 'text'; text: string } =>\n typeof item === 'object' &&\n item !== null &&\n item.type === 'text' &&\n typeof item.text === 'string'\n )\n .map(item => item.text)\n .join('');\n }\n return '';\n}\n\n/**\n * HuggingFace Provider\n * 使用 HuggingFace Router,兼容 OpenAI API 格式\n */\nexport class HuggingFaceProvider extends BaseProvider {\n readonly name = 'huggingface';\n private apiKey: string;\n private baseUrl: string;\n\n constructor(config: HuggingFaceConfig | string) {\n super();\n if (typeof config === 'string') {\n this.apiKey = config;\n this.baseUrl = BASE_URL;\n } else {\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl ?? BASE_URL;\n }\n }\n\n /**\n * 发送聊天请求(非流式)\n */\n async chat(options: ChatOptions): Promise<ChatResult> {\n const { model, messages, temperature = 0.7, maxTokens } = options;\n\n const body: Record<string, unknown> = {\n model,\n messages,\n temperature,\n stream: false,\n };\n\n if (maxTokens) {\n body.max_tokens = maxTokens;\n }\n\n const response = await fetch(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`HuggingFace API error: ${response.status} ${error}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result: any = await response.json();\n const choice = result.choices?.[0];\n\n if (!choice) {\n throw new Error('No response from model');\n }\n\n const msg = choice.message;\n const reasoningContent = msg?.reasoning_content ?? null;\n\n return {\n content: extractTextContent(msg?.content),\n reasoning: reasoningContent ? extractTextContent(reasoningContent) : null,\n model: result.model ?? model,\n usage: {\n promptTokens: result.usage?.prompt_tokens ?? 0,\n completionTokens: result.usage?.completion_tokens ?? 0,\n totalTokens: result.usage?.total_tokens ?? 0,\n },\n finishReason: choice.finish_reason ?? null,\n };\n }\n\n /**\n * 发送流式聊天请求\n */\n async *chatStream(\n options: ChatOptions\n ): AsyncGenerator<StreamChunk, void, unknown> {\n const { model, messages, temperature = 0.7, maxTokens } = options;\n\n const body: Record<string, unknown> = {\n model,\n messages,\n temperature,\n stream: true,\n };\n\n if (maxTokens) {\n body.max_tokens = maxTokens;\n }\n\n const response = await fetch(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`HuggingFace API error: ${response.status} ${error}`);\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error('No response body');\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed === 'data: [DONE]') continue;\n if (!trimmed.startsWith('data: ')) continue;\n\n try {\n const data = JSON.parse(trimmed.slice(6));\n const delta = data.choices?.[0]?.delta;\n if (!delta) continue;\n\n // 思考内容\n if (delta.reasoning_content) {\n yield {\n type: 'reasoning',\n text: extractTextContent(delta.reasoning_content),\n };\n }\n\n // 回答内容\n if (delta.content) {\n yield {\n type: 'content',\n text: extractTextContent(delta.content),\n };\n }\n } catch {\n // 忽略解析错误\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n}\n","/**\n * ModelScope Provider 实现\n * 使用 OpenAI 兼容 API\n */\n\nimport { BaseProvider } from './__base__';\nimport type { ChatOptions, ChatResult, StreamChunk } from './__types__';\n\nconst BASE_URL = 'https://api-inference.modelscope.cn/v1';\n\n/**\n * ModelScope Provider 配置\n */\nexport interface ModelScopeConfig {\n apiKey: string;\n baseUrl?: string;\n}\n\n/**\n * 从 content 中提取文本\n */\nfunction extractTextContent(content: unknown): string {\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n return content\n .filter(\n (item): item is { type: 'text'; text: string } =>\n typeof item === 'object' &&\n item !== null &&\n item.type === 'text' &&\n typeof item.text === 'string'\n )\n .map(item => item.text)\n .join('');\n }\n return '';\n}\n\n/**\n * ModelScope Provider\n * 兼容 OpenAI API 格式,支持 DeepSeek 等模型\n */\nexport class ModelScopeProvider extends BaseProvider {\n readonly name = 'modelscope';\n private apiKey: string;\n private baseUrl: string;\n\n constructor(config: ModelScopeConfig | string) {\n super();\n if (typeof config === 'string') {\n this.apiKey = config;\n this.baseUrl = BASE_URL;\n } else {\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl ?? BASE_URL;\n }\n }\n\n /**\n * 发送聊天请求(非流式)\n */\n async chat(options: ChatOptions): Promise<ChatResult> {\n const {\n model,\n messages,\n temperature = 0.7,\n maxTokens,\n reasoning,\n } = options;\n\n const body: Record<string, unknown> = {\n model,\n messages,\n temperature,\n stream: false,\n };\n\n if (maxTokens) {\n body.max_tokens = maxTokens;\n }\n\n // ModelScope 使用 enable_thinking 控制思考\n // 参考: https://www.alibabacloud.com/help/en/model-studio/deepseek-api\n // 只在用户明确设置时才添加该参数\n if (reasoning?.effort) {\n if (reasoning.effort === 'off') {\n body.enable_thinking = false;\n } else {\n body.enable_thinking = true;\n }\n }\n\n const response = await fetch(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`ModelScope API error: ${response.status} ${error}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result: any = await response.json();\n const choice = result.choices?.[0];\n\n if (!choice) {\n throw new Error('No response from model');\n }\n\n const msg = choice.message;\n const reasoningContent = msg?.reasoning_content ?? null;\n\n return {\n content: extractTextContent(msg?.content),\n reasoning: reasoningContent ? extractTextContent(reasoningContent) : null,\n model: result.model ?? model,\n usage: {\n promptTokens: result.usage?.prompt_tokens ?? 0,\n completionTokens: result.usage?.completion_tokens ?? 0,\n totalTokens: result.usage?.total_tokens ?? 0,\n },\n finishReason: choice.finish_reason ?? null,\n };\n }\n\n /**\n * 发送流式聊天请求\n */\n async *chatStream(\n options: ChatOptions\n ): AsyncGenerator<StreamChunk, void, unknown> {\n const {\n model,\n messages,\n temperature = 0.7,\n maxTokens,\n reasoning,\n } = options;\n\n const body: Record<string, unknown> = {\n model,\n messages,\n temperature,\n stream: true,\n };\n\n if (maxTokens) {\n body.max_tokens = maxTokens;\n }\n\n // ModelScope 使用 enable_thinking 控制思考\n // 只在用户明确设置时才添加该参数\n if (reasoning?.effort) {\n if (reasoning.effort === 'off') {\n body.enable_thinking = false;\n } else {\n body.enable_thinking = true;\n }\n }\n\n const response = await fetch(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`ModelScope API error: ${response.status} ${error}`);\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error('No response body');\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed === 'data: [DONE]') continue;\n if (!trimmed.startsWith('data: ')) continue;\n\n try {\n const data = JSON.parse(trimmed.slice(6));\n const delta = data.choices?.[0]?.delta;\n if (!delta) continue;\n\n // 思考内容\n if (delta.reasoning_content) {\n yield {\n type: 'reasoning',\n text: extractTextContent(delta.reasoning_content),\n };\n }\n\n // 回答内容\n if (delta.content) {\n yield {\n type: 'content',\n text: extractTextContent(delta.content),\n };\n }\n } catch {\n // 忽略解析错误\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n}\n","/**\n * DeepSeek Provider 实现\n * 使用 DeepSeek API (OpenAI 兼容格式)\n * https://api-docs.deepseek.com/\n *\n * 支持模型:\n * - deepseek-chat: DeepSeek-V3 通用对话模型(可通过 thinking 参数启用思考)\n * - deepseek-reasoner: DeepSeek-R1 推理模型(自动启用思考)\n *\n * 思考模式:\n * - 使用 reasoning.effort 不为 'off' 时,会启用 thinking 模式\n * - effort 映射为 max_tokens 控制思考量:low=1024, medium=4096, high=16384\n */\n\nimport { BaseProvider } from './__base__';\nimport type {\n ChatOptions,\n ChatResult,\n StreamChunk,\n ReasoningConfig,\n} from './__types__';\nimport { EFFORT_TOKEN_MAP } from './__types__';\n\nconst BASE_URL = 'https://api.deepseek.com';\n\n/**\n * DeepSeek Provider 配置\n */\nexport interface DeepSeekConfig {\n apiKey: string;\n baseUrl?: string;\n}\n\n/**\n * 根据 reasoning 配置计算 max_tokens\n * budgetTokens 优先,否则使用 effort 映射\n */\nfunction getReasoningMaxTokens(\n reasoning?: ReasoningConfig,\n userMaxTokens?: number\n): number | undefined {\n if (!reasoning || reasoning.effort === 'off') {\n return userMaxTokens;\n }\n\n // budgetTokens 优先\n if (reasoning.budgetTokens !== undefined) {\n return reasoning.budgetTokens;\n }\n\n // 使用 effort 映射\n if (reasoning.effort) {\n return EFFORT_TOKEN_MAP[reasoning.effort];\n }\n\n return userMaxTokens;\n}\n\n/**\n * 从 content 中提取文本\n */\nfunction extractTextContent(content: unknown): string {\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n return content\n .filter(\n (item): item is { type: 'text'; text: string } =>\n typeof item === 'object' &&\n item !== null &&\n item.type === 'text' &&\n typeof item.text === 'string'\n )\n .map(item => item.text)\n .join('');\n }\n return '';\n}\n\n/**\n * DeepSeek Provider\n * 使用 DeepSeek API,兼容 OpenAI 格式\n */\nexport class DeepSeekProvider extends BaseProvider {\n readonly name = 'deepseek';\n private apiKey: string;\n private baseUrl: string;\n\n constructor(config: DeepSeekConfig | string) {\n super();\n if (typeof config === 'string') {\n this.apiKey = config;\n this.baseUrl = BASE_URL;\n } else {\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl ?? BASE_URL;\n }\n }\n\n /**\n * 发送聊天请求(非流式)\n */\n async chat(options: ChatOptions): Promise<ChatResult> {\n const {\n model,\n messages,\n temperature = 0.7,\n maxTokens,\n reasoning,\n } = options;\n\n // 计算 max_tokens(包含思考 token)\n const effectiveMaxTokens = getReasoningMaxTokens(reasoning, maxTokens);\n\n const body: Record<string, unknown> = {\n model,\n messages,\n temperature,\n stream: false,\n };\n\n if (effectiveMaxTokens) {\n body.max_tokens = effectiveMaxTokens;\n }\n\n // 如果 effort 不为 'off',启用 thinking 模式\n if (reasoning?.effort && reasoning.effort !== 'off') {\n body.thinking = { type: 'enabled' };\n }\n\n const response = await fetch(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`DeepSeek API error: ${response.status} ${error}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result: any = await response.json();\n const choice = result.choices?.[0];\n\n if (!choice) {\n throw new Error('No response from model');\n }\n\n const msg = choice.message;\n // DeepSeek R1 使用 reasoning_content 返回思考过程\n const reasoningContent = msg?.reasoning_content ?? null;\n\n return {\n content: extractTextContent(msg?.content),\n reasoning: reasoningContent ? extractTextContent(reasoningContent) : null,\n model: result.model ?? model,\n usage: {\n promptTokens: result.usage?.prompt_tokens ?? 0,\n completionTokens: result.usage?.completion_tokens ?? 0,\n totalTokens: result.usage?.total_tokens ?? 0,\n },\n finishReason: choice.finish_reason ?? null,\n };\n }\n\n /**\n * 发送流式聊天请求\n */\n async *chatStream(\n options: ChatOptions\n ): AsyncGenerator<StreamChunk, void, unknown> {\n const {\n model,\n messages,\n temperature = 0.7,\n maxTokens,\n reasoning,\n } = options;\n\n // 计算 max_tokens(包含思考 token)\n const effectiveMaxTokens = getReasoningMaxTokens(reasoning, maxTokens);\n\n const body: Record<string, unknown> = {\n model,\n messages,\n temperature,\n stream: true,\n };\n\n if (effectiveMaxTokens) {\n body.max_tokens = effectiveMaxTokens;\n }\n\n // 如果 effort 不为 'off',启用 thinking 模式\n if (reasoning?.effort && reasoning.effort !== 'off') {\n body.thinking = { type: 'enabled' };\n }\n\n const response = await fetch(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`DeepSeek API error: ${response.status} ${error}`);\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error('No response body');\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed === 'data: [DONE]') continue;\n if (!trimmed.startsWith('data: ')) continue;\n\n try {\n const data = JSON.parse(trimmed.slice(6));\n const delta = data.choices?.[0]?.delta;\n if (!delta) continue;\n\n // DeepSeek R1 推理模型的思考内容\n if (delta.reasoning_content) {\n yield {\n type: 'reasoning',\n text: extractTextContent(delta.reasoning_content),\n };\n }\n\n // 回答内容\n if (delta.content) {\n yield {\n type: 'content',\n text: extractTextContent(delta.content),\n };\n }\n } catch {\n // 忽略解析错误\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n}\n","/**\n * 统一的 Provider 工厂\n * 让所有 Provider 使用方式一致\n */\n\nimport type { AIProvider } from './__base__';\nimport { OpenRouterProvider } from './openrouter';\nimport { GeminiProvider } from './gemini';\nimport { GroqProvider } from './groq';\nimport { HuggingFaceProvider } from './huggingface';\nimport { ModelScopeProvider } from './modelscope';\nimport { DeepSeekProvider } from './deepseek';\n\n/**\n * 支持的 Provider 类型\n */\nexport type ProviderType =\n | 'openrouter'\n | 'gemini'\n | 'groq'\n | 'huggingface'\n | 'modelscope'\n | 'deepseek';\n\n/**\n * 统一的 Provider 配置\n */\nexport interface ProviderConfig {\n /** Provider 类型 */\n provider: ProviderType;\n /** API Key */\n apiKey: string;\n /** 自定义 API 地址(可选) */\n baseUrl?: string;\n}\n\n/**\n * 创建 AI Provider 实例\n *\n * @example\n * ```ts\n * // 所有 Provider 使用相同方式创建\n * const openrouter = createProvider({ provider: 'openrouter', apiKey: 'xxx' });\n * const gemini = createProvider({ provider: 'gemini', apiKey: 'xxx' });\n * const groq = createProvider({ provider: 'groq', apiKey: 'xxx' });\n *\n * // 之后使用方式完全一致\n * const answer = await openrouter.ask('gpt-4o', '你好');\n * const answer = await gemini.ask('gemini-2.5-flash', '你好');\n * ```\n */\nexport function createProvider(config: ProviderConfig): AIProvider {\n const { provider, apiKey, baseUrl } = config;\n\n switch (provider) {\n case 'openrouter':\n return new OpenRouterProvider(apiKey);\n\n case 'gemini':\n return new GeminiProvider(baseUrl ? { apiKey, baseUrl } : apiKey);\n\n case 'groq':\n return new GroqProvider(baseUrl ? { apiKey, baseUrl } : apiKey);\n\n case 'huggingface':\n return new HuggingFaceProvider(baseUrl ? { apiKey, baseUrl } : apiKey);\n\n case 'modelscope':\n return new ModelScopeProvider(baseUrl ? { apiKey, baseUrl } : apiKey);\n\n case 'deepseek':\n return new DeepSeekProvider(baseUrl ? { apiKey, baseUrl } : apiKey);\n\n default:\n throw new Error(`Unknown provider: ${provider}`);\n }\n}\n\n/**\n * 快捷创建函数\n */\nexport const ai = {\n openrouter: (apiKey: string, baseUrl?: string) =>\n createProvider({ provider: 'openrouter', apiKey, baseUrl }),\n\n gemini: (apiKey: string, baseUrl?: string) =>\n createProvider({ provider: 'gemini', apiKey, baseUrl }),\n\n groq: (apiKey: string, baseUrl?: string) =>\n createProvider({ provider: 'groq', apiKey, baseUrl }),\n\n huggingface: (apiKey: string, baseUrl?: string) =>\n createProvider({ provider: 'huggingface', apiKey, baseUrl }),\n\n modelscope: (apiKey: string, baseUrl?: string) =>\n createProvider({ provider: 'modelscope', apiKey, baseUrl }),\n\n deepseek: (apiKey: string, baseUrl?: string) =>\n createProvider({ provider: 'deepseek', apiKey, baseUrl }),\n};\n"],"mappings":"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","names":["extractTextContent","BASE_URL","extractTextContent","BASE_URL","extractTextContent","BASE_URL","extractTextContent","BASE_URL","extractTextContent"]}
|