@huyooo/ai-chat-core 0.2.19 → 0.2.21
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/dist/events.d.ts +452 -0
- package/dist/events.js +1 -0
- package/dist/index.d.ts +202 -550
- package/dist/index.js +1 -1
- package/package.json +23 -4
- package/src/agent.ts +399 -0
- package/src/constants.ts +125 -0
- package/src/events.ts +797 -0
- package/src/index.ts +309 -0
- package/src/internal/update-plan.ts +2 -0
- package/src/internal/web-search.ts +78 -0
- package/src/mcp/client-manager.ts +301 -0
- package/src/mcp/index.ts +2 -0
- package/src/mcp/types.ts +43 -0
- package/src/providers/context-compressor.ts +149 -0
- package/src/providers/index.ts +120 -0
- package/src/providers/model-registry.ts +320 -0
- package/src/providers/orchestrator.ts +761 -0
- package/src/providers/protocols/anthropic.ts +406 -0
- package/src/providers/protocols/ark.ts +362 -0
- package/src/providers/protocols/deepseek.ts +344 -0
- package/src/providers/protocols/error-utils.ts +74 -0
- package/src/providers/protocols/gemini.ts +350 -0
- package/src/providers/protocols/index.ts +36 -0
- package/src/providers/protocols/openai.ts +420 -0
- package/src/providers/protocols/qwen.ts +326 -0
- package/src/providers/protocols/types.ts +189 -0
- package/src/providers/types.ts +272 -0
- package/src/providers/unified-adapter.ts +367 -0
- package/src/router.ts +72 -0
- package/src/test-utils/mock-sse.ts +32 -0
- package/src/tools.ts +162 -0
- package/src/types.ts +531 -0
- package/src/utils.ts +86 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Protocol 错误处理工具
|
|
3
|
+
*
|
|
4
|
+
* 将各种 API 错误(HTTP status + JSON body / SDK 异常)转换为用户友好的消息。
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** HTTP 状态码 → 友好消息 */
|
|
8
|
+
const STATUS_MESSAGES: Record<number, string> = {
|
|
9
|
+
400: '请求参数错误',
|
|
10
|
+
401: 'API 认证失败,请检查 API Key 配置',
|
|
11
|
+
402: '账户余额不足,请充值后重试',
|
|
12
|
+
403: '没有权限访问此模型',
|
|
13
|
+
404: '请求的模型或接口不存在',
|
|
14
|
+
429: '请求过于频繁,请稍后重试',
|
|
15
|
+
500: 'API 服务器内部错误,请稍后重试',
|
|
16
|
+
502: 'API 网关错误,请稍后重试',
|
|
17
|
+
503: 'API 服务暂时不可用,请稍后重试',
|
|
18
|
+
504: 'API 请求超时,请稍后重试',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 从 HTTP 响应中提取用户友好的错误消息
|
|
23
|
+
*
|
|
24
|
+
* @param status HTTP 状态码
|
|
25
|
+
* @param body 原始响应体字符串
|
|
26
|
+
* @param providerName 供应商名称(如 "Gemini"、"OpenAI")
|
|
27
|
+
*/
|
|
28
|
+
export function friendlyHttpError(status: number, body: string, providerName: string): string {
|
|
29
|
+
// 1. 尝试从 JSON body 提取 message
|
|
30
|
+
const parsed = tryParseErrorBody(body);
|
|
31
|
+
const apiMessage = parsed?.message;
|
|
32
|
+
|
|
33
|
+
// 2. 已知 status → 友好中文
|
|
34
|
+
const statusMessage = STATUS_MESSAGES[status];
|
|
35
|
+
if (statusMessage) {
|
|
36
|
+
// 如果有 API 返回的具体消息且不太长,附在后面
|
|
37
|
+
if (apiMessage && apiMessage.length <= 100) {
|
|
38
|
+
return `${statusMessage}(${apiMessage})`;
|
|
39
|
+
}
|
|
40
|
+
return statusMessage;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 3. 未知 status,但有 API 消息
|
|
44
|
+
if (apiMessage) {
|
|
45
|
+
const msg = apiMessage.length > 200 ? apiMessage.slice(0, 200) + '...' : apiMessage;
|
|
46
|
+
return `${providerName} 错误 (${status}): ${msg}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 4. 纯兜底
|
|
50
|
+
return `${providerName} 错误 (${status})`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 尝试从 JSON 响应体中提取 error.message
|
|
55
|
+
* 兼容格式:
|
|
56
|
+
* { "error": { "message": "..." } } — OpenAI / Gemini / Vercel
|
|
57
|
+
* { "error_msg": "..." } — ARK
|
|
58
|
+
* { "message": "..." } — 通用
|
|
59
|
+
*/
|
|
60
|
+
function tryParseErrorBody(body: string): { message?: string; type?: string } | null {
|
|
61
|
+
try {
|
|
62
|
+
const json = JSON.parse(body);
|
|
63
|
+
if (json?.error?.message) {
|
|
64
|
+
return { message: json.error.message, type: json.error.type };
|
|
65
|
+
}
|
|
66
|
+
if (typeof json?.error_msg === 'string') {
|
|
67
|
+
return { message: json.error_msg };
|
|
68
|
+
}
|
|
69
|
+
if (typeof json?.message === 'string') {
|
|
70
|
+
return { message: json.message };
|
|
71
|
+
}
|
|
72
|
+
} catch { /* not JSON */ }
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini Protocol(Google Gemini API)
|
|
3
|
+
*
|
|
4
|
+
* 只负责:
|
|
5
|
+
* - HTTP 请求发送
|
|
6
|
+
* - SSE 流解析
|
|
7
|
+
* - 原始事件产出
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
Protocol,
|
|
12
|
+
ProtocolConfig,
|
|
13
|
+
ProtocolMessage,
|
|
14
|
+
ProtocolToolDefinition,
|
|
15
|
+
ProtocolRequestOptions,
|
|
16
|
+
RawEvent,
|
|
17
|
+
RawToolCall,
|
|
18
|
+
RawSearchResult,
|
|
19
|
+
} from './types';
|
|
20
|
+
import { DebugLogger } from '../../utils';
|
|
21
|
+
import { friendlyHttpError } from './error-utils';
|
|
22
|
+
|
|
23
|
+
const logger = DebugLogger.module('GeminiProtocol');
|
|
24
|
+
|
|
25
|
+
const DEFAULT_GEMINI_URL = 'https://generativelanguage.googleapis.com/v1beta';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 历史中无 thoughtSignature 时使用的占位值(跳过 Gemini 校验)。
|
|
29
|
+
* 见 https://ai.google.dev/gemini-api/docs/thought-signatures
|
|
30
|
+
*/
|
|
31
|
+
const GEMINI_THOUGHT_SIGNATURE_DUMMY = 'skip_thought_signature_validator';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Gemini Protocol 实现
|
|
35
|
+
*/
|
|
36
|
+
export class GeminiProtocol implements Protocol {
|
|
37
|
+
readonly name = 'gemini';
|
|
38
|
+
|
|
39
|
+
private apiKey: string;
|
|
40
|
+
private apiUrl: string;
|
|
41
|
+
|
|
42
|
+
constructor(config: ProtocolConfig) {
|
|
43
|
+
this.apiKey = config.apiKey;
|
|
44
|
+
this.apiUrl = config.apiUrl ?? DEFAULT_GEMINI_URL;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 发送请求并返回原始事件流
|
|
49
|
+
*/
|
|
50
|
+
async *stream(
|
|
51
|
+
messages: ProtocolMessage[],
|
|
52
|
+
tools: ProtocolToolDefinition[],
|
|
53
|
+
options: ProtocolRequestOptions
|
|
54
|
+
): AsyncGenerator<RawEvent> {
|
|
55
|
+
const requestBody = this.buildRequestBody(messages, tools, options);
|
|
56
|
+
const url = `${this.apiUrl}/models/${options.model}:streamGenerateContent?key=${this.apiKey}&alt=sse`;
|
|
57
|
+
|
|
58
|
+
logger.debug('发送 Gemini 请求', {
|
|
59
|
+
url: url.replace(this.apiKey, '***'),
|
|
60
|
+
model: options.model,
|
|
61
|
+
enableSearch: options.enableSearch,
|
|
62
|
+
enableThinking: options.enableThinking,
|
|
63
|
+
toolsCount: tools.length,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const response = await fetch(url, {
|
|
67
|
+
method: 'POST',
|
|
68
|
+
headers: { 'Content-Type': 'application/json' },
|
|
69
|
+
body: JSON.stringify(requestBody),
|
|
70
|
+
signal: options.signal,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
if (!response.ok) {
|
|
74
|
+
const errorText = await response.text();
|
|
75
|
+
logger.error('Gemini API 错误', { status: response.status, body: errorText.slice(0, 500) });
|
|
76
|
+
yield { type: 'error', error: friendlyHttpError(response.status, errorText, 'Gemini') };
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const reader = response.body?.getReader();
|
|
81
|
+
if (!reader) {
|
|
82
|
+
yield { type: 'error', error: '无法获取响应流' };
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
yield* this.parseSSE(reader);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 构建请求体
|
|
91
|
+
*/
|
|
92
|
+
private buildRequestBody(
|
|
93
|
+
messages: ProtocolMessage[],
|
|
94
|
+
tools: ProtocolToolDefinition[],
|
|
95
|
+
options: ProtocolRequestOptions
|
|
96
|
+
): Record<string, unknown> {
|
|
97
|
+
const { systemInstruction, contents } = this.convertMessages(messages);
|
|
98
|
+
|
|
99
|
+
const body: Record<string, unknown> = {
|
|
100
|
+
contents,
|
|
101
|
+
generationConfig: {
|
|
102
|
+
maxOutputTokens: options.familyConfig.defaultMaxTokens ?? 65536,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
if (systemInstruction) {
|
|
107
|
+
body.systemInstruction = systemInstruction;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 启用 thinking(需要 includeThoughts 才能输出思考内容)
|
|
111
|
+
if (options.enableThinking) {
|
|
112
|
+
(body.generationConfig as Record<string, unknown>).thinkingConfig = {
|
|
113
|
+
thinkingBudget: 24576,
|
|
114
|
+
includeThoughts: true,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 构建工具
|
|
119
|
+
// 注意:Gemini 的 googleSearch 工具不能与其他函数调用工具同时使用
|
|
120
|
+
// 因此:如果有其他工具,则通过 web_search 工具(Tavily)进行搜索
|
|
121
|
+
// 如果没有其他工具,可以使用原生 googleSearch
|
|
122
|
+
const geminiTools: unknown[] = [];
|
|
123
|
+
|
|
124
|
+
// 添加函数调用工具:按名称去重(混合模式可能传入重复)
|
|
125
|
+
if (tools.length > 0) {
|
|
126
|
+
const decls = tools.map(t => ({
|
|
127
|
+
name: t.name,
|
|
128
|
+
description: t.description,
|
|
129
|
+
parameters: t.parameters,
|
|
130
|
+
}));
|
|
131
|
+
const byName = new Map<string, { name: string; description: string; parameters: object }>();
|
|
132
|
+
for (const d of decls) {
|
|
133
|
+
if (!byName.has(d.name)) byName.set(d.name, d);
|
|
134
|
+
}
|
|
135
|
+
geminiTools.push({
|
|
136
|
+
functionDeclarations: Array.from(byName.values()),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
// 仅在没有其他工具时使用原生 Google Search
|
|
140
|
+
else if (options.enableSearch) {
|
|
141
|
+
geminiTools.push({ googleSearch: {} });
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (geminiTools.length > 0) {
|
|
145
|
+
body.tools = geminiTools;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return body;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* 转换消息格式
|
|
153
|
+
*/
|
|
154
|
+
private convertMessages(messages: ProtocolMessage[]): {
|
|
155
|
+
systemInstruction?: { parts: { text: string }[] };
|
|
156
|
+
contents: unknown[];
|
|
157
|
+
} {
|
|
158
|
+
let systemInstruction: { parts: { text: string }[] } | undefined;
|
|
159
|
+
const contents: unknown[] = [];
|
|
160
|
+
|
|
161
|
+
for (const msg of messages) {
|
|
162
|
+
switch (msg.role) {
|
|
163
|
+
case 'system':
|
|
164
|
+
systemInstruction = { parts: [{ text: msg.content }] };
|
|
165
|
+
break;
|
|
166
|
+
|
|
167
|
+
case 'user': {
|
|
168
|
+
// 当只有图片没有文字时提供默认提示
|
|
169
|
+
const textContent = msg.content || (msg.images?.length ? '请分析这张图片' : '');
|
|
170
|
+
const parts: unknown[] = [{ text: textContent }];
|
|
171
|
+
if (msg.images?.length) {
|
|
172
|
+
for (const img of msg.images) {
|
|
173
|
+
if (img.startsWith('data:')) {
|
|
174
|
+
const match = img.match(/^data:([^;]+);base64,(.+)$/);
|
|
175
|
+
if (match) {
|
|
176
|
+
parts.push({
|
|
177
|
+
inlineData: { mimeType: match[1], data: match[2] },
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
} else {
|
|
181
|
+
parts.push({
|
|
182
|
+
inlineData: { mimeType: 'image/jpeg', data: img },
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
contents.push({ role: 'user', parts });
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
case 'assistant':
|
|
192
|
+
if (msg.toolCalls?.length) {
|
|
193
|
+
const parts: unknown[] = [];
|
|
194
|
+
for (const tc of msg.toolCalls) {
|
|
195
|
+
const funcPart: Record<string, unknown> = {
|
|
196
|
+
functionCall: {
|
|
197
|
+
name: tc.name,
|
|
198
|
+
args: JSON.parse(tc.arguments || '{}'),
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
// Gemini 3:每个 functionCall part 必须带 thoughtSignature,否则 400。
|
|
202
|
+
// 历史/跨模型回放可能没有,用官方 dummy 跳过校验。见 thought-signatures 文档。
|
|
203
|
+
funcPart.thoughtSignature = tc.thoughtSignature ?? GEMINI_THOUGHT_SIGNATURE_DUMMY;
|
|
204
|
+
parts.push(funcPart);
|
|
205
|
+
}
|
|
206
|
+
contents.push({ role: 'model', parts });
|
|
207
|
+
} else {
|
|
208
|
+
contents.push({ role: 'model', parts: [{ text: msg.content }] });
|
|
209
|
+
}
|
|
210
|
+
break;
|
|
211
|
+
|
|
212
|
+
case 'tool':
|
|
213
|
+
contents.push({
|
|
214
|
+
role: 'user',
|
|
215
|
+
parts: [{
|
|
216
|
+
functionResponse: {
|
|
217
|
+
name: msg.toolName || 'unknown',
|
|
218
|
+
response: { result: msg.content },
|
|
219
|
+
},
|
|
220
|
+
}],
|
|
221
|
+
});
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return { systemInstruction, contents };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* 解析 SSE 流
|
|
231
|
+
*/
|
|
232
|
+
private async *parseSSE(reader: ReadableStreamDefaultReader<Uint8Array>): AsyncGenerator<RawEvent> {
|
|
233
|
+
const decoder = new TextDecoder();
|
|
234
|
+
let buffer = '';
|
|
235
|
+
const pendingToolCalls = new Map<string, RawToolCall>();
|
|
236
|
+
let textStarted = false;
|
|
237
|
+
let toolCallIndex = 0;
|
|
238
|
+
|
|
239
|
+
while (true) {
|
|
240
|
+
const { done, value } = await reader.read();
|
|
241
|
+
if (done) break;
|
|
242
|
+
|
|
243
|
+
buffer += decoder.decode(value, { stream: true });
|
|
244
|
+
const lines = buffer.split('\n');
|
|
245
|
+
buffer = lines.pop() || '';
|
|
246
|
+
|
|
247
|
+
for (const line of lines) {
|
|
248
|
+
if (!line.startsWith('data:')) continue;
|
|
249
|
+
|
|
250
|
+
const data = line.slice(5).trim();
|
|
251
|
+
if (!data) continue;
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
const json = JSON.parse(data);
|
|
255
|
+
const candidate = json.candidates?.[0];
|
|
256
|
+
if (!candidate?.content?.parts) continue;
|
|
257
|
+
|
|
258
|
+
for (const part of candidate.content.parts) {
|
|
259
|
+
// 处理文本(根据 thought 标志区分思考和回复)
|
|
260
|
+
if (part.text) {
|
|
261
|
+
if (part.thought === true) {
|
|
262
|
+
// 思考内容
|
|
263
|
+
yield { type: 'thinking_delta', delta: part.text };
|
|
264
|
+
} else {
|
|
265
|
+
// 正常回复
|
|
266
|
+
if (!textStarted) {
|
|
267
|
+
textStarted = true;
|
|
268
|
+
yield { type: 'thinking_done' };
|
|
269
|
+
}
|
|
270
|
+
yield { type: 'text_delta', delta: part.text };
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// 处理函数调用
|
|
275
|
+
if (part.functionCall) {
|
|
276
|
+
const callId = `gemini-${toolCallIndex++}`;
|
|
277
|
+
const toolCall: RawToolCall = {
|
|
278
|
+
id: callId,
|
|
279
|
+
name: part.functionCall.name,
|
|
280
|
+
arguments: JSON.stringify(part.functionCall.args || {}),
|
|
281
|
+
};
|
|
282
|
+
// 捕获 thoughtSignature
|
|
283
|
+
if (part.thoughtSignature) {
|
|
284
|
+
toolCall.thoughtSignature = part.thoughtSignature;
|
|
285
|
+
}
|
|
286
|
+
pendingToolCalls.set(callId, toolCall);
|
|
287
|
+
yield { type: 'tool_call_start', toolCall: { id: callId, name: toolCall.name } };
|
|
288
|
+
yield { type: 'tool_call_done', toolCall };
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// 处理 grounding metadata(搜索结果)
|
|
293
|
+
const groundingMeta = candidate.groundingMetadata;
|
|
294
|
+
if (groundingMeta?.groundingChunks?.length) {
|
|
295
|
+
const searchResults: RawSearchResult[] = [];
|
|
296
|
+
for (const chunk of groundingMeta.groundingChunks) {
|
|
297
|
+
if (chunk.web?.uri) {
|
|
298
|
+
searchResults.push({
|
|
299
|
+
title: chunk.web.title || '',
|
|
300
|
+
url: chunk.web.uri,
|
|
301
|
+
snippet: '',
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (searchResults.length > 0) {
|
|
306
|
+
yield { type: 'search_result', searchResults };
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// 检查是否结束
|
|
311
|
+
if (candidate.finishReason) {
|
|
312
|
+
// 提取 Token 使用统计(Gemini usageMetadata)
|
|
313
|
+
const meta = json.usageMetadata;
|
|
314
|
+
const usage = meta ? {
|
|
315
|
+
promptTokens: meta.promptTokenCount || 0,
|
|
316
|
+
completionTokens: meta.candidatesTokenCount || 0,
|
|
317
|
+
totalTokens: meta.totalTokenCount || 0,
|
|
318
|
+
reasoningTokens: meta.thoughtsTokenCount || 0,
|
|
319
|
+
cachedTokens: meta.cachedContentTokenCount || 0,
|
|
320
|
+
} : undefined;
|
|
321
|
+
|
|
322
|
+
if (pendingToolCalls.size > 0) {
|
|
323
|
+
yield { type: 'done', finishReason: 'tool_calls', usage };
|
|
324
|
+
} else {
|
|
325
|
+
yield { type: 'done', finishReason: 'stop', usage };
|
|
326
|
+
}
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
} catch {
|
|
330
|
+
// 忽略解析错误
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// 兜底
|
|
336
|
+
if (pendingToolCalls.size > 0) {
|
|
337
|
+
yield { type: 'done', finishReason: 'tool_calls' };
|
|
338
|
+
} else {
|
|
339
|
+
yield { type: 'done', finishReason: 'stop' };
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* 创建 Gemini Protocol
|
|
346
|
+
*/
|
|
347
|
+
export function createGeminiProtocol(config: ProtocolConfig): GeminiProtocol {
|
|
348
|
+
return new GeminiProtocol(config);
|
|
349
|
+
}
|
|
350
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Protocol Layer 导出
|
|
3
|
+
*
|
|
4
|
+
* Protocol 只负责 HTTP/SSE 通信,不处理业务逻辑
|
|
5
|
+
*
|
|
6
|
+
* 每个 Protocol 对应一种 API 协议:
|
|
7
|
+
* - ArkProtocol: 火山引擎 Responses API(豆包/DeepSeek)
|
|
8
|
+
* - QwenProtocol: 通义千问 DashScope API
|
|
9
|
+
* - GeminiProtocol: Google Gemini API
|
|
10
|
+
* - OpenAIProtocol: OpenAI API(通过 OpenRouter)
|
|
11
|
+
* - AnthropicProtocol: Anthropic API(通过 OpenRouter)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// 类型
|
|
15
|
+
export type {
|
|
16
|
+
RawEventType,
|
|
17
|
+
RawEvent,
|
|
18
|
+
RawToolCall,
|
|
19
|
+
RawSearchResult,
|
|
20
|
+
ProtocolToolCall,
|
|
21
|
+
ProtocolMessage,
|
|
22
|
+
ProtocolToolDefinition,
|
|
23
|
+
ProtocolRequestOptions,
|
|
24
|
+
Protocol,
|
|
25
|
+
ProtocolConfig,
|
|
26
|
+
ProtocolFactory,
|
|
27
|
+
} from './types';
|
|
28
|
+
|
|
29
|
+
// 各 Protocol 实现
|
|
30
|
+
export { ArkProtocol, createArkProtocol } from './ark';
|
|
31
|
+
export { DeepSeekProtocol, createDeepSeekProtocol } from './deepseek';
|
|
32
|
+
export { QwenProtocol, createQwenProtocol } from './qwen';
|
|
33
|
+
export { GeminiProtocol, createGeminiProtocol } from './gemini';
|
|
34
|
+
export { OpenAIProtocol, createOpenAIProtocol } from './openai';
|
|
35
|
+
export { AnthropicProtocol, createAnthropicProtocol } from './anthropic';
|
|
36
|
+
|