@spacex110/core 0.1.15 → 0.1.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/types.ts CHANGED
@@ -78,6 +78,13 @@ export interface Model {
78
78
  name: string;
79
79
  /** 模型能力列表(如 text, vision, audio) */
80
80
  capabilities?: ModelCapability[];
81
+ /**
82
+ * 模型输出能力(如 image, audio)。
83
+ * 与 capabilities 区分:capabilities 指模型能理解/处理哪些输入;
84
+ * outputCapabilities 指模型能生成哪些类型的输出。
85
+ * 当前仅在多模态输出场景(如 OpenRouter 文生图、Gemini 生图)使用。
86
+ */
87
+ outputCapabilities?: Array<'image' | 'audio'>;
81
88
  /** 上下文窗口大小 */
82
89
  contextLength?: number;
83
90
  }
@@ -161,3 +168,173 @@ export interface AIConfigFormProps {
161
168
  /** 是否禁用整个表单 */
162
169
  disabled?: boolean;
163
170
  }
171
+
172
+ // ============ Multimodal Chat Types ============
173
+
174
+ /**
175
+ * 多模态内容块(输入侧调用方传入格式)。
176
+ * 不同协议的 ContentPart 形态不同,这里提供统一的 OpenAI 风格接口作为上层标准。
177
+ */
178
+ export type ContentPart =
179
+ | { type: 'text'; text: string }
180
+ | { type: 'image_url'; image_url: { url: string; detail?: 'low' | 'high' | 'auto' } }
181
+ // Anthropic 风格图片块
182
+ | {
183
+ type: 'image';
184
+ source:
185
+ | { type: 'base64'; media_type: string; data: string }
186
+ | { type: 'url'; url: string };
187
+ }
188
+ // Gemini 风格 inline 数据块(图片/音频通用)
189
+ | { type: 'inline_data'; inline_data: { mime_type: string; data: string } }
190
+ // OpenAI 风格输入音频
191
+ | { type: 'audio'; input_audio: { data: string; format: 'wav' | 'mp3' } };
192
+
193
+ /**
194
+ * 多模态聊天消息。
195
+ * content 可以是纯文本字符串(兼容 sendDirectChat)或多模态内容块数组。
196
+ */
197
+ export interface ChatMessage {
198
+ role: 'system' | 'user' | 'assistant' | 'tool';
199
+ /**
200
+ * 消息内容:字符串走纯文本路径,多模态块数组走多模态路径。
201
+ */
202
+ content: string | ContentPart[];
203
+ /** 可选的消息名(部分协议支持) */
204
+ name?: string;
205
+ }
206
+
207
+ /**
208
+ * 内部统一的多模态内容块。
209
+ * 各协议策略都接收 NormalizedMessage[] 作为输入,避免重复处理不同协议字段差异。
210
+ */
211
+ export type NormalizedPart =
212
+ | { type: 'text'; data: string; meta?: Record<string, unknown> }
213
+ | { type: 'image'; data: string; mimeType?: string; meta?: Record<string, unknown> }
214
+ | { type: 'audio'; data: string; mimeType?: string; meta?: Record<string, unknown> };
215
+
216
+ /** 内部统一的消息结构 */
217
+ export interface NormalizedMessage {
218
+ role: 'system' | 'user' | 'assistant' | 'tool';
219
+ parts: NormalizedPart[];
220
+ }
221
+
222
+ /**
223
+ * 响应侧的内容块。
224
+ * 文本部分用 string;多模态用数组,每个元素描述一种产出(文本/图片/音频)。
225
+ */
226
+ export type ContentResponsePart =
227
+ | { type: 'text'; text: string }
228
+ | { type: 'image'; url?: string; b64_json?: string; mimeType?: string }
229
+ | { type: 'audio'; url?: string; b64_json?: string; mimeType?: string };
230
+
231
+ /** 各协议策略解析后的统一响应结构 */
232
+ export interface ResponseMessage {
233
+ role: 'assistant';
234
+ /**
235
+ * 响应内容:纯文本时用 string,包含图片/音频时用 ContentResponsePart 数组。
236
+ */
237
+ content: string | ContentResponsePart[];
238
+ /** token 用量(如协议提供) */
239
+ usage?: {
240
+ inputTokens?: number;
241
+ outputTokens?: number;
242
+ totalTokens?: number;
243
+ };
244
+ /** 原始协议响应(调试/透传用) */
245
+ raw?: unknown;
246
+ /** 结束原因(如 'stop'、'length'、'tool_calls') */
247
+ finishReason?: string;
248
+ }
249
+
250
+ /**
251
+ * 调用 sendMultimodalChat / sendMultimodalChatStream 的输入参数。
252
+ * 与 sendDirectChat 不同:messages 字段是 ChatMessage[](支持 content: string | ContentPart[])。
253
+ */
254
+ export interface MultimodalChatOptions {
255
+ /** 协议类型 */
256
+ apiFormat: ApiFormat;
257
+ /** API Key */
258
+ apiKey: string;
259
+ /** 模型 ID */
260
+ model: string;
261
+ /** 厂商 Base URL */
262
+ baseUrl: string;
263
+ /** 聊天消息列表(支持多模态) */
264
+ messages: ChatMessage[];
265
+ /** 最大输出 token */
266
+ maxTokens?: number;
267
+ /** 温度 */
268
+ temperature?: number;
269
+ /** 请求超时(毫秒) */
270
+ timeoutMs?: number;
271
+ /**
272
+ * 期望的输出模态。
273
+ * - 仅在 OpenRouter(OpenAI 协议)或 Gemini 协议下生效;其他协议传入 image 会直接报错
274
+ * - 示例:['text']、['text', 'image']
275
+ */
276
+ outputModalities?: Array<'text' | 'image'>;
277
+ /** 透传给 fetch 的额外 headers(用于透传 Authorization 代理等) */
278
+ extraHeaders?: Record<string, string>;
279
+ }
280
+
281
+ /** 非流式多模态聊天结果 */
282
+ export interface MultimodalChatResult {
283
+ success: boolean;
284
+ /** 纯文本内容(仅当响应只有文本时填充) */
285
+ text?: string;
286
+ /** 多模态产出(文本/图片/音频混排;与 text 二选一) */
287
+ images?: Array<{
288
+ type: 'image';
289
+ url?: string;
290
+ b64_json?: string;
291
+ mimeType?: string;
292
+ }>;
293
+ /** token 用量 */
294
+ usage?: {
295
+ inputTokens?: number;
296
+ outputTokens?: number;
297
+ totalTokens?: number;
298
+ };
299
+ /** 耗时(毫秒) */
300
+ latencyMs?: number;
301
+ /** 错误信息(success=false 时填充) */
302
+ message?: string;
303
+ /** 结束原因 */
304
+ finishReason?: string;
305
+ /** 协议原始响应 */
306
+ raw?: unknown;
307
+ }
308
+
309
+ /** 流式多模态聊天的增量回调状态 */
310
+ export interface MultimodalStreamDelta {
311
+ /** 累计的完整文本 */
312
+ text?: string;
313
+ /** 累计的图片数组(每次浅拷贝替换,不要 append) */
314
+ images?: Array<{
315
+ type: 'image';
316
+ url?: string;
317
+ b64_json?: string;
318
+ mimeType?: string;
319
+ }>;
320
+ /** 结束原因(最后一片 chunk 时填充) */
321
+ finishReason?: string;
322
+ /** token 用量(最后一片 chunk 时填充) */
323
+ usage?: {
324
+ inputTokens?: number;
325
+ outputTokens?: number;
326
+ totalTokens?: number;
327
+ };
328
+ }
329
+
330
+ /** 流式多模态聊天入参 */
331
+ export interface MultimodalChatStreamOptions extends Omit<MultimodalChatOptions, 'timeoutMs'> {
332
+ /**
333
+ * 增量回调,每次收到协议 chunk 时触发。
334
+ * state.text 是累计完整文本(同 sendDirectChatStream 约定);
335
+ * state.images 是累计完整图片数组(图片一般整块出现,浅拷贝给上层)。
336
+ */
337
+ onDelta: (state: MultimodalStreamDelta) => void;
338
+ /** 可选超时(毫秒) */
339
+ timeoutMs?: number;
340
+ }
@@ -1,276 +0,0 @@
1
- import { AIConfig, Provider, Model, ModelCapability, StorageAdapter, ApiFormat } from './types';
2
-
3
- /** 通道配置(扩展 AIConfig,包含更多元数据) */
4
- export interface ChannelConfig extends AIConfig {
5
- /** 通道唯一标识 */
6
- id: string;
7
- /** 通道名称(用户自定义) */
8
- name?: string;
9
- /** Provider 名称 */
10
- providerName: string;
11
- /** 模型显示名称 */
12
- modelName: string;
13
- /** API 格式 */
14
- apiFormat: ApiFormat;
15
- /** 模型能力列表 */
16
- capabilities?: ModelCapability[];
17
- /** 上下文窗口大小 */
18
- contextLength?: number;
19
- /** 创建时间 */
20
- createdAt: number;
21
- /** 最后使用时间 */
22
- lastUsedAt?: number;
23
- /** 连接状态 */
24
- status?: 'untested' | 'connected' | 'error';
25
- /** 最后错误信息 */
26
- lastError?: string;
27
- }
28
- /** 通道管理器配置选项 */
29
- export interface ChannelManagerOptions {
30
- /** 存储适配器(默认使用加密存储) */
31
- storageAdapter?: StorageAdapter;
32
- /** 存储键名前缀 */
33
- storagePrefix?: string;
34
- /** 当前激活通道的存储键 */
35
- activeChannelKey?: string;
36
- /** 能力默认通道的存储键 */
37
- capabilityDefaultsKey?: string;
38
- /** 后端代理地址(可选,用于解决 CORS 问题) */
39
- proxyUrl?: string;
40
- }
41
- /** 通道查询过滤条件 */
42
- export interface ChannelFilter {
43
- /** 按 Provider ID 过滤 */
44
- providerId?: string;
45
- /** 按 API 格式过滤 */
46
- apiFormat?: ApiFormat;
47
- /** 按模型能力过滤 */
48
- capability?: ModelCapability;
49
- /** 按连接状态过滤 */
50
- status?: ChannelConfig['status'];
51
- /** 关键字搜索(匹配名称、模型名、Provider 名) */
52
- keyword?: string;
53
- }
54
- /** 聊天结果 */
55
- export interface ChatResult {
56
- success: boolean;
57
- content?: string;
58
- message?: string;
59
- latencyMs?: number;
60
- channelId?: string;
61
- model?: string;
62
- }
63
- /** 事件类型 */
64
- export type ChannelEventType = 'add' | 'update' | 'delete' | 'activate' | 'chat' | 'test' | 'clear';
65
- type ChannelEventListener = (data: any) => void;
66
- export declare class AIChannelManager {
67
- private storageAdapter;
68
- private channels;
69
- private activeChannelId;
70
- private storagePrefix;
71
- private activeChannelKey;
72
- private capabilityDefaultsKey;
73
- private capabilityDefaults;
74
- private proxyUrl?;
75
- private listeners;
76
- constructor(options?: ChannelManagerOptions);
77
- /** 监听事件 */
78
- on(event: ChannelEventType, listener: ChannelEventListener): () => void;
79
- /** 取消监听 */
80
- off(event: ChannelEventType, listener: ChannelEventListener): void;
81
- private emit;
82
- private getStorageKey;
83
- private loadChannels;
84
- private loadActiveChannel;
85
- private saveChannel;
86
- private deleteChannelFromStorage;
87
- private saveActiveChannel;
88
- private loadCapabilityDefaults;
89
- private saveCapabilityDefaults;
90
- /** 添加通道 */
91
- addChannel(config: AIConfig, name?: string): Promise<ChannelConfig>;
92
- /** 删除通道 */
93
- deleteChannel(id: string): void;
94
- /** 更新通道 */
95
- updateChannel(id: string, config: Partial<AIConfig>, name?: string): Promise<ChannelConfig>;
96
- /** 获取所有通道 */
97
- getChannels(): ChannelConfig[];
98
- /** 根据 ID 获取通道 */
99
- getChannel(id: string): ChannelConfig | undefined;
100
- /** 按 Provider ID 过滤通道 */
101
- getChannelsByProvider(providerId: string): ChannelConfig[];
102
- /** 按模型能力过滤通道(如 vision, reasoning, audio) */
103
- getChannelsByCapability(capability: ModelCapability): ChannelConfig[];
104
- /** 按 API 格式过滤通道(如 openai, anthropic, gemini) */
105
- getChannelsByFormat(format: ApiFormat): ChannelConfig[];
106
- /** 按连接状态过滤通道 */
107
- getChannelsByStatus(status: ChannelConfig['status']): ChannelConfig[];
108
- /** 综合条件查询通道 */
109
- queryChannels(filter: ChannelFilter): ChannelConfig[];
110
- /** 获取通道数量 */
111
- getChannelCount(): number;
112
- /** 获取当前激活的通道 */
113
- getActiveChannel(): ChannelConfig | undefined;
114
- /** 设置当前激活的通道 */
115
- setActiveChannel(id: string): void;
116
- /** 清除当前激活的通道 */
117
- clearActiveChannel(): void;
118
- /**
119
- * 为指定能力类型设置默认通道
120
- * 当调用 getChannelForCapability 时,优先返回此通道
121
- */
122
- setDefaultForCapability(capability: ModelCapability, channelId: string): void;
123
- /**
124
- * 获取指定能力类型的默认通道 ID
125
- * 返回 undefined 表示未设置
126
- */
127
- getDefaultForCapability(capability: ModelCapability): string | undefined;
128
- /**
129
- * 清除指定能力类型的默认通道
130
- */
131
- clearDefaultForCapability(capability: ModelCapability): void;
132
- /**
133
- * 获取所有能力类型的默认通道映射
134
- * 返回 { capability: channelId } 的对象
135
- */
136
- getAllCapabilityDefaults(): Record<string, string>;
137
- /**
138
- * 根据能力类型获取最适合的通道(带降级链)
139
- *
140
- * 降级链:
141
- * 1. 该能力类型的显式默认通道
142
- * 2. 具有该能力且最后使用时间最新的通道
143
- * 3. 全局激活通道
144
- * 4. 第一个可用通道
145
- */
146
- getChannelForCapability(capability: ModelCapability): ChannelConfig | undefined;
147
- /**
148
- * 使用指定能力类型的默认通道发送聊天请求
149
- * 自动选择合适的通道,无需手动指定 channelId
150
- */
151
- chatForCapability(capability: ModelCapability, message: string, options?: {
152
- messages?: Array<{
153
- role: string;
154
- content: string;
155
- }>;
156
- maxTokens?: number;
157
- }): Promise<ChatResult>;
158
- /**
159
- * 使用指定能力类型的默认通道发送流式聊天请求
160
- */
161
- chatStreamForCapability(capability: ModelCapability, message: string, options?: {
162
- messages?: Array<{
163
- role: string;
164
- content: string;
165
- }>;
166
- maxTokens?: number;
167
- signal?: AbortSignal;
168
- onDelta?: (full: string) => void;
169
- }): Promise<ChatResult>;
170
- /** 获取 Provider 的可用模型列表(动态获取 + 静态兜底) */
171
- getProviderModels(providerId: string, apiKey?: string, baseUrl?: string): Promise<Model[]>;
172
- /** 获取通道对应的 Provider 的模型列表 */
173
- getChannelModels(id: string): Promise<Model[]>;
174
- /** 获取 Provider 的静态模型列表(不发起网络请求) */
175
- getStaticModelList(providerId: string): Model[];
176
- /** 按能力过滤模型列表 */
177
- getModelsByCapability(models: Model[], capability: ModelCapability): Model[];
178
- /** 获取所有已配置的模型摘要列表 */
179
- getConfiguredModels(): Array<{
180
- channelId: string;
181
- providerId: string;
182
- providerName: string;
183
- model: string;
184
- modelName: string;
185
- apiFormat: ApiFormat;
186
- capabilities: ModelCapability[];
187
- status: ChannelConfig['status'];
188
- }>;
189
- /** 更新通道的 API Key */
190
- updateApiKey(id: string, apiKey: string): Promise<ChannelConfig>;
191
- /** 验证 API Key 格式(简单校验,非空且长度合理) */
192
- validateApiKey(providerId: string, apiKey: string): {
193
- valid: boolean;
194
- message?: string;
195
- };
196
- /** 脱敏显示 API Key(如 sk-••••••••J4xK) */
197
- maskApiKey(apiKey: string): string;
198
- /** 获取通道的脱敏 API Key */
199
- getMaskedApiKey(id: string): string;
200
- /** 使用当前激活的通道发送聊天请求 */
201
- chat(message: string, options?: {
202
- messages?: Array<{
203
- role: string;
204
- content: string;
205
- }>;
206
- maxTokens?: number;
207
- }): Promise<ChatResult>;
208
- /** 使用指定通道发送聊天请求 */
209
- chatWith(channelId: string, message: string, options?: {
210
- messages?: Array<{
211
- role: string;
212
- content: string;
213
- }>;
214
- maxTokens?: number;
215
- }): Promise<ChatResult>;
216
- /** 使用当前激活通道发送流式聊天。onDelta 每次收到「累计完整文本」。 */
217
- chatStream(message: string, options: {
218
- messages?: Array<{
219
- role: string;
220
- content: string;
221
- }>;
222
- maxTokens?: number;
223
- onDelta: (full: string) => void;
224
- signal?: AbortSignal;
225
- }): Promise<ChatResult>;
226
- /** 使用指定通道发送流式聊天。onDelta 每次收到「累计完整文本」。 */
227
- chatWithStream(channelId: string, message: string, options: {
228
- messages?: Array<{
229
- role: string;
230
- content: string;
231
- }>;
232
- maxTokens?: number;
233
- onDelta: (full: string) => void;
234
- signal?: AbortSignal;
235
- }): Promise<ChatResult>;
236
- /** 测试指定通道的连接 */
237
- testChannel(id: string): Promise<{
238
- success: boolean;
239
- latencyMs?: number;
240
- message?: string;
241
- }>;
242
- /** 测试所有通道连接 */
243
- testAllChannels(): Promise<Array<{
244
- id: string;
245
- channel: ChannelConfig;
246
- result: {
247
- success: boolean;
248
- latencyMs?: number;
249
- message?: string;
250
- };
251
- }>>;
252
- /** 获取所有可用的 Provider */
253
- getAvailableProviders(): Provider[];
254
- /** 获取单个 Provider 信息 */
255
- getProvider(providerId: string): Provider | undefined;
256
- /** 按 API 格式获取 Provider 列表 */
257
- getProvidersByFormat(format: ApiFormat): Provider[];
258
- /** 导出所有通道配置(不包含 API Key 明文) */
259
- exportChannels(includeApiKeys?: boolean): string;
260
- /** 导入通道配置 */
261
- importChannels(json: string, merge?: boolean): Promise<ChannelConfig[]>;
262
- /** 清空所有通道 */
263
- clearAllChannels(): void;
264
- /** 批量删除通道 */
265
- deleteChannels(ids: string[]): void;
266
- /** 获取统计信息 */
267
- getStats(): {
268
- total: number;
269
- byStatus: Record<string, number>;
270
- byFormat: Record<string, number>;
271
- byProvider: Record<string, number>;
272
- byCapability: Record<string, number>;
273
- };
274
- }
275
- export {};
276
- //# sourceMappingURL=channel-manager.d.ts.map