diff --git a/packages/aiCore/AI_SDK_ARCHITECTURE.md b/packages/aiCore/AI_SDK_ARCHITECTURE.md new file mode 100644 index 0000000000..e6316571d9 --- /dev/null +++ b/packages/aiCore/AI_SDK_ARCHITECTURE.md @@ -0,0 +1,688 @@ +# Cherry Studio AI Core 基于 Vercel AI SDK 的技术架构 + +## 1. 架构设计理念 + +### 1.1 设计目标 +- **统一接口**:使用 Vercel AI SDK 统一不同 AI Provider 的接口差异 +- **动态导入**:通过动态导入实现按需加载,减少打包体积 +- **最小包装**:直接使用 AI SDK 的类型和接口,避免重复定义 +- **中间件增强**:扩大中间件的介入范围,覆盖请求的全生命周期(规划中) +- **类型安全**:利用 TypeScript 和 AI SDK 的类型系统确保类型安全 +- **轻量级**:专注核心功能,保持包的轻量和高效 +- **包级独立**:作为独立包管理,便于复用和维护 + +### 1.2 核心优势 +- **标准化**:AI SDK 提供统一的模型接口,减少适配工作 +- **简化维护**:废弃复杂的 XxxApiClient,统一为工厂函数模式 +- **更好的开发体验**:完整的 TypeScript 支持和丰富的生态系统 +- **性能优化**:AI SDK 内置优化和最佳实践 +- **模块化设计**:独立包结构,支持跨项目复用 +- **可扩展中间件**:支持在请求全生命周期中插入自定义逻辑 + +## 2. 整体架构图 + +```mermaid +graph TD + subgraph "Cherry Studio 主应用" + UI["用户界面"] + Components["React 组件"] + end + + subgraph "packages/aiCore (AI Core 包)" + ApiClientFactory["ApiClientFactory (工厂类)"] + UniversalClient["UniversalAiSdkClient (统一客户端)"] + ProviderRegistry["Provider 注册表"] + MiddlewareChain["中间件链 (规划中)"] + end + + subgraph "动态导入层" + DynamicImport["动态导入"] + end + + subgraph "Vercel AI SDK" + AICore["ai (核心库)"] + OpenAI["@ai-sdk/openai"] + Anthropic["@ai-sdk/anthropic"] + Google["@ai-sdk/google"] + XAI["@ai-sdk/xai"] + Others["其他 19+ Providers"] + end + + subgraph "中间件生态 (规划中)" + PreRequest["请求预处理"] + StreamTransform["流转换"] + PostProcess["后处理"] + ErrorHandle["错误处理"] + Logging["日志记录"] + Cache["缓存"] + end + + UI --> ApiClientFactory + Components --> ApiClientFactory + ApiClientFactory --> UniversalClient + UniversalClient --> MiddlewareChain + MiddlewareChain --> ProviderRegistry + ProviderRegistry --> DynamicImport + DynamicImport --> OpenAI + DynamicImport --> Anthropic + DynamicImport --> Google + DynamicImport --> XAI + DynamicImport --> Others + + UniversalClient --> AICore + AICore --> streamText + AICore --> generateText + + MiddlewareChain --> PreRequest + MiddlewareChain --> StreamTransform + MiddlewareChain --> PostProcess + MiddlewareChain --> ErrorHandle + MiddlewareChain --> Logging + MiddlewareChain --> Cache +``` + +## 3. 包结构设计 + +### 3.1 包级文件结构(当前简化版 + 规划) + +``` +packages/aiCore/ +├── src/ +│ ├── providers/ +│ │ ├── registry.ts # Provider 注册表 ✅ +│ │ └── types.ts # 核心类型定义 ✅ +│ ├── clients/ +│ │ ├── UniversalAiSdkClient.ts # 统一AI SDK客户端 ✅ +│ │ └── ApiClientFactory.ts # 客户端工厂 ✅ +│ ├── middleware/ # 中间件系统 (规划中) +│ │ ├── lifecycle/ # 生命周期中间件 +│ │ │ ├── PreRequestMiddleware.ts +│ │ │ ├── PostResponseMiddleware.ts +│ │ │ ├── ErrorHandlingMiddleware.ts +│ │ │ └── CacheMiddleware.ts +│ │ ├── core/ # 核心中间件 +│ │ │ ├── StreamProcessingMiddleware.ts +│ │ │ ├── RequestValidationMiddleware.ts +│ │ │ └── ResponseTransformMiddleware.ts +│ │ ├── feat/ # 特性中间件 +│ │ │ ├── ThinkingMiddleware.ts +│ │ │ ├── ToolCallMiddleware.ts +│ │ │ └── WebSearchMiddleware.ts +│ │ ├── builder.ts # 中间件构建器 +│ │ ├── composer.ts # 中间件组合器 +│ │ ├── register.ts # 中间件注册表 +│ │ └── types.ts # 中间件类型定义 +│ ├── services/ # 高级服务 (规划中) +│ │ ├── AiCoreService.ts # 统一服务入口 +│ │ ├── CompletionsService.ts # 文本生成服务 +│ │ ├── EmbeddingService.ts # 嵌入服务 +│ │ └── ImageService.ts # 图像生成服务 +│ └── index.ts # 包主入口文件 ✅ +├── package.json # 包配置文件 ✅ +├── tsconfig.json # TypeScript 配置 ✅ +├── README.md # 包说明文档 ✅ +└── AI_SDK_ARCHITECTURE.md # 本文档 ✅ +``` + +**图例:** +- ✅ 已实现 +- 规划中:设计完成,待实现 + +### 3.2 包配置 (package.json) + +```json +{ + "name": "@cherry-studio/ai-core", + "version": "1.0.0", + "description": "Cherry Studio AI Core - 基于 Vercel AI SDK 的统一 AI Provider 接口", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "dependencies": { + "ai": "^4.3.16" + }, + "peerDependenciesMeta": { + "@ai-sdk/openai": { "optional": true }, + "@ai-sdk/anthropic": { "optional": true }, + "@ai-sdk/google": { "optional": true }, + "@ai-sdk/xai": { "optional": true } + }, + "keywords": [ + "ai", "sdk", "vercel-ai-sdk", "cherry-studio" + ] +} +``` + +## 4. 核心组件详解 + +### 4.1 Provider 注册表 (`providers/registry.ts`) + +统一管理所有 AI Provider 的注册和动态导入。 + +**主要功能:** +- 动态导入 AI SDK providers +- 提供统一的 Provider 创建接口 +- 支持 19+ 官方 AI SDK providers +- 类型安全的 Provider 配置 + +**核心 API:** +```typescript +export interface ProviderConfig { + id: string + name: string + import: () => Promise + creatorFunctionName: string +} + +export class AiProviderRegistry { + getProvider(id: string): ProviderConfig | undefined + getAllProviders(): ProviderConfig[] + isSupported(id: string): boolean + registerProvider(config: ProviderConfig): void +} +``` + +**支持的 Providers:** +- OpenAI, Anthropic, Google, XAI +- Azure OpenAI, Amazon Bedrock, Google Vertex +- Groq, Together.ai, Fireworks, DeepSeek +- Cerebras, DeepInfra, Replicate, Perplexity +- Cohere, Fal AI, Vercel (19+ providers) + +### 4.2 统一AI SDK客户端 (`clients/UniversalAiSdkClient.ts`) + +将不同 AI providers 包装为统一接口。 + +**主要功能:** +- 异步初始化和动态加载 +- 统一的 stream() 和 generate() 方法 +- 直接使用 AI SDK 的 streamText() 和 generateText() +- 配置验证和错误处理 + +**核心 API:** +```typescript +export class UniversalAiSdkClient { + async initialize(): Promise + isInitialized(): boolean + async stream(request: any): Promise + async generate(request: any): Promise + validateConfig(): boolean + getProviderInfo(): { id: string; name: string; isInitialized: boolean } +} +``` + +### 4.3 客户端工厂 (`clients/ApiClientFactory.ts`) + +统一创建和管理 AI SDK 客户端。 + +**主要功能:** +- 统一的客户端创建接口 +- 智能缓存和复用机制 +- 批量创建和健康检查 +- 错误处理和重试 + +**核心 API:** +```typescript +export class ApiClientFactory { + static async createAiSdkClient(providerId: string, options: any): Promise + static getCachedClient(providerId: string, options: any): UniversalAiSdkClient | undefined + static clearCache(): void + static async healthCheck(): Promise + static getSupportedProviders(): ProviderInfo[] +} +``` + +### 4.4 增强的中间件系统 (规划中) + +扩展中间件架构,支持请求全生命周期的介入。 + +**生命周期阶段:** +1. **Pre-Request**:请求预处理、参数验证、缓存检查 +2. **Request**:实际的 AI SDK 调用 +3. **Stream Processing**:流式响应处理、实时转换 +4. **Post-Response**:响应后处理、结果聚合 +5. **Error Handling**:错误处理、重试、降级 + +**中间件分类:** + +**生命周期中间件:** +- `PreRequestMiddleware`:请求前处理,参数验证、权限检查 +- `PostResponseMiddleware`:响应后处理,结果转换、统计记录 +- `ErrorHandlingMiddleware`:错误处理,重试机制、降级策略 +- `CacheMiddleware`:缓存中间件,请求缓存、结果缓存 + +**核心中间件:** +- `StreamProcessingMiddleware`:流式处理,chunk 转换、进度追踪 +- `RequestValidationMiddleware`:请求验证,schema 验证、安全检查 +- `ResponseTransformMiddleware`:响应转换,格式标准化、类型转换 + +**特性中间件:** +- `ThinkingMiddleware`:思考过程中间件,记录推理步骤 +- `ToolCallMiddleware`:工具调用中间件,函数调用处理 +- `WebSearchMiddleware`:网络搜索中间件,集成搜索功能 + +**中间件 API 设计:** +```typescript +export interface Middleware { + name: string + priority: number + execute(context: MiddlewareContext, next: () => Promise): Promise +} + +export interface MiddlewareContext { + request: AiCoreRequest + response?: AiCoreResponse + error?: Error + metadata: Record + provider: string + model: string +} + +export class MiddlewareChain { + use(middleware: Middleware): this + compose(): (context: MiddlewareContext) => Promise + execute(context: MiddlewareContext): Promise +} +``` + +### 4.5 统一服务接口 (规划中) + +作为包的主要对外接口,提供高级 AI 功能。 + +**服务方法:** +- `completions()`: 文本生成 +- `streamCompletions()`: 流式文本生成 +- `generateObject()`: 结构化数据生成 +- `generateImage()`: 图像生成 +- `embed()`: 文本嵌入 + +**API 设计:** +```typescript +export class AiCoreService { + constructor(middlewares?: Middleware[]) + + async completions(request: CompletionRequest): Promise + async streamCompletions(request: CompletionRequest): Promise + async generateObject(request: ObjectGenerationRequest): Promise + async generateImage(request: ImageGenerationRequest): Promise + async embed(request: EmbeddingRequest): Promise + + use(middleware: Middleware): this + configure(config: AiCoreConfig): this +} +``` + +## 5. 使用方式 + +### 5.1 基础用法 + +```typescript +import { createAiSdkClient } from '@cherry-studio/ai-core' + +// 创建 OpenAI 客户端 +const client = await createAiSdkClient('openai', { + apiKey: 'your-api-key' +}) + +// 流式生成 +const result = await client.stream({ + modelId: 'gpt-4', + messages: [{ role: 'user', content: 'Hello!' }] +}) + +// 非流式生成 +const response = await client.generate({ + modelId: 'gpt-4', + messages: [{ role: 'user', content: 'Hello!' }] +}) +``` + +### 5.2 便捷函数 + +```typescript +import { createOpenAIClient, streamGeneration } from '@cherry-studio/ai-core' + +// 快速创建特定 provider 客户端 +const client = await createOpenAIClient({ + apiKey: 'your-api-key' +}) + +// 便捷的一次性调用 +const result = await streamGeneration( + 'anthropic', + 'claude-3-sonnet', + [{ role: 'user', content: 'Hello!' }], + { apiKey: 'your-api-key' } +) +``` + +### 5.3 多 Provider 支持 + +```typescript +import { createAiSdkClient, AiCore } from '@cherry-studio/ai-core' + +// 检查支持的 providers +const providers = AiCore.getSupportedProviders() +console.log(`支持 ${providers.length} 个 AI providers`) + +// 创建多个 provider 客户端 +const openai = await createAiSdkClient('openai', { apiKey: 'openai-key' }) +const anthropic = await createAiSdkClient('anthropic', { apiKey: 'anthropic-key' }) +const google = await createAiSdkClient('google', { apiKey: 'google-key' }) +const xai = await createAiSdkClient('xai', { apiKey: 'xai-key' }) +``` + +### 5.4 在 Cherry Studio 中集成 + +```typescript +// 替换现有的 XxxApiClient +// 之前: +// const openaiClient = new OpenAIApiClient(config) +// const anthropicClient = new AnthropicApiClient(config) + +// 现在: +import { createAiSdkClient } from '@cherry-studio/ai-core' + +const createProviderClient = async (provider: CherryProvider) => { + return await createAiSdkClient(provider.id, { + apiKey: provider.apiKey, + baseURL: provider.baseURL + }) +} +``` + +### 5.5 中间件使用 (规划中) + +```typescript +import { + AiCoreService, + ThinkingMiddleware, + CacheMiddleware, + LoggingMiddleware +} from '@cherry-studio/ai-core' + +// 创建带中间件的服务 +const aiService = new AiCoreService() + .use(new CacheMiddleware({ ttl: 3600 })) + .use(new LoggingMiddleware({ level: 'info' })) + .use(new ThinkingMiddleware({ recordSteps: true })) + +// 使用增强的服务 +const result = await aiService.streamCompletions({ + provider: 'openai', + model: 'gpt-4', + messages: [{ role: 'user', content: 'Explain quantum computing' }], + middleware: { + thinking: { enabled: true }, + cache: { enabled: true, key: 'quantum-explanation' } + } +}) + +// 自定义中间件 +class CustomMiddleware implements Middleware { + name = 'custom' + priority = 100 + + async execute(context: MiddlewareContext, next: () => Promise): Promise { + console.log('Before request:', context.request) + + await next() // 执行下一个中间件或实际请求 + + console.log('After response:', context.response) + } +} + +aiService.use(new CustomMiddleware()) +``` + +### 5.6 完整的工作流示例 (规划中) + +```typescript +import { + createAiSdkClient, + AiCoreService, + MiddlewareChain, + PreRequestMiddleware, + StreamProcessingMiddleware, + PostResponseMiddleware +} from '@cherry-studio/ai-core' + +// 创建完整的工作流 +const createEnhancedAiService = async () => { + // 创建中间件链 + const middlewareChain = new MiddlewareChain() + .use(new PreRequestMiddleware({ + validateApiKey: true, + checkRateLimit: true + })) + .use(new StreamProcessingMiddleware({ + enableProgressTracking: true, + chunkTransform: (chunk) => ({ + ...chunk, + timestamp: Date.now() + }) + })) + .use(new PostResponseMiddleware({ + saveToHistory: true, + calculateMetrics: true + })) + + // 创建服务实例 + const service = new AiCoreService(middlewareChain.middlewares) + + return service +} + +// 使用增强服务 +const enhancedService = await createEnhancedAiService() + +const response = await enhancedService.completions({ + provider: 'anthropic', + model: 'claude-3-sonnet', + messages: [ + { role: 'user', content: 'Write a technical blog post about AI middleware' } + ], + options: { + temperature: 0.7, + maxTokens: 2000 + }, + middleware: { + // 中间件特定配置 + thinking: { recordSteps: true }, + cache: { enabled: true, ttl: 1800 }, + logging: { level: 'debug' } + } +}) +``` + +## 6. 与现有架构的对比 + +| 方面 | 现有架构 | 新架构 (AI Core 包) | +|------|----------|-------------------| +| **代码组织** | 集成在主应用中 | 独立包,模块化管理 | +| **Provider 管理** | 各自独立的 XxxApiClient | 统一的 Provider 注册表 + 工厂 | +| **接口标准化** | 手动适配各 Provider 差异 | AI SDK 统一接口 | +| **类型安全** | 部分类型安全 | 完整的 TypeScript 支持 | +| **维护成本** | 每个 Provider 需要单独维护 | 统一维护,新 Provider 快速接入 | +| **包体积** | 所有 Provider 都打包 | 按需加载,动态导入 | +| **复用性** | 仅限当前项目 | 可跨项目复用 | +| **扩展性** | 添加新 Provider 复杂 | 只需在注册表中添加配置 | + +## 7. 简化设计原则 + +### 7.1 最小包装原则 +- 直接使用 AI SDK 的类型,不重复定义 +- 避免过度抽象和复杂的中间层 +- 保持与 AI SDK 原生 API 的一致性 + +### 7.2 动态导入优化 +```typescript +// 按需加载,减少打包体积 +const module = await import('@ai-sdk/openai') +const createOpenAI = module.createOpenAI +``` + +### 7.3 类型安全 +```typescript +// 直接使用 AI SDK 类型 +import { streamText, generateText } from 'ai' + +// 避免重复定义,直接传递参数 +return streamText({ model, ...request }) +``` + +### 7.4 配置简化 +```typescript +// 简化的 Provider 配置 +interface ProviderConfig { + id: string // provider 标识 + name: string // 显示名称 + import: () => Promise // 动态导入函数 + creatorFunctionName: string // 创建函数名 +} +``` + +## 8. 技术要点 + +### 8.1 动态导入策略 +- **按需加载**:只加载用户实际使用的 providers +- **缓存机制**:避免重复导入和初始化 +- **错误处理**:优雅处理导入失败的情况 + +### 8.2 依赖管理策略 +- **核心依赖**:`ai` 库作为必需依赖 +- **可选依赖**:所有 `@ai-sdk/*` 包都是可选的 +- **版本兼容**:支持 AI SDK v3-v5 版本 + +### 8.3 缓存策略 +- **客户端缓存**:基于 provider + options 的智能缓存 +- **配置哈希**:安全的 API key 哈希处理 +- **生命周期管理**:支持缓存清理和验证 + +## 9. 迁移策略 + +### 9.1 阶段一:包基础搭建 (Week 1) ✅ 已完成 +1. ✅ 创建简化的包结构 +2. ✅ 实现 Provider 注册表 +3. ✅ 创建统一客户端和工厂 +4. ✅ 配置构建和类型系统 + +### 9.2 阶段二:核心功能完善 (Week 2) ✅ 已完成 +1. ✅ 支持 19+ 官方 AI SDK providers +2. ✅ 实现缓存和错误处理 +3. ✅ 完善类型安全和 API 设计 +4. ✅ 添加便捷函数和工具 + +### 9.3 阶段三:集成测试 (Week 3) 🔄 进行中 +1. 在 Cherry Studio 中集成测试 +2. 功能完整性验证 +3. 性能基准测试 +4. 兼容性问题修复 + +### 9.4 阶段四:中间件系统实现 (Week 4-5) 📋 规划中 +1. **中间件核心架构** + - 实现 `MiddlewareChain` 和 `MiddlewareContext` + - 创建中间件接口和基础类型 + - 建立中间件生命周期管理 + +2. **生命周期中间件** + - `PreRequestMiddleware`:请求预处理 + - `PostResponseMiddleware`:响应后处理 + - `ErrorHandlingMiddleware`:错误处理 + - `CacheMiddleware`:缓存机制 + +3. **核心中间件** + - `StreamProcessingMiddleware`:流式处理 + - `RequestValidationMiddleware`:请求验证 + - `ResponseTransformMiddleware`:响应转换 + +4. **集成到现有架构** + - 在 `UniversalAiSdkClient` 中集成中间件链 + - 更新 `ApiClientFactory` 支持中间件配置 + - 创建 `AiCoreService` 统一服务接口 + +### 9.5 阶段五:特性中间件 (Week 6) 📋 规划中 +1. **Cherry Studio 特性中间件** + - `ThinkingMiddleware`:思考过程记录 + - `ToolCallMiddleware`:工具调用处理 + - `WebSearchMiddleware`:网络搜索集成 + +2. **高级功能** + - 中间件组合器和构建器 + - 动态中间件加载 + - 中间件配置管理 + +### 9.6 阶段六:文档和发布 (Week 7) 📋 规划中 +1. 完善使用文档和示例 +2. 中间件开发指南 +3. 准备发布到 npm +4. 建立维护流程 + +### 9.7 阶段七:生态系统扩展 (Week 8+) 🚀 未来规划 +1. 社区中间件插件系统 +2. 可视化中间件编排工具 +3. 性能监控和分析 +4. 高级缓存策略 + +## 10. 预期收益 + +### 10.1 开发效率提升 +- **90%** 减少新 Provider 接入时间(只需添加注册表配置) +- **70%** 减少维护工作量 +- **95%** 提升开发体验(统一接口 + 类型安全) +- **独立开发**:可以独立于主应用开发和测试 + +### 10.2 代码质量改善 +- 完整的 TypeScript 类型安全 +- 统一的错误处理机制 +- 标准化的 AI SDK 接口 +- 更好的测试覆盖率 + +### 10.3 架构优势 +- **轻量级**:最小化的包装层 +- **可复用**:其他项目可以直接使用 +- **可维护**:独立版本管理和发布 +- **可扩展**:新 provider 只需配置即可 + +### 10.4 生态系统价值 +- 支持 AI SDK 的完整生态系统 +- 可以独立发布到 npm +- 为开源社区贡献价值 +- 建立统一的 AI 基础设施 + +## 11. 风险评估与应对 + +### 11.1 技术风险 +- **AI SDK 版本兼容**:支持多版本兼容策略 +- **依赖管理**:合理使用 peerDependencies +- **类型一致性**:直接使用 AI SDK 类型 +- **性能影响**:最小化包装层开销 + +### 11.2 迁移风险 +- **功能对等性**:确保所有现有功能都能实现 +- **API 兼容性**:提供平滑的迁移路径 +- **集成复杂度**:保持简单的集成方式 +- **学习成本**:提供清晰的使用文档 + +## 12. 总结 + +简化的 AI Core 架构专注于核心价值: + +### 12.1 核心价值 +- **统一接口**:一套 API 支持 19+ AI providers +- **按需加载**:只打包用户实际使用的 providers +- **类型安全**:完整的 TypeScript 支持 +- **轻量高效**:最小化的包装层 + +### 12.2 设计哲学 +- **直接使用 AI SDK**:避免重复造轮子 +- **最小包装**:只在必要时添加抽象层 +- **开发者友好**:简单易用的 API 设计 +- **生态兼容**:充分利用 AI SDK 生态系统 + +### 12.3 成功关键 +1. **保持简单**:专注核心功能,避免过度设计 +2. **充分测试**:确保功能完整性和稳定性 +3. **渐进迁移**:平滑过渡,降低风险 +4. **文档完善**:支持快速上手和深度使用 + +这个简化的架构为 Cherry Studio 提供了一个轻量、高效、可维护的 AI 基础设施,同时为社区贡献了一个高质量的开源包。 \ No newline at end of file diff --git a/packages/aiCore/README.md b/packages/aiCore/README.md new file mode 100644 index 0000000000..99aa6ecc2a --- /dev/null +++ b/packages/aiCore/README.md @@ -0,0 +1,114 @@ +# @cherry-studio/ai-core + +Cherry Studio AI Core 是一个基于 Vercel AI SDK 的统一 AI Provider 接口包。 + +## 特性 + +- 🚀 统一的 AI Provider 接口 +- 🔄 动态导入支持 +- 💾 智能缓存机制 +- 🛠️ TypeScript 支持 +- 📦 轻量级设计 + +## 支持的 Providers + +基于 [AI SDK 官方支持的 providers](https://ai-sdk.dev/providers/ai-sdk-providers): + +**核心 Providers:** +- OpenAI +- Anthropic +- Google Generative AI +- Google Vertex AI +- Mistral AI +- xAI (Grok) +- Azure OpenAI +- Amazon Bedrock + +**扩展 Providers:** +- Cohere +- Groq +- Together.ai +- Fireworks +- DeepSeek +- Cerebras +- DeepInfra +- Replicate +- Perplexity +- Fal AI +- Vercel + +## 安装 + +```bash +npm install @cherry-studio/ai-core ai +``` + +还需要安装你要使用的 AI SDK provider: + +```bash +npm install @ai-sdk/openai @ai-sdk/anthropic @ai-sdk/google +``` + +## 使用示例 + +### 基础用法 + +```typescript +import { createAiSdkClient } from '@cherry-studio/ai-core' + +// 创建 OpenAI 客户端 +const client = await createAiSdkClient('openai', { + apiKey: 'your-api-key' +}) + +// 流式生成 +const result = await client.stream({ + modelId: 'gpt-4', + messages: [ + { role: 'user', content: 'Hello!' } + ] +}) + +// 非流式生成 +const response = await client.generate({ + modelId: 'gpt-4', + messages: [ + { role: 'user', content: 'Hello!' } + ] +}) +``` + +### 便捷函数 + +```typescript +import { createOpenAIClient, streamGeneration } from '@cherry-studio/ai-core' + +// 快速创建 OpenAI 客户端 +const client = await createOpenAIClient({ + apiKey: 'your-api-key' +}) + +// 便捷流式生成 +const result = await streamGeneration( + 'openai', + 'gpt-4', + [{ role: 'user', content: 'Hello!' }], + { apiKey: 'your-api-key' } +) +``` + +### 多 Provider 支持 + +```typescript +import { createAiSdkClient } from '@cherry-studio/ai-core' + +// 支持多种 AI providers +const openaiClient = await createAiSdkClient('openai', { apiKey: 'openai-key' }) +const anthropicClient = await createAiSdkClient('anthropic', { apiKey: 'anthropic-key' }) +const googleClient = await createAiSdkClient('google', { apiKey: 'google-key' }) +const xaiClient = await createAiSdkClient('xai', { apiKey: 'xai-key' }) +``` + +## License + +MIT \ No newline at end of file diff --git a/packages/aiCore/package.json b/packages/aiCore/package.json new file mode 100644 index 0000000000..4d9fd4d35f --- /dev/null +++ b/packages/aiCore/package.json @@ -0,0 +1,117 @@ +{ + "name": "@cherry-studio/ai-core", + "version": "1.0.0", + "description": "Cherry Studio AI Core - Unified AI Provider Interface Based on Vercel AI SDK", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc", + "dev": "tsc -w", + "clean": "rm -rf dist" + }, + "keywords": [ + "ai", + "sdk", + "openai", + "anthropic", + "google", + "cherry-studio", + "vercel-ai-sdk" + ], + "author": "Cherry Studio", + "license": "MIT", + "dependencies": { + "@ai-sdk/amazon-bedrock": "^2.2.10", + "@ai-sdk/anthropic": "^1.2.12", + "@ai-sdk/azure": "^1.3.23", + "@ai-sdk/cerebras": "^0.2.14", + "@ai-sdk/cohere": "^1.2.10", + "@ai-sdk/deepinfra": "^0.2.15", + "@ai-sdk/deepseek": "^0.2.14", + "@ai-sdk/fal": "^0.1.12", + "@ai-sdk/fireworks": "^0.2.14", + "@ai-sdk/google": "^1.2.19", + "@ai-sdk/google-vertex": "^2.2.24", + "@ai-sdk/groq": "^1.2.9", + "@ai-sdk/mistral": "^1.2.8", + "@ai-sdk/openai": "^1.3.22", + "@ai-sdk/perplexity": "^1.1.9", + "@ai-sdk/replicate": "^0.2.8", + "@ai-sdk/togetherai": "^0.2.14", + "@ai-sdk/vercel": "^0.0.1", + "@ai-sdk/xai": "^1.2.16", + "ai": "^4.3.16" + }, + "peerDependenciesMeta": { + "@ai-sdk/amazon-bedrock": { + "optional": true + }, + "@ai-sdk/anthropic": { + "optional": true + }, + "@ai-sdk/azure": { + "optional": true + }, + "@ai-sdk/cerebras": { + "optional": true + }, + "@ai-sdk/cohere": { + "optional": true + }, + "@ai-sdk/deepinfra": { + "optional": true + }, + "@ai-sdk/deepseek": { + "optional": true + }, + "@ai-sdk/fal": { + "optional": true + }, + "@ai-sdk/fireworks": { + "optional": true + }, + "@ai-sdk/google": { + "optional": true + }, + "@ai-sdk/google-vertex": { + "optional": true + }, + "@ai-sdk/groq": { + "optional": true + }, + "@ai-sdk/mistral": { + "optional": true + }, + "@ai-sdk/openai": { + "optional": true + }, + "@ai-sdk/perplexity": { + "optional": true + }, + "@ai-sdk/replicate": { + "optional": true + }, + "@ai-sdk/together": { + "optional": true + }, + "@ai-sdk/vercel": { + "optional": true + }, + "@ai-sdk/xai": { + "optional": true + } + }, + "devDependencies": { + "typescript": "^5.0.0" + }, + "files": [ + "dist" + ], + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.js" + } + } +} diff --git a/packages/aiCore/src/clients/ApiClientFactory.ts b/packages/aiCore/src/clients/ApiClientFactory.ts new file mode 100644 index 0000000000..050c551dc9 --- /dev/null +++ b/packages/aiCore/src/clients/ApiClientFactory.ts @@ -0,0 +1,341 @@ +/** + * API Client Factory + * 整合现有实现的改进版API客户端工厂 + */ + +import { aiProviderRegistry } from '../providers/registry' +import type { CacheStats as BaseCacheStats, ClientConfig as BaseClientConfig } from '../providers/types' +import { UniversalAiSdkClient } from './UniversalAiSdkClient' + +// 客户端配置接口 +export interface ClientConfig extends BaseClientConfig {} + +// 缓存统计信息 +export interface CacheStats extends BaseCacheStats {} + +// 错误类型 +export class ClientFactoryError extends Error { + constructor( + message: string, + public providerId?: string, + public cause?: Error + ) { + super(message) + this.name = 'ClientFactoryError' + } +} + +/** + * API Client Factory + * 统一管理和创建AI SDK客户端 + */ +export class ApiClientFactory { + private static instance: ApiClientFactory + private static sdkClients = new Map() + private static lastCleanup = new Date() + + private constructor() { + // Private constructor for singleton pattern + } + + public static getInstance(): ApiClientFactory { + if (!ApiClientFactory.instance) { + ApiClientFactory.instance = new ApiClientFactory() + } + return ApiClientFactory.instance + } + + /** + * [NEW METHOD] Create a new universal client for ai-sdk providers. + * [新方法] 为 ai-sdk 提供商创建一个新的通用客户端。 + */ + static async createAiSdkClient(providerId: string, options: any = {}): Promise { + try { + // 验证provider是否支持 + if (!aiProviderRegistry.isSupported(providerId)) { + throw new ClientFactoryError(`Provider "${providerId}" is not supported`, providerId) + } + + // 生成缓存键 - 对于有认证选项的providers,使用更精细的键 + const cacheKey = this.generateCacheKey(providerId, options) + + // 检查缓存 + if (this.sdkClients.has(cacheKey)) { + const cachedClient = this.sdkClients.get(cacheKey)! + // 验证缓存的客户端是否仍然有效 + if (cachedClient.isInitialized() && cachedClient.validateConfig()) { + return cachedClient + } else { + // 如果缓存的客户端无效,清理它 + this.sdkClients.delete(cacheKey) + cachedClient.cleanup() + } + } + + // 1. 创建一个新的通用客户端实例 + const client = new UniversalAiSdkClient(providerId, options) + + // 2. 初始化它(这将执行动态导入) + await client.initialize() + + // 3. 验证配置 + if (!client.validateConfig()) { + throw new ClientFactoryError(`Invalid configuration for provider "${providerId}"`, providerId) + } + + // 4. 缓存并返回 + this.sdkClients.set(cacheKey, client) + return client + } catch (error) { + if (error instanceof ClientFactoryError) { + throw error + } + throw new ClientFactoryError( + `Failed to create client for provider "${providerId}": ${error instanceof Error ? error.message : 'Unknown error'}`, + providerId, + error instanceof Error ? error : undefined + ) + } + } + + /** + * 获取缓存的客户端 + */ + static getCachedClient(providerId: string, options: any = {}): UniversalAiSdkClient | undefined { + const cacheKey = this.generateCacheKey(providerId, options) + return this.sdkClients.get(cacheKey) + } + + /** + * 检查客户端是否存在于缓存中 + */ + static hasCachedClient(providerId: string, options: any = {}): boolean { + const cacheKey = this.generateCacheKey(providerId, options) + return this.sdkClients.has(cacheKey) + } + + /** + * 生成缓存键 + */ + private static generateCacheKey(providerId: string, options: any): string { + // 创建一个包含关键配置的键,但不包含敏感信息的完整内容 + const keyData = { + providerId, + apiKey: options.apiKey ? this.hashApiKey(options.apiKey) : undefined, + baseURL: options.baseURL, + organization: options.organization, + project: options.project, + // 添加其他相关但非敏感的配置 + model: options.model, + region: options.region + } + + // 移除undefined值 + Object.keys(keyData).forEach((key) => { + if (keyData[key as keyof typeof keyData] === undefined) { + delete keyData[key as keyof typeof keyData] + } + }) + + return JSON.stringify(keyData) + } + + /** + * 对API Key进行哈希处理(用于缓存键) + */ + private static hashApiKey(apiKey: string): string { + // 简单的哈希方法,只取前8个字符和后4个字符 + if (apiKey.length <= 12) { + return apiKey.slice(0, 4) + '...' + } + return apiKey.slice(0, 8) + '...' + apiKey.slice(-4) + } + + /** + * 清理缓存 + */ + static clearCache(): void { + // 清理所有客户端 + this.sdkClients.forEach((client) => { + try { + client.cleanup() + } catch (error) { + console.warn('Error cleaning up client:', error) + } + }) + + this.sdkClients.clear() + this.lastCleanup = new Date() + } + + /** + * 清理特定provider的缓存 + */ + static clearProviderCache(providerId: string): void { + const keysToDelete: string[] = [] + + this.sdkClients.forEach((client, key) => { + if (key.includes(`"providerId":"${providerId}"`)) { + try { + client.cleanup() + } catch (error) { + console.warn(`Error cleaning up client for ${providerId}:`, error) + } + keysToDelete.push(key) + } + }) + + keysToDelete.forEach((key) => { + this.sdkClients.delete(key) + }) + } + + /** + * 获取缓存统计信息 + */ + static getCacheStats(): CacheStats { + return { + size: this.sdkClients.size, + keys: Array.from(this.sdkClients.keys()), + lastCleanup: this.lastCleanup + } + } + + /** + * 预热指定的客户端 + */ + static async warmupClients(configs: ClientConfig[]): Promise { + const warmupPromises = configs.map(async (config) => { + try { + const { providerId, ...options } = config + await this.createAiSdkClient(providerId, options) + console.log(`✅ Warmed up client for provider: ${providerId}`) + } catch (error) { + console.warn(`⚠️ Failed to warm up client for ${config.providerId}:`, error) + } + }) + + await Promise.allSettled(warmupPromises) + } + + /** + * 获取所有支持的providers信息 + */ + static getSupportedProviders(): Array<{ + id: string + name: string + hasCachedClient: boolean + }> { + const providers = aiProviderRegistry.getAllProviders() + + return providers.map((provider) => ({ + id: provider.id, + name: provider.name, + hasCachedClient: Array.from(this.sdkClients.keys()).some((key) => key.includes(`"providerId":"${provider.id}"`)) + })) + } + + /** + * 批量创建客户端 + */ + static async createMultipleClients(configs: ClientConfig[]): Promise<{ + success: Array<{ providerId: string; client: UniversalAiSdkClient }> + errors: Array<{ providerId: string; error: Error }> + }> { + const success: Array<{ providerId: string; client: UniversalAiSdkClient }> = [] + const errors: Array<{ providerId: string; error: Error }> = [] + + await Promise.allSettled( + configs.map(async (config) => { + try { + const { providerId, ...options } = config + const client = await this.createAiSdkClient(providerId, options) + success.push({ providerId, client }) + } catch (error) { + errors.push({ + providerId: config.providerId, + error: error instanceof Error ? error : new Error('Unknown error') + }) + } + }) + ) + + return { success, errors } + } + + /** + * 健康检查 - 检查所有缓存客户端的状态 + */ + static async healthCheck(): Promise<{ + healthy: number + unhealthy: number + total: number + details: Array<{ + providerId: string + status: 'healthy' | 'unhealthy' + error?: string + }> + }> { + const details: Array<{ + providerId: string + status: 'healthy' | 'unhealthy' + error?: string + }> = [] + + let healthy = 0 + let unhealthy = 0 + + for (const [, client] of this.sdkClients) { + try { + const info = client.getProviderInfo() + if (client.isInitialized() && client.validateConfig()) { + healthy++ + details.push({ + providerId: info.id, + status: 'healthy' + }) + } else { + unhealthy++ + details.push({ + providerId: info.id, + status: 'unhealthy', + error: 'Client not properly initialized or invalid config' + }) + } + } catch (error) { + unhealthy++ + details.push({ + providerId: 'unknown', + status: 'unhealthy', + error: error instanceof Error ? error.message : 'Unknown error' + }) + } + } + + return { + healthy, + unhealthy, + total: this.sdkClients.size, + details + } + } +} + +// 导出单例实例和便捷函数 +export const apiClientFactory = ApiClientFactory.getInstance() + +// 便捷函数 +export const createAiSdkClient = (providerId: string, options?: any) => + ApiClientFactory.createAiSdkClient(providerId, options) + +export const getCachedClient = (providerId: string, options?: any) => + ApiClientFactory.getCachedClient(providerId, options) + +export const clearCache = () => ApiClientFactory.clearCache() + +export const warmupClients = (configs: ClientConfig[]) => ApiClientFactory.warmupClients(configs) + +export const healthCheck = () => ApiClientFactory.healthCheck() + +// 默认导出 +export default ApiClientFactory diff --git a/packages/aiCore/src/clients/UniversalAiSdkClient.ts b/packages/aiCore/src/clients/UniversalAiSdkClient.ts new file mode 100644 index 0000000000..166b46f0a1 --- /dev/null +++ b/packages/aiCore/src/clients/UniversalAiSdkClient.ts @@ -0,0 +1,201 @@ +/** + * Universal AI SDK Client + * 基于现有实现的简化版统一AI SDK客户端 + */ + +import { generateText, streamText } from 'ai' + +import { aiProviderRegistry } from '../providers/registry' + +/** + * Universal AI SDK Client + * 统一的AI SDK客户端实现 + */ +export class UniversalAiSdkClient { + private provider: any // The instantiated provider (e.g., from createOpenAI) + private initialized = false + private providerConfig: any + + constructor( + private providerName: string, + private options: any // API keys, etc. + ) {} + + /** + * 初始化客户端 - 异步步骤,因为涉及动态导入 + */ + async initialize(): Promise { + if (this.initialized) return + + // 获取Provider配置 + this.providerConfig = aiProviderRegistry.getProvider(this.providerName) + if (!this.providerConfig) { + throw new Error(`Provider "${this.providerName}" is not registered.`) + } + + try { + // 使用注册表的动态导入功能 + const module = await this.providerConfig.import() + + // 获取创建函数 + const creatorFunction = module[this.providerConfig.creatorFunctionName] + + if (typeof creatorFunction !== 'function') { + throw new Error( + `Creator function "${this.providerConfig.creatorFunctionName}" not found in the imported module for provider "${this.providerName}".` + ) + } + + // 创建provider实例 + this.provider = creatorFunction(this.options) + this.initialized = true + } catch (error) { + if (error instanceof Error) { + throw new Error(`Failed to initialize provider "${this.providerName}": ${error.message}`) + } + throw new Error(`An unknown error occurred while initializing provider "${this.providerName}".`) + } + } + + /** + * 检查是否已初始化 + */ + isInitialized(): boolean { + return this.initialized + } + + /** + * 获取特定模型实例的辅助方法 + */ + private getModel(modelId: string): any { + if (!this.initialized) throw new Error('Client not initialized') + + // 大多数providers都有直接调用模式:provider(modelId) + if (typeof this.provider === 'function') { + return this.provider(modelId) + } + + throw new Error(`Unknown model access pattern for provider "${this.providerName}"`) + } + + /** + * 实现流式逻辑,使用核心ai-sdk函数 + */ + async stream(request: any): Promise { + if (!this.initialized) await this.initialize() + + const model = this.getModel(request.modelId) + + // 直接调用标准ai-sdk函数 + return streamText({ + model, + ...request + }) + } + + /** + * 实现非流式逻辑 + */ + async generate(request: any): Promise { + if (!this.initialized) await this.initialize() + + const model = this.getModel(request.modelId) + + return generateText({ + model, + ...request + }) + } + + /** + * 验证配置 + */ + validateConfig(): boolean { + try { + // 基础验证 + if (!this.providerName) return false + if (!this.providerConfig) return false + + // API Key验证(如果需要) + if (this.requiresApiKey() && !this.options?.apiKey) { + return false + } + + return true + } catch { + return false + } + } + + /** + * 检查Provider是否需要API Key + */ + private requiresApiKey(): boolean { + // 大多数云服务Provider都需要API Key + const noApiKeyProviders = ['local', 'ollama'] // 本地运行的Provider + return !noApiKeyProviders.includes(this.providerName) + } + + /** + * 获取Provider信息 + */ + getProviderInfo(): { + id: string + name: string + isInitialized: boolean + } { + return { + id: this.providerName, + name: this.providerConfig?.name || this.providerName, + isInitialized: this.initialized + } + } + + /** + * 清理资源 + */ + cleanup(): void { + this.provider = null + this.initialized = false + this.providerConfig = null + } +} + +// 工厂函数,方便创建客户端 +export async function createUniversalClient(providerName: string, options: any = {}): Promise { + const client = new UniversalAiSdkClient(providerName, options) + await client.initialize() + return client +} + +// 便捷的流式生成函数 +export async function streamGeneration( + providerName: string, + modelId: string, + messages: any[], + options: any = {} +): Promise { + const client = await createUniversalClient(providerName, options) + + return client.stream({ + modelId, + messages, + ...options + }) +} + +// 便捷的非流式生成函数 +export async function generateCompletion( + providerName: string, + modelId: string, + messages: any[], + options: any = {} +): Promise { + const client = await createUniversalClient(providerName, options) + + return client.generate({ + modelId, + messages, + ...options + }) +} diff --git a/packages/aiCore/src/index.ts b/packages/aiCore/src/index.ts new file mode 100644 index 0000000000..56c15811b9 --- /dev/null +++ b/packages/aiCore/src/index.ts @@ -0,0 +1,130 @@ +/** + * Cherry Studio AI Core Package + * 基于 Vercel AI SDK 的统一 AI Provider 接口 + */ + +// 核心导出 +export { ApiClientFactory, apiClientFactory } from './clients/ApiClientFactory' +export { UniversalAiSdkClient } from './clients/UniversalAiSdkClient' +export { aiProviderRegistry, PROVIDER_REGISTRY } from './providers/registry' + +// 类型导出 +export type { CacheStats, ClientConfig, ClientFactoryError } from './clients/ApiClientFactory' +export type { ProviderConfig } from './providers/registry' +export type { ProviderError } from './providers/types' + +// 便捷函数导出 +export { clearCache, createAiSdkClient, getCachedClient, healthCheck, warmupClients } from './clients/ApiClientFactory' +export { createUniversalClient, generateCompletion, streamGeneration } from './clients/UniversalAiSdkClient' +export { getAllProviders, getProvider, isProviderSupported, registerProvider } from './providers/registry' + +// 默认导出 - 主要的工厂类 +export { ApiClientFactory as default } from './clients/ApiClientFactory' + +// 导入内部使用的函数 +import { ApiClientFactory } from './clients/ApiClientFactory' +import { clearCache, createAiSdkClient, healthCheck } from './clients/ApiClientFactory' +import { aiProviderRegistry } from './providers/registry' +import { getAllProviders, isProviderSupported } from './providers/registry' + +// 包信息 +export const AI_CORE_VERSION = '1.0.0' +export const AI_CORE_NAME = '@cherry-studio/ai-core' + +// 包配置和实用工具 +export const AiCore = { + version: AI_CORE_VERSION, + name: AI_CORE_NAME, + + // 快速创建客户端 + async createClient(providerId: string, options: any = {}) { + return createAiSdkClient(providerId, options) + }, + + // 获取支持的providers + getSupportedProviders() { + return getAllProviders() + }, + + // 检查provider支持 + isSupported(providerId: string) { + return isProviderSupported(providerId) + }, + + // 获取缓存统计 + getCacheStats() { + return ApiClientFactory.getCacheStats() + }, + + // 健康检查 + async healthCheck() { + return healthCheck() + }, + + // 清理所有资源 + cleanup() { + clearCache() + aiProviderRegistry.cleanup() + } +} + +// 便捷的预配置clients创建函数 +export const createOpenAIClient = async (options: { apiKey: string; baseURL?: string }) => { + return createAiSdkClient('openai', options) +} + +export const createAnthropicClient = async (options: { apiKey: string; baseURL?: string }) => { + return createAiSdkClient('anthropic', options) +} + +export const createGoogleClient = async (options: { apiKey: string; baseURL?: string }) => { + return createAiSdkClient('google', options) +} + +export const createXAIClient = async (options: { apiKey: string; baseURL?: string }) => { + return createAiSdkClient('xai', options) +} + +// 调试和开发工具 +export const DevTools = { + // 列出所有注册的providers + listProviders() { + return aiProviderRegistry.getAllProviders().map((p) => ({ + id: p.id, + name: p.name + })) + }, + + // 测试provider连接 + async testProvider(providerId: string, options: any) { + try { + const client = await createAiSdkClient(providerId, options) + const info = client.getProviderInfo() + return { + success: true, + providerId: info.id, + name: info.name, + isInitialized: info.isInitialized + } + } catch (error) { + return { + success: false, + providerId, + error: error instanceof Error ? error.message : 'Unknown error' + } + } + }, + + // 获取详细的缓存信息 + getCacheDetails() { + const stats = ApiClientFactory.getCacheStats() + const providers = aiProviderRegistry.getAllProviders() + + return { + cacheStats: stats, + supportedProviders: providers.length, + registeredProviders: aiProviderRegistry.getAllProviders().length, + activeClients: stats.size + } + } +} diff --git a/packages/aiCore/src/providers/registry.ts b/packages/aiCore/src/providers/registry.ts new file mode 100644 index 0000000000..2f7a7d6412 --- /dev/null +++ b/packages/aiCore/src/providers/registry.ts @@ -0,0 +1,226 @@ +/** + * AI Provider 注册表 + * 统一管理所有 AI SDK Providers 的动态导入和工厂函数 + */ + +// Provider 配置接口(简化版) +export interface ProviderConfig { + id: string + name: string + // 动态导入函数 + import: () => Promise + // 创建函数名称 + creatorFunctionName: string +} + +/** + * AI SDK Provider 注册表 + * 管理所有支持的 AI Providers 及其动态导入 + */ +export class AiProviderRegistry { + private static instance: AiProviderRegistry + private registry = new Map() + + private constructor() { + this.initializeProviders() + } + + public static getInstance(): AiProviderRegistry { + if (!AiProviderRegistry.instance) { + AiProviderRegistry.instance = new AiProviderRegistry() + } + return AiProviderRegistry.instance + } + + /** + * 初始化所有支持的 Providers + * 基于 AI SDK 官方文档: https://ai-sdk.dev/providers/ai-sdk-providers + */ + private initializeProviders(): void { + const providers: ProviderConfig[] = [ + // 核心 AI SDK Providers + { + id: 'openai', + name: 'OpenAI', + import: () => import('@ai-sdk/openai'), + creatorFunctionName: 'createOpenAI' + }, + { + id: 'anthropic', + name: 'Anthropic', + import: () => import('@ai-sdk/anthropic'), + creatorFunctionName: 'createAnthropic' + }, + { + id: 'google', + name: 'Google Generative AI', + import: () => import('@ai-sdk/google'), + creatorFunctionName: 'createGoogleGenerativeAI' + }, + { + id: 'google-vertex', + name: 'Google Vertex AI', + import: () => import('@ai-sdk/google-vertex'), + creatorFunctionName: 'createVertex' + }, + { + id: 'mistral', + name: 'Mistral AI', + import: () => import('@ai-sdk/mistral'), + creatorFunctionName: 'createMistral' + }, + { + id: 'xai', + name: 'xAI (Grok)', + import: () => import('@ai-sdk/xai'), + creatorFunctionName: 'createXai' + }, + { + id: 'azure', + name: 'Azure OpenAI', + import: () => import('@ai-sdk/azure'), + creatorFunctionName: 'createAzure' + }, + { + id: 'bedrock', + name: 'Amazon Bedrock', + import: () => import('@ai-sdk/amazon-bedrock'), + creatorFunctionName: 'createAmazonBedrock' + }, + { + id: 'cohere', + name: 'Cohere', + import: () => import('@ai-sdk/cohere'), + creatorFunctionName: 'createCohere' + }, + { + id: 'groq', + name: 'Groq', + import: () => import('@ai-sdk/groq'), + creatorFunctionName: 'createGroq' + }, + { + id: 'together', + name: 'Together.ai', + import: () => import('@ai-sdk/togetherai'), + creatorFunctionName: 'createTogetherAI' + }, + { + id: 'fireworks', + name: 'Fireworks', + import: () => import('@ai-sdk/fireworks'), + creatorFunctionName: 'createFireworks' + }, + { + id: 'deepseek', + name: 'DeepSeek', + import: () => import('@ai-sdk/deepseek'), + creatorFunctionName: 'createDeepSeek' + }, + { + id: 'cerebras', + name: 'Cerebras', + import: () => import('@ai-sdk/cerebras'), + creatorFunctionName: 'createCerebras' + }, + { + id: 'deepinfra', + name: 'DeepInfra', + import: () => import('@ai-sdk/deepinfra'), + creatorFunctionName: 'createDeepInfra' + }, + { + id: 'replicate', + name: 'Replicate', + import: () => import('@ai-sdk/replicate'), + creatorFunctionName: 'createReplicate' + }, + { + id: 'perplexity', + name: 'Perplexity', + import: () => import('@ai-sdk/perplexity'), + creatorFunctionName: 'createPerplexity' + }, + { + id: 'fal', + name: 'Fal AI', + import: () => import('@ai-sdk/fal'), + creatorFunctionName: 'createFal' + }, + { + id: 'vercel', + name: 'Vercel', + import: () => import('@ai-sdk/vercel'), + creatorFunctionName: 'createVercel' + } + ] + + // 初始化注册表 + providers.forEach((config) => { + this.registry.set(config.id, config) + }) + } + + /** + * 获取所有已注册的 Providers + */ + public getAllProviders(): ProviderConfig[] { + return Array.from(this.registry.values()) + } + + /** + * 根据 ID 获取 Provider 配置 + */ + public getProvider(id: string): ProviderConfig | undefined { + return this.registry.get(id) + } + + /** + * 检查 Provider 是否支持(是否已注册) + */ + public isSupported(id: string): boolean { + return this.registry.has(id) + } + + /** + * 注册新的 Provider(用于扩展) + */ + public registerProvider(config: ProviderConfig): void { + this.registry.set(config.id, config) + } + + /** + * 清理资源 + */ + public cleanup(): void { + this.registry.clear() + } + + /** + * 获取兼容现有实现的注册表格式 + */ + public getCompatibleRegistry(): Record Promise; creatorFunctionName: string }> { + const compatibleRegistry: Record Promise; creatorFunctionName: string }> = {} + + this.getAllProviders().forEach((provider) => { + compatibleRegistry[provider.id] = { + import: provider.import, + creatorFunctionName: provider.creatorFunctionName + } + }) + + return compatibleRegistry + } +} + +// 导出单例实例 +export const aiProviderRegistry = AiProviderRegistry.getInstance() + +// 便捷函数 +export const getProvider = (id: string) => aiProviderRegistry.getProvider(id) +export const getAllProviders = () => aiProviderRegistry.getAllProviders() +export const isProviderSupported = (id: string) => aiProviderRegistry.isSupported(id) +export const registerProvider = (config: ProviderConfig) => aiProviderRegistry.registerProvider(config) + +// 兼容现有实现的导出 +export const PROVIDER_REGISTRY = aiProviderRegistry.getCompatibleRegistry() diff --git a/packages/aiCore/src/providers/types.ts b/packages/aiCore/src/providers/types.ts new file mode 100644 index 0000000000..8908a5967c --- /dev/null +++ b/packages/aiCore/src/providers/types.ts @@ -0,0 +1,47 @@ +/** + * Provider 相关核心类型定义 + * 只定义必要的接口,其他类型直接使用 AI SDK + */ + +// Provider 配置接口(简化版) +export interface ProviderConfig { + id: string + name: string + import: () => Promise + creatorFunctionName: string +} + +// API 客户端工厂接口 +export interface ApiClientFactory { + createAiSdkClient(providerId: string, options?: any): Promise + getCachedClient(providerId: string, options?: any): any + clearCache(): void +} + +// 客户端配置 +export interface ClientConfig { + providerId: string + apiKey?: string + baseURL?: string + [key: string]: any +} + +// 错误类型 +export class ProviderError extends Error { + constructor( + message: string, + public providerId: string, + public code?: string, + public cause?: Error + ) { + super(message) + this.name = 'ProviderError' + } +} + +// 缓存统计信息 +export interface CacheStats { + size: number + keys: string[] + lastCleanup?: Date +} diff --git a/packages/aiCore/tsconfig.json b/packages/aiCore/tsconfig.json new file mode 100644 index 0000000000..b45b2bc8ca --- /dev/null +++ b/packages/aiCore/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "node", + "declaration": true, + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "noEmitOnError": false, + "experimentalDecorators": true, + "emitDecoratorMetadata": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index ad87138f87..67aea5b85e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -74,6 +74,313 @@ __metadata: languageName: node linkType: hard +"@ai-sdk/amazon-bedrock@npm:^2.2.10": + version: 2.2.10 + resolution: "@ai-sdk/amazon-bedrock@npm:2.2.10" + dependencies: + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + "@smithy/eventstream-codec": "npm:^4.0.1" + "@smithy/util-utf8": "npm:^4.0.0" + aws4fetch: "npm:^1.0.20" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/ca066cc4dd94146374492e18e313b7664b661562e7fa3c94ad55c731564744281d62662337718fe107c99d7d2ebf8fd655c8e2cb3dcbcd30b2e33cbc248c962e + languageName: node + linkType: hard + +"@ai-sdk/anthropic@npm:1.2.12, @ai-sdk/anthropic@npm:^1.2.12": + version: 1.2.12 + resolution: "@ai-sdk/anthropic@npm:1.2.12" + dependencies: + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/da13e1ed3c03efe207dbb0fd5fe9f399e4119e6687ec1096418a33a7eeea3c5f912a51c74b185bba3c203b15ee0c1b9cdf649711815ff8e769e31af266ac00fb + languageName: node + linkType: hard + +"@ai-sdk/azure@npm:^1.3.23": + version: 1.3.23 + resolution: "@ai-sdk/azure@npm:1.3.23" + dependencies: + "@ai-sdk/openai": "npm:1.3.22" + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/18fcd3271e316edffe1b289b1c148e3bf6e0e51e57440d6a5aa4d76b53831dd5219fffcedb92d7dddebac81add46151a00bf70bd9e14509421e3bb0e359fd6bf + languageName: node + linkType: hard + +"@ai-sdk/cerebras@npm:^0.2.14": + version: 0.2.14 + resolution: "@ai-sdk/cerebras@npm:0.2.14" + dependencies: + "@ai-sdk/openai-compatible": "npm:0.2.14" + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/a94f91daa618ce3f0499b77191f53c54a5a1f8bce6b4ad12acc976e4410f83271dfb1fb377bab9dee573f497d9a505160b757ac0120d8dc160c7081618f94b45 + languageName: node + linkType: hard + +"@ai-sdk/cohere@npm:^1.2.10": + version: 1.2.10 + resolution: "@ai-sdk/cohere@npm:1.2.10" + dependencies: + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/7a7d026458322c9579d860244072525cbe939b86ad89f0cb29b0103fc8a1cb7e54b11bb5f13a4db6c18507a12a8a0b4035333c2e996d8ded4708b5ec355b78e7 + languageName: node + linkType: hard + +"@ai-sdk/deepinfra@npm:^0.2.15": + version: 0.2.15 + resolution: "@ai-sdk/deepinfra@npm:0.2.15" + dependencies: + "@ai-sdk/openai-compatible": "npm:0.2.14" + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/569a7d9fdf2d4ab16e371243782ece401d2336ed152741789e91f2df24918e536b4e1e8ee9ae9436a1fe059e00c32a06c867f083c1d93443be2a564fd465459e + languageName: node + linkType: hard + +"@ai-sdk/deepseek@npm:^0.2.14": + version: 0.2.14 + resolution: "@ai-sdk/deepseek@npm:0.2.14" + dependencies: + "@ai-sdk/openai-compatible": "npm:0.2.14" + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/abf22e44336c2b9cf075da20d3e641bbe6584861820ebbcb37877ce4730503c561984b63040384aef53ae0b5835f6680f7c42477588ce5fdf6ad37df695e129e + languageName: node + linkType: hard + +"@ai-sdk/fal@npm:^0.1.12": + version: 0.1.12 + resolution: "@ai-sdk/fal@npm:0.1.12" + dependencies: + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/3e5f0a72cf479e017dbddafb5bcba64f51e3f7feba33045bb132a7ec3e0abe5b4b65740a0e4fc7631b7a0587f8beb8e52b94adee409e6c82db57ba5a87ab8006 + languageName: node + linkType: hard + +"@ai-sdk/fireworks@npm:^0.2.14": + version: 0.2.14 + resolution: "@ai-sdk/fireworks@npm:0.2.14" + dependencies: + "@ai-sdk/openai-compatible": "npm:0.2.14" + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/c34dba26e0de8754017b4bc16c1b4a295863b4d18e33c5e1bf6e6057029c78cae397e610b34e1eae16af454653cbd97754b66a1f7eede9285df2e16f4637aec3 + languageName: node + linkType: hard + +"@ai-sdk/google-vertex@npm:^2.2.24": + version: 2.2.24 + resolution: "@ai-sdk/google-vertex@npm:2.2.24" + dependencies: + "@ai-sdk/anthropic": "npm:1.2.12" + "@ai-sdk/google": "npm:1.2.19" + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + google-auth-library: "npm:^9.15.0" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/720139b34e8b395d52517abdc81b54f8c6eac1334879f76c07515701bfc2c0dfec7aefb0aee3851e1ec9721462b02a3caffecc5803fd267604f5b1548b352ae3 + languageName: node + linkType: hard + +"@ai-sdk/google@npm:1.2.19, @ai-sdk/google@npm:^1.2.19": + version: 1.2.19 + resolution: "@ai-sdk/google@npm:1.2.19" + dependencies: + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/b40d62ce822ce00850492e4a41c8b6b1ba2ddaaaa8f8d9b8381c198781adb23000fc4f434ef7edf5ba356a4455f8afbbdc5cbecbb0f66b7bcabbcd25758fc6b8 + languageName: node + linkType: hard + +"@ai-sdk/groq@npm:^1.2.9": + version: 1.2.9 + resolution: "@ai-sdk/groq@npm:1.2.9" + dependencies: + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/b268c337fb656d6b36e2a0ee7737c073ad22521acf20b6861a51c269d4f49f59c269d6184ce21cbc61316987e46ed64696dffef57d6d60fb9c45f069d0f30297 + languageName: node + linkType: hard + +"@ai-sdk/mistral@npm:^1.2.8": + version: 1.2.8 + resolution: "@ai-sdk/mistral@npm:1.2.8" + dependencies: + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/d798ce75685f86f8a77c38745c71328fd1bd6b361601d1cb613b94c3c709e890e15e369f8b7e7b009e28394ec42c500c775ec293d506de2be08b13730ea7a924 + languageName: node + linkType: hard + +"@ai-sdk/openai-compatible@npm:0.2.14": + version: 0.2.14 + resolution: "@ai-sdk/openai-compatible@npm:0.2.14" + dependencies: + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/60980df8507c1e5d04ac51123bc15ea5cbf29eb88485f63da28d64ab5d9c3b335d2a2c9155a383605972ef5fa636929c8e2d360bf799153acf2b358e1af1fd47 + languageName: node + linkType: hard + +"@ai-sdk/openai@npm:1.3.22, @ai-sdk/openai@npm:^1.3.22": + version: 1.3.22 + resolution: "@ai-sdk/openai@npm:1.3.22" + dependencies: + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/bcc73a84bebd15aa54568c3c77cedd5f999e282c5be180d5e28ebc789f8873dd0a74d87f1ec4a0f16e3e61b658c3b0734835daf176ed910966246db73c72b468 + languageName: node + linkType: hard + +"@ai-sdk/perplexity@npm:^1.1.9": + version: 1.1.9 + resolution: "@ai-sdk/perplexity@npm:1.1.9" + dependencies: + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/02720dc2d65de771900a3b588b257ac9c3bdf8b3a9e255875b03e4ede9ef185a4c6d311782b5e8033306a6e7fde40fdec526345ba0843a84d45184a556e883ca + languageName: node + linkType: hard + +"@ai-sdk/provider-utils@npm:2.2.8": + version: 2.2.8 + resolution: "@ai-sdk/provider-utils@npm:2.2.8" + dependencies: + "@ai-sdk/provider": "npm:1.1.3" + nanoid: "npm:^3.3.8" + secure-json-parse: "npm:^2.7.0" + peerDependencies: + zod: ^3.23.8 + checksum: 10c0/34c72bf5f23f2d3e7aef496da7099422ba3b3ff243c35511853e16c3f1528717500262eea32b19e3e09bc4452152a5f31e650512f53f08a5f5645d907bff429e + languageName: node + linkType: hard + +"@ai-sdk/provider@npm:1.1.3": + version: 1.1.3 + resolution: "@ai-sdk/provider@npm:1.1.3" + dependencies: + json-schema: "npm:^0.4.0" + checksum: 10c0/40e080e223328e7c89829865e9c48f4ce8442a6a59f7ed5dfbdb4f63e8d859a76641e2d31e91970dd389bddb910f32ec7c3dbb0ce583c119e5a1e614ea7b8bc4 + languageName: node + linkType: hard + +"@ai-sdk/react@npm:1.2.12": + version: 1.2.12 + resolution: "@ai-sdk/react@npm:1.2.12" + dependencies: + "@ai-sdk/provider-utils": "npm:2.2.8" + "@ai-sdk/ui-utils": "npm:1.2.11" + swr: "npm:^2.2.5" + throttleit: "npm:2.1.0" + peerDependencies: + react: ^18 || ^19 || ^19.0.0-rc + zod: ^3.23.8 + peerDependenciesMeta: + zod: + optional: true + checksum: 10c0/5422feb4ffeebd3287441cf658733e9ad7f9081fc279e85f57700d7fe9f4ed8a0504789c1be695790df44b28730e525cf12acf0f52bfa5adecc561ffd00cb2a5 + languageName: node + linkType: hard + +"@ai-sdk/replicate@npm:^0.2.8": + version: 0.2.8 + resolution: "@ai-sdk/replicate@npm:0.2.8" + dependencies: + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/96a90a815b60914126fce854dd32d5912cc4c09d418259af232214d083da8ea6857ad0c99b47758d59d2c4d845dcb33844bb97c6bd78238aee6a00c0069a5f94 + languageName: node + linkType: hard + +"@ai-sdk/togetherai@npm:^0.2.14": + version: 0.2.14 + resolution: "@ai-sdk/togetherai@npm:0.2.14" + dependencies: + "@ai-sdk/openai-compatible": "npm:0.2.14" + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/ae8108fd81e583d7bde30cc391e048197b44dcb3881eecb69d65bc3ef8067a728e308b172587348278700e9b3235e3f6163bcdafb5bb2ec4cc87ff4f87a8e02b + languageName: node + linkType: hard + +"@ai-sdk/ui-utils@npm:1.2.11": + version: 1.2.11 + resolution: "@ai-sdk/ui-utils@npm:1.2.11" + dependencies: + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + zod-to-json-schema: "npm:^3.24.1" + peerDependencies: + zod: ^3.23.8 + checksum: 10c0/de0a10f9e16010126a21a1690aaf56d545b9c0f8d8b2cc33ffd22c2bb2e914949acb9b3f86e0e39a0e4b0d4f24db12e2b094045e34b311de0c8f84bfab48cc92 + languageName: node + linkType: hard + +"@ai-sdk/vercel@npm:^0.0.1": + version: 0.0.1 + resolution: "@ai-sdk/vercel@npm:0.0.1" + dependencies: + "@ai-sdk/openai-compatible": "npm:0.2.14" + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/608a747dc2abb2fc7789cad503769dab5cdedaf39f3494a70f7dbb42ea2dcccd91827b856508faac5305486981206397faa25edca3d593f42ab38869b220835c + languageName: node + linkType: hard + +"@ai-sdk/xai@npm:^1.2.16": + version: 1.2.16 + resolution: "@ai-sdk/xai@npm:1.2.16" + dependencies: + "@ai-sdk/openai-compatible": "npm:0.2.14" + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + peerDependencies: + zod: ^3.0.0 + checksum: 10c0/5418f42506679c49f8c6127b0cdf8185622ccb844d6cf928efe1f819b20cbb4eae631eb7dc534468c790fa7087438b4ebd3b4072c13fb28e0c947ebdd6628ec2 + languageName: node + linkType: hard + "@ampproject/remapping@npm:^2.2.0, @ampproject/remapping@npm:^2.3.0": version: 2.3.0 resolution: "@ampproject/remapping@npm:2.3.0" @@ -228,6 +535,38 @@ __metadata: languageName: node linkType: hard +"@aws-crypto/crc32@npm:5.2.0": + version: 5.2.0 + resolution: "@aws-crypto/crc32@npm:5.2.0" + dependencies: + "@aws-crypto/util": "npm:^5.2.0" + "@aws-sdk/types": "npm:^3.222.0" + tslib: "npm:^2.6.2" + checksum: 10c0/eab9581d3363af5ea498ae0e72de792f54d8890360e14a9d8261b7b5c55ebe080279fb2556e07994d785341cdaa99ab0b1ccf137832b53b5904cd6928f2b094b + languageName: node + linkType: hard + +"@aws-crypto/util@npm:^5.2.0": + version: 5.2.0 + resolution: "@aws-crypto/util@npm:5.2.0" + dependencies: + "@aws-sdk/types": "npm:^3.222.0" + "@smithy/util-utf8": "npm:^2.0.0" + tslib: "npm:^2.6.2" + checksum: 10c0/0362d4c197b1fd64b423966945130207d1fe23e1bb2878a18e361f7743c8d339dad3f8729895a29aa34fff6a86c65f281cf5167c4bf253f21627ae80b6dd2951 + languageName: node + linkType: hard + +"@aws-sdk/types@npm:^3.222.0": + version: 3.821.0 + resolution: "@aws-sdk/types@npm:3.821.0" + dependencies: + "@smithy/types": "npm:^4.3.1" + tslib: "npm:^2.6.2" + checksum: 10c0/6202b2c0db1dd5ee78e6dc45c51f8b19deff0ee400dd5a7a15d089cc5493a2db6a6e0553ff32742e8bc810d428b36599534e14c1b466695550aef1b1d87f043d + languageName: node + linkType: hard + "@babel/code-frame@npm:^7.10.4": version: 7.27.1 resolution: "@babel/code-frame@npm:7.27.1" @@ -509,6 +848,73 @@ __metadata: languageName: node linkType: hard +"@cherry-studio/ai-core@workspace:packages/aiCore": + version: 0.0.0-use.local + resolution: "@cherry-studio/ai-core@workspace:packages/aiCore" + dependencies: + "@ai-sdk/amazon-bedrock": "npm:^2.2.10" + "@ai-sdk/anthropic": "npm:^1.2.12" + "@ai-sdk/azure": "npm:^1.3.23" + "@ai-sdk/cerebras": "npm:^0.2.14" + "@ai-sdk/cohere": "npm:^1.2.10" + "@ai-sdk/deepinfra": "npm:^0.2.15" + "@ai-sdk/deepseek": "npm:^0.2.14" + "@ai-sdk/fal": "npm:^0.1.12" + "@ai-sdk/fireworks": "npm:^0.2.14" + "@ai-sdk/google": "npm:^1.2.19" + "@ai-sdk/google-vertex": "npm:^2.2.24" + "@ai-sdk/groq": "npm:^1.2.9" + "@ai-sdk/mistral": "npm:^1.2.8" + "@ai-sdk/openai": "npm:^1.3.22" + "@ai-sdk/perplexity": "npm:^1.1.9" + "@ai-sdk/replicate": "npm:^0.2.8" + "@ai-sdk/togetherai": "npm:^0.2.14" + "@ai-sdk/vercel": "npm:^0.0.1" + "@ai-sdk/xai": "npm:^1.2.16" + ai: "npm:^4.3.16" + typescript: "npm:^5.0.0" + peerDependenciesMeta: + "@ai-sdk/amazon-bedrock": + optional: true + "@ai-sdk/anthropic": + optional: true + "@ai-sdk/azure": + optional: true + "@ai-sdk/cerebras": + optional: true + "@ai-sdk/cohere": + optional: true + "@ai-sdk/deepinfra": + optional: true + "@ai-sdk/deepseek": + optional: true + "@ai-sdk/fal": + optional: true + "@ai-sdk/fireworks": + optional: true + "@ai-sdk/google": + optional: true + "@ai-sdk/google-vertex": + optional: true + "@ai-sdk/groq": + optional: true + "@ai-sdk/mistral": + optional: true + "@ai-sdk/openai": + optional: true + "@ai-sdk/perplexity": + optional: true + "@ai-sdk/replicate": + optional: true + "@ai-sdk/together": + optional: true + "@ai-sdk/vercel": + optional: true + "@ai-sdk/xai": + optional: true + languageName: unknown + linkType: soft + "@cherrystudio/embedjs-interfaces@npm:0.1.30": version: 0.1.30 resolution: "@cherrystudio/embedjs-interfaces@npm:0.1.30" @@ -3184,6 +3590,13 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/api@npm:1.9.0": + version: 1.9.0 + resolution: "@opentelemetry/api@npm:1.9.0" + checksum: 10c0/9aae2fe6e8a3a3eeb6c1fdef78e1939cf05a0f37f8a4fae4d6bf2e09eb1e06f966ece85805626e01ba5fab48072b94f19b835449e58b6d26720ee19a58298add + languageName: node + linkType: hard + "@parcel/watcher-android-arm64@npm:2.5.1": version: 2.5.1 resolution: "@parcel/watcher-android-arm64@npm:2.5.1" @@ -3815,6 +4228,94 @@ __metadata: languageName: node linkType: hard +"@smithy/eventstream-codec@npm:^4.0.1": + version: 4.0.4 + resolution: "@smithy/eventstream-codec@npm:4.0.4" + dependencies: + "@aws-crypto/crc32": "npm:5.2.0" + "@smithy/types": "npm:^4.3.1" + "@smithy/util-hex-encoding": "npm:^4.0.0" + tslib: "npm:^2.6.2" + checksum: 10c0/89b76826d4d3bf97317e3539ece105b9a03552144ad816a687b0b2cbca60e2b3513062c04b6cfacaffb270d616ffc8ac8bf549afc4aa676a6d7465df5a3215ba + languageName: node + linkType: hard + +"@smithy/is-array-buffer@npm:^2.2.0": + version: 2.2.0 + resolution: "@smithy/is-array-buffer@npm:2.2.0" + dependencies: + tslib: "npm:^2.6.2" + checksum: 10c0/2f2523cd8cc4538131e408eb31664983fecb0c8724956788b015aaf3ab85a0c976b50f4f09b176f1ed7bbe79f3edf80743be7a80a11f22cd9ce1285d77161aaf + languageName: node + linkType: hard + +"@smithy/is-array-buffer@npm:^4.0.0": + version: 4.0.0 + resolution: "@smithy/is-array-buffer@npm:4.0.0" + dependencies: + tslib: "npm:^2.6.2" + checksum: 10c0/ae393fbd5944d710443cd5dd225d1178ef7fb5d6259c14f3e1316ec75e401bda6cf86f7eb98bfd38e5ed76e664b810426a5756b916702cbd418f0933e15e7a3b + languageName: node + linkType: hard + +"@smithy/types@npm:^4.3.1": + version: 4.3.1 + resolution: "@smithy/types@npm:4.3.1" + dependencies: + tslib: "npm:^2.6.2" + checksum: 10c0/8b350562b9ed4ff97465025b4ae77a34bb07b9d47fb6f9781755aac9401b0355a63c2fef307393e2dae3fa0277149dd7d83f5bc2a63d4ad3519ea32fd56b5cda + languageName: node + linkType: hard + +"@smithy/util-buffer-from@npm:^2.2.0": + version: 2.2.0 + resolution: "@smithy/util-buffer-from@npm:2.2.0" + dependencies: + "@smithy/is-array-buffer": "npm:^2.2.0" + tslib: "npm:^2.6.2" + checksum: 10c0/223d6a508b52ff236eea01cddc062b7652d859dd01d457a4e50365af3de1e24a05f756e19433f6ccf1538544076b4215469e21a4ea83dc1d58d829725b0dbc5a + languageName: node + linkType: hard + +"@smithy/util-buffer-from@npm:^4.0.0": + version: 4.0.0 + resolution: "@smithy/util-buffer-from@npm:4.0.0" + dependencies: + "@smithy/is-array-buffer": "npm:^4.0.0" + tslib: "npm:^2.6.2" + checksum: 10c0/be7cd33b6cb91503982b297716251e67cdca02819a15797632091cadab2dc0b4a147fff0709a0aa9bbc0b82a2644a7ed7c8afdd2194d5093cee2e9605b3a9f6f + languageName: node + linkType: hard + +"@smithy/util-hex-encoding@npm:^4.0.0": + version: 4.0.0 + resolution: "@smithy/util-hex-encoding@npm:4.0.0" + dependencies: + tslib: "npm:^2.6.2" + checksum: 10c0/70dbb3aa1a79aff3329d07a66411ff26398df338bdd8a6d077b438231afe3dc86d9a7022204baddecd8bc633f059d5c841fa916d81dd7447ea79b64148f386d2 + languageName: node + linkType: hard + +"@smithy/util-utf8@npm:^2.0.0": + version: 2.3.0 + resolution: "@smithy/util-utf8@npm:2.3.0" + dependencies: + "@smithy/util-buffer-from": "npm:^2.2.0" + tslib: "npm:^2.6.2" + checksum: 10c0/e18840c58cc507ca57fdd624302aefd13337ee982754c9aa688463ffcae598c08461e8620e9852a424d662ffa948fc64919e852508028d09e89ced459bd506ab + languageName: node + linkType: hard + +"@smithy/util-utf8@npm:^4.0.0": + version: 4.0.0 + resolution: "@smithy/util-utf8@npm:4.0.0" + dependencies: + "@smithy/util-buffer-from": "npm:^4.0.0" + tslib: "npm:^2.6.2" + checksum: 10c0/28a5a5372cbf0b3d2e32dd16f79b04c2aec6f704cf13789db922e9686fde38dde0171491cfa4c2c201595d54752a319faaeeed3c325329610887694431e28c98 + languageName: node + linkType: hard + "@strongtz/win32-arm64-msvc@npm:^0.4.7": version: 0.4.7 resolution: "@strongtz/win32-arm64-msvc@npm:0.4.7" @@ -4394,6 +4895,13 @@ __metadata: languageName: node linkType: hard +"@types/diff-match-patch@npm:^1.0.36": + version: 1.0.36 + resolution: "@types/diff-match-patch@npm:1.0.36" + checksum: 10c0/0bad011ab138baa8bde94e7815064bb881f010452463272644ddbbb0590659cb93f7aa2776ff442c6721d70f202839e1053f8aa62d801cc4166f7a3ea9130055 + languageName: node + linkType: hard + "@types/diff@npm:^7": version: 7.0.2 resolution: "@types/diff@npm:7.0.2" @@ -5824,6 +6332,26 @@ __metadata: languageName: node linkType: hard +"ai@npm:^4.3.16": + version: 4.3.16 + resolution: "ai@npm:4.3.16" + dependencies: + "@ai-sdk/provider": "npm:1.1.3" + "@ai-sdk/provider-utils": "npm:2.2.8" + "@ai-sdk/react": "npm:1.2.12" + "@ai-sdk/ui-utils": "npm:1.2.11" + "@opentelemetry/api": "npm:1.9.0" + jsondiffpatch: "npm:0.6.0" + peerDependencies: + react: ^18 || ^19 || ^19.0.0-rc + zod: ^3.23.8 + peerDependenciesMeta: + react: + optional: true + checksum: 10c0/befe761c9386cda6de33370a2590900352b444d81959255c624e2bfd40765f126d29269f0ef3e00bde07daf237004aa0b66d0b253664aa478c148e923ce78c41 + languageName: node + linkType: hard + "ajv-formats@npm:^2.1.1": version: 2.1.1 resolution: "ajv-formats@npm:2.1.1" @@ -6232,6 +6760,13 @@ __metadata: languageName: node linkType: hard +"aws4fetch@npm:^1.0.20": + version: 1.0.20 + resolution: "aws4fetch@npm:1.0.20" + checksum: 10c0/a4eac7bd0d1c3e611c17ed1ef41ac0b48c0a8e74a985ad968c071e74d94586d3572edc943b43fa5ca756c686ea73baa2f48e264d657bb8c2e95c8e0037d48a87 + languageName: node + linkType: hard + "axios@npm:^1.7.3": version: 1.8.4 resolution: "axios@npm:1.8.4" @@ -6736,7 +7271,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^5.4.1": +"chalk@npm:^5.3.0, chalk@npm:^5.4.1": version: 5.4.1 resolution: "chalk@npm:5.4.1" checksum: 10c0/b23e88132c702f4855ca6d25cb5538b1114343e41472d5263ee8a37cccfccd9c4216d111e1097c6a27830407a1dc81fecdf2a56f2c63033d4dbbd88c10b0dcef @@ -8169,6 +8704,13 @@ __metadata: languageName: node linkType: hard +"diff-match-patch@npm:^1.0.5": + version: 1.0.5 + resolution: "diff-match-patch@npm:1.0.5" + checksum: 10c0/142b6fad627b9ef309d11bd935e82b84c814165a02500f046e2773f4ea894d10ed3017ac20454900d79d4a0322079f5b713cf0986aaf15fce0ec4a2479980c86 + languageName: node + linkType: hard + "diff@npm:^7.0.0": version: 7.0.0 resolution: "diff@npm:7.0.0" @@ -10258,7 +10800,7 @@ __metadata: languageName: node linkType: hard -"google-auth-library@npm:^9.14.2": +"google-auth-library@npm:^9.14.2, google-auth-library@npm:^9.15.0": version: 9.15.1 resolution: "google-auth-library@npm:9.15.1" dependencies: @@ -11458,6 +12000,13 @@ __metadata: languageName: node linkType: hard +"json-schema@npm:^0.4.0": + version: 0.4.0 + resolution: "json-schema@npm:0.4.0" + checksum: 10c0/d4a637ec1d83544857c1c163232f3da46912e971d5bf054ba44fdb88f07d8d359a462b4aec46f2745efbc57053365608d88bc1d7b1729f7b4fc3369765639ed3 + languageName: node + linkType: hard + "json-stable-stringify-without-jsonify@npm:^1.0.1": version: 1.0.1 resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" @@ -11490,6 +12039,19 @@ __metadata: languageName: node linkType: hard +"jsondiffpatch@npm:0.6.0": + version: 0.6.0 + resolution: "jsondiffpatch@npm:0.6.0" + dependencies: + "@types/diff-match-patch": "npm:^1.0.36" + chalk: "npm:^5.3.0" + diff-match-patch: "npm:^1.0.5" + bin: + jsondiffpatch: bin/jsondiffpatch.js + checksum: 10c0/f7822e48a8ef8b9f7c6024cc59b7d3707a9fe6d84fd776d169de5a1803ad551ffe7cfdc7587f3900f224bc70897355884ed43eb1c8ccd02e7f7b43a7ebcfed4f + languageName: node + linkType: hard + "jsonfile@npm:^4.0.0": version: 4.0.0 resolution: "jsonfile@npm:4.0.0" @@ -16438,6 +17000,13 @@ __metadata: languageName: node linkType: hard +"secure-json-parse@npm:^2.7.0": + version: 2.7.0 + resolution: "secure-json-parse@npm:2.7.0" + checksum: 10c0/f57eb6a44a38a3eeaf3548228585d769d788f59007454214fab9ed7f01fbf2e0f1929111da6db28cf0bcc1a2e89db5219a59e83eeaec3a54e413a0197ce879e4 + languageName: node + linkType: hard + "seek-bzip@npm:^1.0.5": version: 1.0.6 resolution: "seek-bzip@npm:1.0.6" @@ -17214,6 +17783,18 @@ __metadata: languageName: node linkType: hard +"swr@npm:^2.2.5": + version: 2.3.3 + resolution: "swr@npm:2.3.3" + dependencies: + dequal: "npm:^2.0.3" + use-sync-external-store: "npm:^1.4.0" + peerDependencies: + react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 10c0/882fc8291912860e0c50eae3470ebf0cd58b0144cb12adcc4b14c5cef913ea06479043830508d8b0b3d4061d99ad8dd52485c9c879fbd4e9b893484e6d8da9e3 + languageName: node + linkType: hard + "symbol-tree@npm:^3.2.4": version: 3.2.4 resolution: "symbol-tree@npm:3.2.4" @@ -17361,6 +17942,13 @@ __metadata: languageName: node linkType: hard +"throttleit@npm:2.1.0": + version: 2.1.0 + resolution: "throttleit@npm:2.1.0" + checksum: 10c0/1696ae849522cea6ba4f4f3beac1f6655d335e51b42d99215e196a718adced0069e48deaaf77f7e89f526ab31de5b5c91016027da182438e6f9280be2f3d5265 + languageName: node + linkType: hard + "through2@npm:4.0.2": version: 4.0.2 resolution: "through2@npm:4.0.2" @@ -17673,7 +18261,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.1, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.8.1": +"tslib@npm:^2.0.1, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.6.2, tslib@npm:^2.8.1": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 @@ -17753,7 +18341,7 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^5.4.3, typescript@npm:^5.6.2": +"typescript@npm:^5.0.0, typescript@npm:^5.4.3, typescript@npm:^5.6.2": version: 5.8.3 resolution: "typescript@npm:5.8.3" bin: @@ -17763,7 +18351,7 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@npm%3A^5.4.3#optional!builtin, typescript@patch:typescript@npm%3A^5.6.2#optional!builtin": +"typescript@patch:typescript@npm%3A^5.0.0#optional!builtin, typescript@patch:typescript@npm%3A^5.4.3#optional!builtin, typescript@patch:typescript@npm%3A^5.6.2#optional!builtin": version: 5.8.3 resolution: "typescript@patch:typescript@npm%3A5.8.3#optional!builtin::version=5.8.3&hash=5786d5" bin: