@weisiren000/oiiai 0.1.2 → 0.1.4

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/providers/__base__.ts","../src/providers/openrouter.ts"],"sourcesContent":["/**\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":"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","names":[]}
1
+ {"version":3,"sources":["../src/providers/openrouter.ts","../src/providers/__model-detection__.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/poe.ts","../src/providers/nova.ts","../src/providers/__factory__.ts"],"sourcesContent":["/**\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","/**\r\n * 模型特性自动检测与智能降级策略\r\n *\r\n * 解决问题:\r\n * 1. 思考模型(thinking models)在低 token 限制下 content 为空\r\n * 2. 模型聚合平台无法预知哪些是思考模型\r\n * 3. 避免硬编码模型列表\r\n *\r\n * 策略:\r\n * 1. 基于模型名称模式匹配(启发式检测)\r\n * 2. 基于响应特征动态检测(运行时检测)\r\n * 3. 智能降级:自动调整参数或提取有效内容\r\n */\r\n\r\nimport type { ChatResult, ChatOptions, ReasoningConfig } from './__types__';\r\n\r\n// ============ 模型特性类型 ============\r\n\r\n/**\r\n * 模型行为类型\r\n */\r\nexport type ModelBehavior =\r\n | 'thinking-first' // 思考优先:先输出 reasoning,content 可能延迟或为空\r\n | 'direct-answer' // 直接回答:主要输出 content\r\n | 'hybrid' // 混合模式:同时输出 reasoning 和 content\r\n | 'unknown'; // 未知\r\n\r\n/**\r\n * 模型特性信息\r\n */\r\nexport interface ModelCharacteristics {\r\n /** 模型行为类型 */\r\n behavior: ModelBehavior;\r\n /** 是否支持 reasoning 参数 */\r\n supportsReasoningConfig: boolean;\r\n /** 推荐的最小 maxTokens(针对思考模型) */\r\n recommendedMinTokens: number;\r\n /** 检测置信度 0-1 */\r\n confidence: number;\r\n /** 检测来源 */\r\n detectedBy: 'pattern' | 'runtime' | 'cache';\r\n}\r\n\r\n/**\r\n * 降级策略结果\r\n */\r\nexport interface FallbackResult {\r\n /** 最终返回的内容 */\r\n content: string;\r\n /** 是否触发了降级 */\r\n didFallback: boolean;\r\n /** 降级原因 */\r\n fallbackReason?: string;\r\n /** 原始 reasoning(如果有) */\r\n originalReasoning?: string | null;\r\n}\r\n\r\n// ============ 模型名称模式检测 ============\r\n\r\n/**\r\n * 思考模型的名称模式(启发式检测)\r\n * 这些模式用于初步判断,不是硬编码的模型列表\r\n *\r\n * 注意:模式按优先级排序,更具体的模式在前\r\n */\r\nconst THINKING_MODEL_PATTERNS: RegExp[] = [\r\n // 明确的思考/推理标识\r\n /[-_]think(?:ing)?(?:[-_:]|$)/i, // *-think, *-thinking\r\n /[-_]reason(?:ing)?(?:[-_:]|$)/i, // *-reason, *-reasoning\r\n /[-_]cot(?:[-_:]|$)/i, // chain-of-thought\r\n /[-_]reflect(?:ion)?(?:[-_:]|$)/i, // reflection models\r\n\r\n // 知名推理模型系列\r\n /\\bo1[-_]?/i, // OpenAI o1 系列\r\n /\\bo3[-_]?/i, // OpenAI o3 系列\r\n /\\br1[-_]?/i, // DeepSeek R1 等\r\n /\\bqwq\\b/i, // Qwen QwQ\r\n /\\bn1[-_]?/i, // nex-n1 等\r\n\r\n // 通用思考关键词(较低优先级)\r\n /think/i, // 包含 think\r\n];\r\n\r\n/**\r\n * 明确的直接回答模型模式\r\n * 注意:这些模式优先级低于思考模型模式\r\n */\r\nconst DIRECT_ANSWER_PATTERNS: RegExp[] = [\r\n /[-_]chat$/i, // *-chat (结尾)\r\n /[-_]instruct/i, // *-instruct\r\n /[-_]turbo/i, // *-turbo\r\n /[-_]flash/i, // gemini-flash 等快速模型\r\n /[-_]lite[-_v]/i, // lite 版本(但不匹配 lite 结尾,避免误判)\r\n /[-_]fast/i, // fast 模型\r\n];\r\n\r\n/**\r\n * 需要特殊处理的模型模式(可能返回空响应)\r\n */\r\nconst PROBLEMATIC_MODEL_PATTERNS: RegExp[] = [\r\n /nova[-_]?\\d*[-_]lite/i, // Amazon Nova Lite 系列\r\n];\r\n\r\n/**\r\n * 检查是否是已知的问题模型\r\n */\r\nexport function isProblematicModel(modelId: string): boolean {\r\n return PROBLEMATIC_MODEL_PATTERNS.some(pattern => pattern.test(modelId));\r\n}\r\n\r\n/**\r\n * 基于模型名称模式检测模型特性\r\n */\r\nexport function detectByModelName(modelId: string): ModelCharacteristics {\r\n const normalizedId = modelId.toLowerCase();\r\n\r\n // 检查是否匹配思考模型模式\r\n const isThinkingPattern = THINKING_MODEL_PATTERNS.some(pattern =>\r\n pattern.test(normalizedId)\r\n );\r\n\r\n // 检查是否匹配直接回答模式\r\n const isDirectPattern = DIRECT_ANSWER_PATTERNS.some(pattern =>\r\n pattern.test(normalizedId)\r\n );\r\n\r\n // 检查是否是问题模型\r\n const isProblematic = isProblematicModel(normalizedId);\r\n\r\n // 如果同时匹配两种模式,优先认为是思考模型(更保守的策略)\r\n if (isThinkingPattern) {\r\n return {\r\n behavior: 'thinking-first',\r\n supportsReasoningConfig: true,\r\n recommendedMinTokens: 500,\r\n confidence: 0.7,\r\n detectedBy: 'pattern',\r\n };\r\n }\r\n\r\n if (isDirectPattern) {\r\n return {\r\n behavior: 'direct-answer',\r\n supportsReasoningConfig: false,\r\n // 问题模型需要更多 token\r\n recommendedMinTokens: isProblematic ? 300 : 100,\r\n confidence: 0.6,\r\n detectedBy: 'pattern',\r\n };\r\n }\r\n\r\n // 未知模型,使用保守默认值\r\n return {\r\n behavior: 'unknown',\r\n supportsReasoningConfig: false,\r\n recommendedMinTokens: isProblematic ? 300 : 200,\r\n confidence: 0.3,\r\n detectedBy: 'pattern',\r\n };\r\n}\r\n\r\n// ============ 运行时特性检测 ============\r\n\r\n/**\r\n * 模型特性缓存(运行时学习)\r\n */\r\nconst modelCharacteristicsCache = new Map<string, ModelCharacteristics>();\r\n\r\n/**\r\n * 基于响应结果检测模型特性\r\n */\r\nexport function detectByResponse(\r\n modelId: string,\r\n result: ChatResult\r\n): ModelCharacteristics {\r\n const hasReasoning = !!result.reasoning && result.reasoning.length > 0;\r\n const hasContent = !!result.content && result.content.trim().length > 0;\r\n const reasoningLength = result.reasoning?.length ?? 0;\r\n const contentLength = result.content?.length ?? 0;\r\n\r\n let behavior: ModelBehavior;\r\n let supportsReasoningConfig = false;\r\n let recommendedMinTokens = 200;\r\n\r\n if (hasReasoning && !hasContent) {\r\n // 只有 reasoning,没有 content -> 典型的思考优先模型\r\n behavior = 'thinking-first';\r\n supportsReasoningConfig = true;\r\n recommendedMinTokens = Math.max(500, reasoningLength + 200);\r\n } else if (hasReasoning && hasContent) {\r\n // 两者都有\r\n if (reasoningLength > contentLength * 2) {\r\n // reasoning 明显更长 -> 思考优先\r\n behavior = 'thinking-first';\r\n supportsReasoningConfig = true;\r\n recommendedMinTokens = 500;\r\n } else {\r\n // 混合模式\r\n behavior = 'hybrid';\r\n supportsReasoningConfig = true;\r\n recommendedMinTokens = 300;\r\n }\r\n } else if (hasContent && !hasReasoning) {\r\n // 只有 content -> 直接回答模型\r\n behavior = 'direct-answer';\r\n supportsReasoningConfig = false;\r\n recommendedMinTokens = 100;\r\n } else {\r\n // 都没有 -> 可能是 token 限制太低\r\n behavior = 'unknown';\r\n recommendedMinTokens = 500;\r\n }\r\n\r\n const characteristics: ModelCharacteristics = {\r\n behavior,\r\n supportsReasoningConfig,\r\n recommendedMinTokens,\r\n confidence: 0.9,\r\n detectedBy: 'runtime',\r\n };\r\n\r\n // 缓存结果\r\n modelCharacteristicsCache.set(modelId, characteristics);\r\n\r\n return characteristics;\r\n}\r\n\r\n/**\r\n * 获取模型特性(优先使用缓存)\r\n */\r\nexport function getModelCharacteristics(modelId: string): ModelCharacteristics {\r\n // 优先使用运行时缓存\r\n const cached = modelCharacteristicsCache.get(modelId);\r\n if (cached) {\r\n return { ...cached, detectedBy: 'cache' };\r\n }\r\n\r\n // 否则使用模式匹配\r\n return detectByModelName(modelId);\r\n}\r\n\r\n// ============ 智能降级策略 ============\r\n\r\n/**\r\n * 降级策略配置\r\n */\r\nexport interface FallbackConfig {\r\n /** 是否启用自动降级 */\r\n enabled: boolean;\r\n /** 当 content 为空时,是否返回 reasoning */\r\n returnReasoningAsContent: boolean;\r\n /** 是否从 reasoning 中提取结论 */\r\n extractConclusionFromReasoning: boolean;\r\n /** 是否自动增加 maxTokens 重试 */\r\n autoRetryWithMoreTokens: boolean;\r\n /** 重试时的 token 增量 */\r\n retryTokenIncrement: number;\r\n /** 最大重试次数 */\r\n maxRetries: number;\r\n}\r\n\r\n/**\r\n * 默认降级配置\r\n */\r\nexport const DEFAULT_FALLBACK_CONFIG: FallbackConfig = {\r\n enabled: true,\r\n returnReasoningAsContent: true,\r\n extractConclusionFromReasoning: true,\r\n autoRetryWithMoreTokens: false, // 默认关闭自动重试,避免额外消耗\r\n retryTokenIncrement: 300,\r\n maxRetries: 2,\r\n};\r\n\r\n/**\r\n * 从 reasoning 中提取结论\r\n * 尝试找到最终答案或结论部分\r\n */\r\nexport function extractConclusionFromReasoning(reasoning: string): string | null {\r\n if (!reasoning) return null;\r\n\r\n // 常见的结论标记模式\r\n const conclusionPatterns = [\r\n /(?:therefore|thus|so|hence|finally|in conclusion|the answer is|result is)[:\\s]*(.+?)(?:\\n|$)/i,\r\n /(?:答案是|结论是|因此|所以|最终)[::\\s]*(.+?)(?:\\n|$)/,\r\n /(?:\\*\\*answer\\*\\*|\\*\\*result\\*\\*)[:\\s]*(.+?)(?:\\n|$)/i,\r\n /=\\s*(.+?)(?:\\n|$)/, // 数学等式结果\r\n ];\r\n\r\n for (const pattern of conclusionPatterns) {\r\n const match = reasoning.match(pattern);\r\n if (match && match[1]) {\r\n return match[1].trim();\r\n }\r\n }\r\n\r\n // 如果没找到明确结论,返回最后一段非空内容\r\n const paragraphs = reasoning.split(/\\n\\n+/).filter(p => p.trim());\r\n if (paragraphs.length > 0) {\r\n const lastParagraph = paragraphs[paragraphs.length - 1].trim();\r\n // 只返回较短的最后段落(可能是结论)\r\n if (lastParagraph.length < 500) {\r\n return lastParagraph;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * 应用降级策略处理响应结果\r\n */\r\nexport function applyFallbackStrategy(\r\n result: ChatResult,\r\n config: Partial<FallbackConfig> = {}\r\n): FallbackResult {\r\n const finalConfig = { ...DEFAULT_FALLBACK_CONFIG, ...config };\r\n\r\n // 如果已有有效 content,直接返回\r\n if (result.content && result.content.trim().length > 0) {\r\n return {\r\n content: result.content,\r\n didFallback: false,\r\n originalReasoning: result.reasoning,\r\n };\r\n }\r\n\r\n // content 为空,需要降级处理\r\n if (!finalConfig.enabled) {\r\n return {\r\n content: '',\r\n didFallback: false,\r\n originalReasoning: result.reasoning,\r\n };\r\n }\r\n\r\n // 尝试从 reasoning 提取结论\r\n if (finalConfig.extractConclusionFromReasoning && result.reasoning) {\r\n const conclusion = extractConclusionFromReasoning(result.reasoning);\r\n if (conclusion) {\r\n return {\r\n content: conclusion,\r\n didFallback: true,\r\n fallbackReason: 'extracted_conclusion_from_reasoning',\r\n originalReasoning: result.reasoning,\r\n };\r\n }\r\n }\r\n\r\n // 直接返回 reasoning 作为 content\r\n if (finalConfig.returnReasoningAsContent && result.reasoning) {\r\n return {\r\n content: result.reasoning,\r\n didFallback: true,\r\n fallbackReason: 'returned_reasoning_as_content',\r\n originalReasoning: result.reasoning,\r\n };\r\n }\r\n\r\n // 无法降级\r\n return {\r\n content: '',\r\n didFallback: false,\r\n fallbackReason: 'no_fallback_available',\r\n originalReasoning: result.reasoning,\r\n };\r\n}\r\n\r\n// ============ 智能参数调整 ============\r\n\r\n/**\r\n * 根据模型特性智能调整请求参数\r\n */\r\nexport function adjustOptionsForModel(\r\n modelId: string,\r\n options: ChatOptions\r\n): ChatOptions {\r\n const characteristics = getModelCharacteristics(modelId);\r\n\r\n // 如果是思考模型且 maxTokens 过低,自动调整\r\n if (\r\n characteristics.behavior === 'thinking-first' &&\r\n (!options.maxTokens || options.maxTokens < characteristics.recommendedMinTokens)\r\n ) {\r\n return {\r\n ...options,\r\n maxTokens: Math.max(\r\n options.maxTokens ?? 0,\r\n characteristics.recommendedMinTokens\r\n ),\r\n };\r\n }\r\n\r\n return options;\r\n}\r\n\r\n/**\r\n * 为思考模型生成推荐配置\r\n */\r\nexport function getRecommendedConfig(\r\n modelId: string,\r\n scenario: 'simple' | 'math' | 'reasoning' | 'fast' = 'simple'\r\n): Partial<ChatOptions> {\r\n const characteristics = getModelCharacteristics(modelId);\r\n\r\n if (characteristics.behavior !== 'thinking-first') {\r\n // 非思考模型,返回基础配置\r\n return {};\r\n }\r\n\r\n // 思考模型的场景化配置\r\n const configs: Record<string, Partial<ChatOptions>> = {\r\n simple: {\r\n maxTokens: 300,\r\n reasoning: { effort: 'low' },\r\n },\r\n math: {\r\n maxTokens: 600,\r\n reasoning: { effort: 'high' },\r\n },\r\n reasoning: {\r\n maxTokens: 800,\r\n reasoning: { effort: 'medium' },\r\n },\r\n fast: {\r\n maxTokens: 200,\r\n reasoning: { effort: 'off' },\r\n },\r\n };\r\n\r\n return configs[scenario] ?? configs.simple;\r\n}\r\n\r\n// ============ 导出工具函数 ============\r\n\r\nexport const ModelDetection = {\r\n detectByModelName,\r\n detectByResponse,\r\n getModelCharacteristics,\r\n applyFallbackStrategy,\r\n adjustOptionsForModel,\r\n getRecommendedConfig,\r\n extractConclusionFromReasoning,\r\n isProblematicModel,\r\n clearCache: () => modelCharacteristicsCache.clear(),\r\n};\r\n","/**\n * AI Provider 接口和基类\n */\n\nimport type {\n ChatOptions,\n ChatResult,\n StreamChunk,\n ModelInfo,\n} from './__types__';\nimport {\n ModelDetection,\n type FallbackConfig,\n type ModelCharacteristics,\n DEFAULT_FALLBACK_CONFIG,\n} from './__model-detection__';\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 */\n getModelCharacteristics?(modelId: string): ModelCharacteristics;\n}\n\n/**\n * 扩展的 ask 选项,支持降级配置\n */\nexport interface AskOptions extends Omit<ChatOptions, 'model' | 'messages'> {\n /** 降级策略配置 */\n fallback?: Partial<FallbackConfig>;\n /** 是否自动调整参数以适应模型特性 */\n autoAdjust?: boolean;\n}\n\n/**\n * AI Provider 基础抽象类\n * 提供一些通用实现,子类只需实现核心方法\n *\n * 特性:\n * - 自动检测模型类型(思考模型 vs 直接回答模型)\n * - 智能降级策略(content 为空时自动处理)\n * - 参数自动调整(为思考模型增加 maxTokens)\n */\nexport abstract class BaseProvider implements AIProvider {\n abstract readonly name: string;\n\n /** 降级策略配置 */\n protected fallbackConfig: FallbackConfig = DEFAULT_FALLBACK_CONFIG;\n\n /** 是否启用自动参数调整 */\n protected autoAdjustEnabled: boolean = true;\n\n abstract chat(options: ChatOptions): Promise<ChatResult>;\n\n abstract chatStream(\n options: ChatOptions\n ): AsyncGenerator<StreamChunk, void, unknown>;\n\n /**\n * 配置降级策略\n */\n configureFallback(config: Partial<FallbackConfig>): this {\n this.fallbackConfig = { ...this.fallbackConfig, ...config };\n return this;\n }\n\n /**\n * 启用/禁用自动参数调整\n */\n setAutoAdjust(enabled: boolean): this {\n this.autoAdjustEnabled = enabled;\n return this;\n }\n\n /**\n * 获取模型特性信息\n */\n getModelCharacteristics(modelId: string): ModelCharacteristics {\n return ModelDetection.getModelCharacteristics(modelId);\n }\n\n /**\n * 智能聊天:自动检测模型特性并应用降级策略\n */\n async chatSmart(options: ChatOptions): Promise<ChatResult> {\n // 自动调整参数\n const adjustedOptions = this.autoAdjustEnabled\n ? ModelDetection.adjustOptionsForModel(options.model, options)\n : options;\n\n const result = await this.chat(adjustedOptions);\n\n // 运行时检测并缓存模型特性\n ModelDetection.detectByResponse(options.model, result);\n\n return result;\n }\n\n /**\n * 简单对话:单轮问答(默认实现)\n *\n * 智能处理思考模型:\n * 1. 自动检测模型类型\n * 2. 为思考模型自动调整 maxTokens\n * 3. 如果 content 为空,智能降级(提取结论或返回 reasoning)\n */\n async ask(\n model: string,\n question: string,\n options?: AskOptions\n ): Promise<string> {\n const { fallback, autoAdjust = this.autoAdjustEnabled, ...chatOptions } = options ?? {};\n\n // 构建请求选项\n let finalOptions: ChatOptions = {\n model,\n messages: [{ role: 'user', content: question }],\n ...chatOptions,\n };\n\n // 自动调整参数\n if (autoAdjust) {\n finalOptions = ModelDetection.adjustOptionsForModel(model, finalOptions);\n }\n\n const result = await this.chat(finalOptions);\n\n // 运行时检测模型特性\n ModelDetection.detectByResponse(model, result);\n\n // 应用降级策略\n const fallbackResult = ModelDetection.applyFallbackStrategy(result, {\n ...this.fallbackConfig,\n ...fallback,\n });\n\n return fallbackResult.content;\n }\n\n /**\n * 带系统提示的对话(默认实现)\n *\n * 智能处理思考模型:\n * 1. 自动检测模型类型\n * 2. 为思考模型自动调整 maxTokens\n * 3. 如果 content 为空,智能降级(提取结论或返回 reasoning)\n */\n async askWithSystem(\n model: string,\n systemPrompt: string,\n userMessage: string,\n options?: AskOptions\n ): Promise<string> {\n const { fallback, autoAdjust = this.autoAdjustEnabled, ...chatOptions } = options ?? {};\n\n // 构建请求选项\n let finalOptions: ChatOptions = {\n model,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: userMessage },\n ],\n ...chatOptions,\n };\n\n // 自动调整参数\n if (autoAdjust) {\n finalOptions = ModelDetection.adjustOptionsForModel(model, finalOptions);\n }\n\n const result = await this.chat(finalOptions);\n\n // 运行时检测模型特性\n ModelDetection.detectByResponse(model, result);\n\n // 应用降级策略\n const fallbackResult = ModelDetection.applyFallbackStrategy(result, {\n ...this.fallbackConfig,\n ...fallback,\n });\n\n return fallbackResult.content;\n }\n\n /**\n * 场景化问答:根据场景自动配置参数\n *\n * @param model 模型 ID\n * @param question 问题\n * @param scenario 场景类型\n * - 'simple': 简单问答(默认)\n * - 'math': 数学计算\n * - 'reasoning': 逻辑推理\n * - 'fast': 快速回答(关闭思考)\n */\n async askWithScenario(\n model: string,\n question: string,\n scenario: 'simple' | 'math' | 'reasoning' | 'fast' = 'simple',\n options?: AskOptions\n ): Promise<string> {\n const recommendedConfig = ModelDetection.getRecommendedConfig(model, scenario);\n return this.ask(model, question, {\n ...recommendedConfig,\n ...options,\n });\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 * reasoning 参数说明:\n * - HuggingFace 是模型聚合平台,thinking 支持取决于具体模型\n * - 如果模型支持,会返回 reasoning_content\n */\n async chat(options: ChatOptions): Promise<ChatResult> {\n const { model, messages, temperature = 0.7, maxTokens, reasoning } = 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 // 传递 reasoning 参数(取决于具体模型是否支持)\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(`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, reasoning } = 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 // 传递 reasoning 参数(取决于具体模型是否支持)\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(`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 * - maxTokens 独立控制输出长度,不受 effort 影响\n */\n\nimport { BaseProvider } from './__base__';\nimport type {\n ChatOptions,\n ChatResult,\n StreamChunk,\n ReasoningConfig,\n} from './__types__';\n\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\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 * reasoning 参数说明:\n * - effort 不为 'off' 时启用 thinking 模式\n * - maxTokens 独立控制输出长度,不受 effort 影响\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 // maxTokens 独立控制输出长度\n if (maxTokens) {\n body.max_tokens = maxTokens;\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 const body: Record<string, unknown> = {\n model,\n messages,\n temperature,\n stream: true,\n };\n\n // maxTokens 独立控制输出长度\n if (maxTokens) {\n body.max_tokens = maxTokens;\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","/**\r\n * Poe Provider 实现\r\n * 使用 Poe API (OpenAI 兼容格式)\r\n * https://creator.poe.com/docs/external-applications/openai-compatible-api\r\n *\r\n * 支持模型:\r\n * - 所有 Poe 上的公开 bot,如 Claude-Opus-4.1, GPT-4o, Gemini-2.5-Pro 等\r\n * - 支持通过 extra_body 传递 reasoning_effort, thinking_budget 等参数\r\n *\r\n * 特点:\r\n * - 单一 API Key 访问数百个模型\r\n * - 使用 Poe 订阅点数,无需额外费用\r\n */\r\n\r\nimport { BaseProvider } from './__base__';\r\nimport type {\r\n ChatOptions,\r\n ChatResult,\r\n StreamChunk,\r\n ReasoningConfig,\r\n} from './__types__';\r\nimport { EFFORT_TOKEN_MAP } from './__types__';\r\n\r\nconst BASE_URL = 'https://api.poe.com/v1';\r\n\r\n/**\r\n * Poe Provider 配置\r\n */\r\nexport interface PoeConfig {\r\n apiKey: string;\r\n baseUrl?: string;\r\n}\r\n\r\n/**\r\n * 从 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' &&\r\n item !== null &&\r\n item.type === 'text' &&\r\n 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 * 从内容中提取思考内容\r\n * 支持多种格式:\r\n * 1. <think>...</think> 标签\r\n * 2. *Thinking...*\\n> ... 格式(DeepSeek 在 Poe 上的格式)\r\n */\r\nfunction extractThinkingFromContent(content: string): {\r\n thinking: string;\r\n content: string;\r\n} {\r\n // 格式1: <think>...</think> 标签\r\n const thinkMatch = content.match(/<think>([\\s\\S]*?)<\\/think>/);\r\n if (thinkMatch) {\r\n const thinking = thinkMatch[1].trim();\r\n const cleanContent = content.replace(/<think>[\\s\\S]*?<\\/think>/, '').trim();\r\n return { thinking, content: cleanContent };\r\n }\r\n\r\n // 格式2: *Thinking...*\\n> ... 格式\r\n // 匹配 *Thinking...* 开头,然后是 > 引用块\r\n const thinkingMatch = content.match(\r\n /^\\*Thinking\\.{0,3}\\*\\s*\\n((?:>.*(?:\\n|$))+)/\r\n );\r\n if (thinkingMatch) {\r\n // 提取 > 引用块内容,去掉 > 前缀\r\n const thinking = thinkingMatch[1]\r\n .split('\\n')\r\n .map(line => line.replace(/^>\\s?/, ''))\r\n .join('\\n')\r\n .trim();\r\n const cleanContent = content.replace(thinkingMatch[0], '').trim();\r\n return { thinking, content: cleanContent };\r\n }\r\n\r\n return { thinking: '', content };\r\n}\r\n\r\n/**\r\n * 构建 extra_body 参数(用于传递 reasoning 配置)\r\n */\r\nfunction buildExtraBody(\r\n reasoning?: ReasoningConfig\r\n): Record<string, unknown> | undefined {\r\n if (!reasoning || reasoning.effort === 'off') {\r\n return undefined;\r\n }\r\n\r\n const extraBody: Record<string, unknown> = {};\r\n\r\n // Poe 通过 extra_body 传递 reasoning_effort\r\n if (reasoning.effort) {\r\n extraBody.reasoning_effort = reasoning.effort;\r\n }\r\n\r\n // 设置 thinking_budget(budgetTokens 优先,否则使用 effort 映射)\r\n if (reasoning.budgetTokens !== undefined) {\r\n extraBody.thinking_budget = reasoning.budgetTokens;\r\n } else if (reasoning.effort && EFFORT_TOKEN_MAP[reasoning.effort]) {\r\n extraBody.thinking_budget = EFFORT_TOKEN_MAP[reasoning.effort];\r\n }\r\n\r\n return Object.keys(extraBody).length > 0 ? extraBody : undefined;\r\n}\r\n\r\n/**\r\n * Poe Provider\r\n * 使用 Poe API,兼容 OpenAI 格式\r\n */\r\nexport class PoeProvider extends BaseProvider {\r\n readonly name = 'poe';\r\n private apiKey: string;\r\n private baseUrl: string;\r\n\r\n constructor(config: PoeConfig | string) {\r\n super();\r\n if (typeof config === 'string') {\r\n this.apiKey = config;\r\n this.baseUrl = BASE_URL;\r\n } else {\r\n this.apiKey = config.apiKey;\r\n this.baseUrl = config.baseUrl ?? BASE_URL;\r\n }\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 body: Record<string, unknown> = {\r\n model,\r\n messages,\r\n temperature,\r\n stream: false,\r\n };\r\n\r\n if (maxTokens) {\r\n body.max_tokens = maxTokens;\r\n }\r\n\r\n // Poe 通过 extra_body 传递自定义参数\r\n const extraBody = buildExtraBody(reasoning);\r\n if (extraBody) {\r\n Object.assign(body, extraBody);\r\n }\r\n\r\n const response = await fetch(`${this.baseUrl}/chat/completions`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n Authorization: `Bearer ${this.apiKey}`,\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await response.text();\r\n throw new Error(`Poe API error: ${response.status} ${error}`);\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const result: any = await response.json();\r\n const choice = result.choices?.[0];\r\n\r\n if (!choice) {\r\n throw new Error('No response from model');\r\n }\r\n\r\n const msg = choice.message;\r\n // Poe 可能返回 reasoning_content(取决于底层模型)\r\n let reasoningContent = msg?.reasoning_content ?? null;\r\n let contentText = extractTextContent(msg?.content);\r\n\r\n // 如果没有 reasoning_content,尝试从 <think> 标签提取\r\n if (!reasoningContent && contentText) {\r\n const extracted = extractThinkingFromContent(contentText);\r\n if (extracted.thinking) {\r\n reasoningContent = extracted.thinking;\r\n contentText = extracted.content;\r\n }\r\n }\r\n\r\n return {\r\n content: contentText,\r\n reasoning: reasoningContent ? extractTextContent(reasoningContent) : null,\r\n model: result.model ?? model,\r\n usage: {\r\n promptTokens: result.usage?.prompt_tokens ?? 0,\r\n completionTokens: result.usage?.completion_tokens ?? 0,\r\n totalTokens: result.usage?.total_tokens ?? 0,\r\n },\r\n finishReason: choice.finish_reason ?? null,\r\n };\r\n }\r\n\r\n /**\r\n * 发送流式聊天请求\r\n */\r\n async *chatStream(\r\n options: ChatOptions\r\n ): AsyncGenerator<StreamChunk, void, unknown> {\r\n const { model, messages, temperature = 0.7, maxTokens, reasoning } = options;\r\n\r\n const body: Record<string, unknown> = {\r\n model,\r\n messages,\r\n temperature,\r\n stream: true,\r\n };\r\n\r\n if (maxTokens) {\r\n body.max_tokens = maxTokens;\r\n }\r\n\r\n // Poe 通过 extra_body 传递自定义参数\r\n const extraBody = buildExtraBody(reasoning);\r\n if (extraBody) {\r\n Object.assign(body, extraBody);\r\n }\r\n\r\n const response = await fetch(`${this.baseUrl}/chat/completions`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n Authorization: `Bearer ${this.apiKey}`,\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await response.text();\r\n throw new Error(`Poe API error: ${response.status} ${error}`);\r\n }\r\n\r\n const reader = response.body?.getReader();\r\n if (!reader) {\r\n throw new Error('No response body');\r\n }\r\n\r\n const decoder = new TextDecoder();\r\n let buffer = '';\r\n // 用于追踪思考模式状态\r\n // 'none' | 'think_tag' | 'markdown_thinking' | 'markdown_quote'\r\n let thinkingMode: 'none' | 'think_tag' | 'markdown_thinking' | 'markdown_quote' = 'none';\r\n let contentBuffer = '';\r\n\r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n const lines = buffer.split('\\n');\r\n buffer = lines.pop() ?? '';\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n if (!trimmed || trimmed === 'data: [DONE]') continue;\r\n if (!trimmed.startsWith('data: ')) continue;\r\n\r\n try {\r\n const data = JSON.parse(trimmed.slice(6));\r\n const delta = data.choices?.[0]?.delta;\r\n if (!delta) continue;\r\n\r\n // 思考内容(如果底层模型支持 reasoning_content)\r\n if (delta.reasoning_content) {\r\n yield {\r\n type: 'reasoning',\r\n text: extractTextContent(delta.reasoning_content),\r\n };\r\n continue;\r\n }\r\n\r\n // 处理 content\r\n if (delta.content) {\r\n const text = extractTextContent(delta.content);\r\n contentBuffer += text;\r\n\r\n // 检测并处理不同的思考格式\r\n // eslint-disable-next-line no-constant-condition\r\n while (true) {\r\n if (thinkingMode === 'none') {\r\n // 检测 <think> 标签\r\n const thinkStart = contentBuffer.indexOf('<think>');\r\n if (thinkStart !== -1) {\r\n if (thinkStart > 0) {\r\n yield { type: 'content', text: contentBuffer.slice(0, thinkStart) };\r\n }\r\n contentBuffer = contentBuffer.slice(thinkStart + 7);\r\n thinkingMode = 'think_tag';\r\n continue;\r\n }\r\n\r\n // 检测 *Thinking...* 格式\r\n const thinkingMatch = contentBuffer.match(/^\\*Thinking\\.{0,3}\\*\\s*\\n/);\r\n if (thinkingMatch) {\r\n contentBuffer = contentBuffer.slice(thinkingMatch[0].length);\r\n thinkingMode = 'markdown_thinking';\r\n continue;\r\n }\r\n\r\n // 没有思考标记,输出内容\r\n if (contentBuffer.length > 0) {\r\n // 保留可能不完整的标记\r\n const keepLen = Math.min(15, contentBuffer.length);\r\n const output = contentBuffer.slice(0, -keepLen) || '';\r\n if (output) {\r\n yield { type: 'content', text: output };\r\n contentBuffer = contentBuffer.slice(-keepLen);\r\n }\r\n }\r\n break;\r\n } else if (thinkingMode === 'think_tag') {\r\n // 在 <think> 标签内\r\n const endIdx = contentBuffer.indexOf('</think>');\r\n if (endIdx !== -1) {\r\n yield { type: 'reasoning', text: contentBuffer.slice(0, endIdx) };\r\n contentBuffer = contentBuffer.slice(endIdx + 8);\r\n thinkingMode = 'none';\r\n continue;\r\n }\r\n // 输出思考内容\r\n if (contentBuffer.length > 8) {\r\n yield { type: 'reasoning', text: contentBuffer.slice(0, -8) };\r\n contentBuffer = contentBuffer.slice(-8);\r\n }\r\n break;\r\n } else if (thinkingMode === 'markdown_thinking') {\r\n // 等待 > 引用块开始\r\n if (contentBuffer.startsWith('>')) {\r\n thinkingMode = 'markdown_quote';\r\n continue;\r\n }\r\n // 如果不是 > 开头,说明思考结束\r\n if (contentBuffer.length > 0 && !contentBuffer.startsWith('>')) {\r\n thinkingMode = 'none';\r\n continue;\r\n }\r\n break;\r\n } else if (thinkingMode === 'markdown_quote') {\r\n // 在 > 引用块内\r\n const newlineIdx = contentBuffer.indexOf('\\n');\r\n if (newlineIdx !== -1) {\r\n const quoteLine = contentBuffer.slice(0, newlineIdx);\r\n contentBuffer = contentBuffer.slice(newlineIdx + 1);\r\n\r\n // 如果是 > 开头,输出为思考内容\r\n if (quoteLine.startsWith('>')) {\r\n const thinkText = quoteLine.replace(/^>\\s?/, '');\r\n yield { type: 'reasoning', text: thinkText + '\\n' };\r\n continue;\r\n }\r\n\r\n // 如果是空行,继续等待(可能还有更多引用块)\r\n if (quoteLine.trim() === '') {\r\n yield { type: 'reasoning', text: '\\n' };\r\n continue;\r\n }\r\n\r\n // 非空非引用行,思考结束,这行是正文内容\r\n thinkingMode = 'none';\r\n yield { type: 'content', text: quoteLine + '\\n' };\r\n continue;\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n } catch {\r\n // 忽略解析错误\r\n }\r\n }\r\n }\r\n\r\n // 输出剩余内容\r\n if (contentBuffer.length > 0) {\r\n if (thinkingMode === 'think_tag' || thinkingMode === 'markdown_quote') {\r\n yield { type: 'reasoning', text: contentBuffer };\r\n } else {\r\n yield { type: 'content', text: contentBuffer };\r\n }\r\n }\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n }\r\n}\r\n","/**\r\n * AWS Nova Provider 实现\r\n * 使用 Amazon Nova API (OpenAI 兼容格式)\r\n * https://docs.aws.amazon.com/nova/\r\n *\r\n * 支持模型:\r\n * - nova-2-lite-v1: Nova 2 Lite 推理模型,支持 extended thinking\r\n * - nova-2-v1: Nova 2 标准模型\r\n * - nova-premier-v1: Nova Premier 高级模型\r\n *\r\n * 思考模式:\r\n * - Nova 2 Lite 支持 extended thinking (reasoningConfig)\r\n * - effort 映射为 maxReasoningEffort: low/medium/high\r\n */\r\n\r\nimport { BaseProvider } from './__base__';\r\nimport type { ChatOptions, ChatResult, StreamChunk } from './__types__';\r\n\r\nconst BASE_URL = 'https://api.nova.amazon.com/v1';\r\n\r\n/**\r\n * AWS Nova Provider 配置\r\n */\r\nexport interface NovaConfig {\r\n apiKey: string;\r\n baseUrl?: string;\r\n}\r\n\r\n/**\r\n * 从 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' &&\r\n item !== null &&\r\n item.type === 'text' &&\r\n 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 * AWS Nova Provider\r\n * 使用 Amazon Nova API,兼容 OpenAI 格式\r\n */\r\nexport class NovaProvider extends BaseProvider {\r\n readonly name = 'nova';\r\n private apiKey: string;\r\n private baseUrl: string;\r\n\r\n constructor(config: NovaConfig | string) {\r\n super();\r\n if (typeof config === 'string') {\r\n this.apiKey = config;\r\n this.baseUrl = BASE_URL;\r\n } else {\r\n this.apiKey = config.apiKey;\r\n this.baseUrl = config.baseUrl ?? BASE_URL;\r\n }\r\n }\r\n\r\n /**\r\n * 发送聊天请求(非流式)\r\n *\r\n * 注意:\r\n * - Nova API 的 temperature 范围是 0-1(不是 0-2)\r\n * - Nova 2 Lite 支持 extended thinking (reasoningConfig)\r\n * - effort 映射为 maxReasoningEffort\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 body: Record<string, unknown> = {\r\n model,\r\n messages,\r\n temperature,\r\n stream: false,\r\n };\r\n\r\n if (maxTokens) {\r\n body.max_tokens = maxTokens;\r\n }\r\n\r\n // Nova 使用 reasoningConfig 控制 extended thinking\r\n // 参考: https://docs.aws.amazon.com/nova/latest/nova2-userguide/extended-thinking.html\r\n if (reasoning?.effort && reasoning.effort !== 'off') {\r\n body.reasoningConfig = {\r\n type: 'enabled',\r\n maxReasoningEffort: reasoning.effort, // low/medium/high\r\n };\r\n }\r\n\r\n const response = await fetch(`${this.baseUrl}/chat/completions`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n Authorization: `Bearer ${this.apiKey}`,\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await response.text();\r\n throw new Error(`Nova API error: ${response.status} ${error}`);\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const result: any = await response.json();\r\n const choice = result.choices?.[0];\r\n\r\n if (!choice) {\r\n throw new Error('No response from model');\r\n }\r\n\r\n const msg = choice.message;\r\n // Nova 返回 reasoning_content 作为思考过程\r\n const reasoningContent = msg?.reasoning_content ?? null;\r\n\r\n return {\r\n content: extractTextContent(msg?.content),\r\n reasoning: reasoningContent ? extractTextContent(reasoningContent) : null,\r\n model: result.model ?? model,\r\n usage: {\r\n promptTokens: result.usage?.prompt_tokens ?? 0,\r\n completionTokens: result.usage?.completion_tokens ?? 0,\r\n totalTokens: result.usage?.total_tokens ?? 0,\r\n },\r\n finishReason: choice.finish_reason ?? null,\r\n };\r\n }\r\n\r\n /**\r\n * 发送流式聊天请求\r\n */\r\n async *chatStream(\r\n options: ChatOptions\r\n ): AsyncGenerator<StreamChunk, void, unknown> {\r\n const { model, messages, temperature = 0.7, maxTokens, reasoning } = options;\r\n\r\n const body: Record<string, unknown> = {\r\n model,\r\n messages,\r\n temperature,\r\n stream: true,\r\n };\r\n\r\n if (maxTokens) {\r\n body.max_tokens = maxTokens;\r\n }\r\n\r\n // Nova 使用 reasoningConfig 控制 extended thinking\r\n if (reasoning?.effort && reasoning.effort !== 'off') {\r\n body.reasoningConfig = {\r\n type: 'enabled',\r\n maxReasoningEffort: reasoning.effort,\r\n };\r\n }\r\n\r\n const response = await fetch(`${this.baseUrl}/chat/completions`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n Authorization: `Bearer ${this.apiKey}`,\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await response.text();\r\n throw new Error(`Nova API error: ${response.status} ${error}`);\r\n }\r\n\r\n const reader = response.body?.getReader();\r\n if (!reader) {\r\n throw new Error('No response body');\r\n }\r\n\r\n const decoder = new TextDecoder();\r\n let buffer = '';\r\n\r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n const lines = buffer.split('\\n');\r\n buffer = lines.pop() ?? '';\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n if (!trimmed || trimmed === 'data: [DONE]') continue;\r\n if (!trimmed.startsWith('data: ')) continue;\r\n\r\n try {\r\n const data = JSON.parse(trimmed.slice(6));\r\n const delta = data.choices?.[0]?.delta;\r\n if (!delta) continue;\r\n\r\n // 思考内容\r\n if (delta.reasoning_content) {\r\n yield {\r\n type: 'reasoning',\r\n text: extractTextContent(delta.reasoning_content),\r\n };\r\n }\r\n\r\n // 回答内容\r\n if (delta.content) {\r\n yield {\r\n type: 'content',\r\n text: extractTextContent(delta.content),\r\n };\r\n }\r\n } catch {\r\n // 忽略解析错误\r\n }\r\n }\r\n }\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n }\r\n}\r\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';\nimport { PoeProvider } from './poe';\nimport { NovaProvider } from './nova';\n\n/**\n * 支持的 Provider 类型\n */\nexport type ProviderType =\n | 'openrouter'\n | 'gemini'\n | 'groq'\n | 'huggingface'\n | 'modelscope'\n | 'deepseek'\n | 'poe'\n | 'nova';\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 case 'poe':\n return new PoeProvider(baseUrl ? { apiKey, baseUrl } : apiKey);\n\n case 'nova':\n return new NovaProvider(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 poe: (apiKey: string, baseUrl?: string) =>\n createProvider({ provider: 'poe', apiKey, baseUrl }),\n\n nova: (apiKey: string, baseUrl?: string) =>\n createProvider({ provider: 'nova', apiKey, baseUrl }),\n};\n"],"mappings":"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","names":["extractTextContent","BASE_URL","extractTextContent","BASE_URL","extractTextContent","BASE_URL","extractTextContent","BASE_URL","extractTextContent","BASE_URL","extractTextContent","BASE_URL","extractTextContent"]}
package/package.json CHANGED
@@ -1,55 +1,59 @@
1
- {
2
- "name": "@weisiren000/oiiai",
3
- "version": "0.1.2",
4
- "description": "统一的 AI Provider 接口封装,支持 OpenRouter、OpenAI、Anthropic 等",
5
- "main": "dist/index.js",
6
- "module": "dist/index.mjs",
7
- "types": "dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.mjs",
12
- "require": "./dist/index.js"
13
- }
14
- },
15
- "files": [
16
- "dist"
17
- ],
18
- "scripts": {
19
- "build": "tsup",
20
- "dev": "tsup --watch",
21
- "prepublishOnly": "npm run build",
22
- "test:openrouter": "tsx src/__tests__/openrouter.test.ts",
23
- "test:modelscope": "tsx src/__tests__/modelscope.test.ts",
24
- "test:huggingface": "tsx src/__tests__/huggingface.test.ts",
25
- "test:groq": "tsx src/__tests__/groq.test.ts",
26
- "test:gemini": "tsx src/__tests__/gemini.test.ts",
27
- "test:iflow": "tsx src/__tests__/iflow.test.ts"
28
- },
29
- "keywords": [
30
- "ai",
31
- "llm",
32
- "openrouter",
33
- "openai",
34
- "anthropic",
35
- "provider"
36
- ],
37
- "author": "",
38
- "license": "MIT",
39
- "dependencies": {
40
- "@openrouter/sdk": "^0.2.11"
41
- },
42
- "devDependencies": {
43
- "@types/node": "^25.0.2",
44
- "dotenv": "^16.0.0",
45
- "tsup": "^8.0.0",
46
- "tsx": "^4.0.0",
47
- "typescript": "^5.0.0"
48
- },
49
- "peerDependencies": {
50
- "typescript": ">=5.0.0"
51
- },
52
- "engines": {
53
- "node": ">=18.0.0"
54
- }
55
- }
1
+ {
2
+ "name": "@weisiren000/oiiai",
3
+ "version": "0.1.4",
4
+ "description": "统一的 AI Provider 接口封装,支持 OpenRouter、OpenAI、Anthropic 等",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsup",
20
+ "dev": "tsup --watch",
21
+ "prepublishOnly": "npm run build",
22
+ "format": "prettier --write .",
23
+ "format:check": "prettier --check .",
24
+ "test:openrouter": "tsx src/__tests__/openrouter.test.ts",
25
+ "test:modelscope": "tsx src/__tests__/modelscope.test.ts",
26
+ "test:huggingface": "tsx src/__tests__/huggingface.test.ts",
27
+ "test:groq": "tsx src/__tests__/groq.test.ts",
28
+ "test:gemini": "tsx src/__tests__/gemini.test.ts",
29
+ "test:nova": "tsx src/__tests__/nova.test.ts",
30
+ "test:nova-effort": "tsx src/__tests__/nova-effort.test.ts"
31
+ },
32
+ "keywords": [
33
+ "ai",
34
+ "llm",
35
+ "openrouter",
36
+ "openai",
37
+ "anthropic",
38
+ "provider"
39
+ ],
40
+ "author": "",
41
+ "license": "MIT",
42
+ "dependencies": {
43
+ "@openrouter/sdk": "^0.2.11"
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "^25.0.2",
47
+ "dotenv": "^16.0.0",
48
+ "prettier": "^3.7.4",
49
+ "tsup": "^8.0.0",
50
+ "tsx": "^4.0.0",
51
+ "typescript": "^5.0.0"
52
+ },
53
+ "peerDependencies": {
54
+ "typescript": ">=5.0.0"
55
+ },
56
+ "engines": {
57
+ "node": ">=18.0.0"
58
+ }
59
+ }