@huyooo/ai-chat-core 0.3.6 → 0.3.8

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.
Files changed (220) hide show
  1. package/dist/adapter/index.d.ts +0 -1
  2. package/dist/adapter/model-adapter.d.ts +0 -1
  3. package/dist/adapter/model-options.d.ts +0 -1
  4. package/dist/adapter/types.d.ts +0 -1
  5. package/dist/chat-runtime.d.ts +0 -1
  6. package/dist/constants.d.ts +0 -1
  7. package/dist/events.d.ts +0 -1
  8. package/dist/extension/index.d.ts +0 -1
  9. package/dist/extension/types.d.ts +0 -1
  10. package/dist/families/index.d.ts +0 -1
  11. package/dist/families/presets.d.ts +0 -1
  12. package/dist/families/resolver.d.ts +0 -1
  13. package/dist/families/types.d.ts +0 -1
  14. package/dist/governance/command-safety.d.ts +0 -1
  15. package/dist/governance/governance.d.ts +0 -1
  16. package/dist/governance/index.d.ts +0 -1
  17. package/dist/governance/types.d.ts +0 -1
  18. package/dist/index.d.ts +0 -1
  19. package/dist/internal/management-args.d.ts +0 -1
  20. package/dist/internal/management-results.d.ts +0 -1
  21. package/dist/llm-config.d.ts +0 -1
  22. package/dist/logger/core.d.ts +0 -1
  23. package/dist/logger/index.d.ts +0 -1
  24. package/dist/orchestrator/compression-handler.d.ts +0 -1
  25. package/dist/orchestrator/context-compressor.d.ts +0 -1
  26. package/dist/orchestrator/context-summarizer.d.ts +0 -1
  27. package/dist/orchestrator/index.d.ts +0 -1
  28. package/dist/orchestrator/orchestrator.d.ts +0 -1
  29. package/dist/orchestrator/types.d.ts +0 -1
  30. package/dist/parts/index.d.ts +0 -1
  31. package/dist/parts/registry.d.ts +0 -1
  32. package/dist/parts/summaries.d.ts +0 -1
  33. package/dist/parts/types.d.ts +0 -1
  34. package/dist/platform.d.ts +0 -1
  35. package/dist/protocols/anthropic.d.ts +0 -1
  36. package/dist/protocols/ark.d.ts +0 -1
  37. package/dist/protocols/deepseek.d.ts +0 -1
  38. package/dist/protocols/error-utils.d.ts +0 -1
  39. package/dist/protocols/gemini.d.ts +0 -1
  40. package/dist/protocols/glm.d.ts +0 -1
  41. package/dist/protocols/grok.d.ts +0 -1
  42. package/dist/protocols/index.d.ts +0 -1
  43. package/dist/protocols/minimax.d.ts +0 -1
  44. package/dist/protocols/moonshot.d.ts +0 -1
  45. package/dist/protocols/openai-sse.d.ts +0 -1
  46. package/dist/protocols/openai.d.ts +0 -1
  47. package/dist/protocols/qwen.d.ts +0 -1
  48. package/dist/protocols/responses-sse.d.ts +0 -1
  49. package/dist/protocols/sse-reader.d.ts +0 -1
  50. package/dist/protocols/tool-arguments.d.ts +0 -1
  51. package/dist/protocols/types.d.ts +0 -1
  52. package/dist/protocols/vercel-gateway.d.ts +0 -1
  53. package/dist/runtime.d.ts +0 -1
  54. package/dist/skills/index.d.ts +0 -1
  55. package/dist/skills/management/admin.d.ts +0 -1
  56. package/dist/skills/management/index.d.ts +0 -1
  57. package/dist/skills/management/inputs.d.ts +0 -1
  58. package/dist/skills/management/operations.d.ts +0 -1
  59. package/dist/skills/management/types.d.ts +0 -1
  60. package/dist/skills/registry.d.ts +0 -1
  61. package/dist/skills/summaries.d.ts +0 -1
  62. package/dist/skills/types.d.ts +0 -1
  63. package/dist/test-utils/mock-sse.d.ts +0 -1
  64. package/dist/tool-manager/define-tool.d.ts +0 -1
  65. package/dist/tool-manager/formats.d.ts +0 -1
  66. package/dist/tool-manager/identity.d.ts +0 -1
  67. package/dist/tool-manager/in-process-provider.d.ts +0 -1
  68. package/dist/tool-manager/index.d.ts +0 -1
  69. package/dist/tool-manager/manager.d.ts +0 -1
  70. package/dist/tool-manager/mcp-provider.d.ts +0 -1
  71. package/dist/tool-manager/summaries.d.ts +0 -1
  72. package/dist/tool-manager/types.d.ts +0 -1
  73. package/dist/types.d.ts +0 -1
  74. package/package.json +2 -3
  75. package/dist/adapter/index.d.ts.map +0 -1
  76. package/dist/adapter/model-adapter.d.ts.map +0 -1
  77. package/dist/adapter/model-options.d.ts.map +0 -1
  78. package/dist/adapter/types.d.ts.map +0 -1
  79. package/dist/chat-runtime.d.ts.map +0 -1
  80. package/dist/constants.d.ts.map +0 -1
  81. package/dist/events.d.ts.map +0 -1
  82. package/dist/extension/index.d.ts.map +0 -1
  83. package/dist/extension/types.d.ts.map +0 -1
  84. package/dist/families/index.d.ts.map +0 -1
  85. package/dist/families/presets.d.ts.map +0 -1
  86. package/dist/families/resolver.d.ts.map +0 -1
  87. package/dist/families/types.d.ts.map +0 -1
  88. package/dist/governance/command-safety.d.ts.map +0 -1
  89. package/dist/governance/governance.d.ts.map +0 -1
  90. package/dist/governance/index.d.ts.map +0 -1
  91. package/dist/governance/types.d.ts.map +0 -1
  92. package/dist/index.d.ts.map +0 -1
  93. package/dist/internal/management-args.d.ts.map +0 -1
  94. package/dist/internal/management-results.d.ts.map +0 -1
  95. package/dist/llm-config.d.ts.map +0 -1
  96. package/dist/logger/core.d.ts.map +0 -1
  97. package/dist/logger/index.d.ts.map +0 -1
  98. package/dist/orchestrator/compression-handler.d.ts.map +0 -1
  99. package/dist/orchestrator/context-compressor.d.ts.map +0 -1
  100. package/dist/orchestrator/context-summarizer.d.ts.map +0 -1
  101. package/dist/orchestrator/index.d.ts.map +0 -1
  102. package/dist/orchestrator/orchestrator.d.ts.map +0 -1
  103. package/dist/orchestrator/types.d.ts.map +0 -1
  104. package/dist/parts/index.d.ts.map +0 -1
  105. package/dist/parts/registry.d.ts.map +0 -1
  106. package/dist/parts/summaries.d.ts.map +0 -1
  107. package/dist/parts/types.d.ts.map +0 -1
  108. package/dist/platform.d.ts.map +0 -1
  109. package/dist/protocols/anthropic.d.ts.map +0 -1
  110. package/dist/protocols/ark.d.ts.map +0 -1
  111. package/dist/protocols/deepseek.d.ts.map +0 -1
  112. package/dist/protocols/error-utils.d.ts.map +0 -1
  113. package/dist/protocols/gemini.d.ts.map +0 -1
  114. package/dist/protocols/glm.d.ts.map +0 -1
  115. package/dist/protocols/grok.d.ts.map +0 -1
  116. package/dist/protocols/index.d.ts.map +0 -1
  117. package/dist/protocols/minimax.d.ts.map +0 -1
  118. package/dist/protocols/moonshot.d.ts.map +0 -1
  119. package/dist/protocols/openai-sse.d.ts.map +0 -1
  120. package/dist/protocols/openai.d.ts.map +0 -1
  121. package/dist/protocols/qwen.d.ts.map +0 -1
  122. package/dist/protocols/responses-sse.d.ts.map +0 -1
  123. package/dist/protocols/sse-reader.d.ts.map +0 -1
  124. package/dist/protocols/tool-arguments.d.ts.map +0 -1
  125. package/dist/protocols/types.d.ts.map +0 -1
  126. package/dist/protocols/vercel-gateway.d.ts.map +0 -1
  127. package/dist/runtime.d.ts.map +0 -1
  128. package/dist/skills/index.d.ts.map +0 -1
  129. package/dist/skills/management/admin.d.ts.map +0 -1
  130. package/dist/skills/management/index.d.ts.map +0 -1
  131. package/dist/skills/management/inputs.d.ts.map +0 -1
  132. package/dist/skills/management/operations.d.ts.map +0 -1
  133. package/dist/skills/management/types.d.ts.map +0 -1
  134. package/dist/skills/registry.d.ts.map +0 -1
  135. package/dist/skills/summaries.d.ts.map +0 -1
  136. package/dist/skills/types.d.ts.map +0 -1
  137. package/dist/test-utils/mock-sse.d.ts.map +0 -1
  138. package/dist/tool-manager/define-tool.d.ts.map +0 -1
  139. package/dist/tool-manager/formats.d.ts.map +0 -1
  140. package/dist/tool-manager/identity.d.ts.map +0 -1
  141. package/dist/tool-manager/in-process-provider.d.ts.map +0 -1
  142. package/dist/tool-manager/index.d.ts.map +0 -1
  143. package/dist/tool-manager/manager.d.ts.map +0 -1
  144. package/dist/tool-manager/mcp-provider.d.ts.map +0 -1
  145. package/dist/tool-manager/summaries.d.ts.map +0 -1
  146. package/dist/tool-manager/types.d.ts.map +0 -1
  147. package/dist/types.d.ts.map +0 -1
  148. package/src/adapter/index.ts +0 -25
  149. package/src/adapter/model-adapter.ts +0 -196
  150. package/src/adapter/model-options.ts +0 -143
  151. package/src/adapter/types.ts +0 -41
  152. package/src/chat-runtime.ts +0 -515
  153. package/src/constants.ts +0 -32
  154. package/src/events.ts +0 -1084
  155. package/src/extension/index.ts +0 -24
  156. package/src/extension/types.ts +0 -49
  157. package/src/families/index.ts +0 -28
  158. package/src/families/presets.ts +0 -124
  159. package/src/families/resolver.ts +0 -22
  160. package/src/families/types.ts +0 -55
  161. package/src/governance/command-safety.ts +0 -224
  162. package/src/governance/governance.ts +0 -125
  163. package/src/governance/index.ts +0 -38
  164. package/src/governance/types.ts +0 -44
  165. package/src/index.ts +0 -426
  166. package/src/internal/management-args.ts +0 -39
  167. package/src/internal/management-results.ts +0 -60
  168. package/src/llm-config.ts +0 -137
  169. package/src/logger/core.ts +0 -96
  170. package/src/logger/index.ts +0 -8
  171. package/src/orchestrator/compression-handler.ts +0 -137
  172. package/src/orchestrator/context-compressor.ts +0 -249
  173. package/src/orchestrator/context-summarizer.ts +0 -123
  174. package/src/orchestrator/index.ts +0 -20
  175. package/src/orchestrator/orchestrator.ts +0 -1002
  176. package/src/orchestrator/types.ts +0 -70
  177. package/src/parts/index.ts +0 -20
  178. package/src/parts/registry.ts +0 -95
  179. package/src/parts/summaries.ts +0 -40
  180. package/src/parts/types.ts +0 -63
  181. package/src/platform.ts +0 -73
  182. package/src/protocols/anthropic.ts +0 -377
  183. package/src/protocols/ark.ts +0 -300
  184. package/src/protocols/deepseek.ts +0 -192
  185. package/src/protocols/error-utils.ts +0 -71
  186. package/src/protocols/gemini.ts +0 -352
  187. package/src/protocols/glm.ts +0 -212
  188. package/src/protocols/grok.ts +0 -98
  189. package/src/protocols/index.ts +0 -48
  190. package/src/protocols/minimax.ts +0 -308
  191. package/src/protocols/moonshot.ts +0 -186
  192. package/src/protocols/openai-sse.ts +0 -156
  193. package/src/protocols/openai.ts +0 -97
  194. package/src/protocols/qwen.ts +0 -358
  195. package/src/protocols/responses-sse.ts +0 -224
  196. package/src/protocols/sse-reader.ts +0 -54
  197. package/src/protocols/tool-arguments.ts +0 -32
  198. package/src/protocols/types.ts +0 -198
  199. package/src/protocols/vercel-gateway.ts +0 -391
  200. package/src/runtime.ts +0 -167
  201. package/src/skills/index.ts +0 -29
  202. package/src/skills/management/admin.ts +0 -170
  203. package/src/skills/management/index.ts +0 -27
  204. package/src/skills/management/inputs.ts +0 -79
  205. package/src/skills/management/operations.ts +0 -256
  206. package/src/skills/management/types.ts +0 -57
  207. package/src/skills/registry.ts +0 -120
  208. package/src/skills/summaries.ts +0 -48
  209. package/src/skills/types.ts +0 -65
  210. package/src/test-utils/mock-sse.ts +0 -32
  211. package/src/tool-manager/define-tool.ts +0 -201
  212. package/src/tool-manager/formats.ts +0 -146
  213. package/src/tool-manager/identity.ts +0 -80
  214. package/src/tool-manager/in-process-provider.ts +0 -164
  215. package/src/tool-manager/index.ts +0 -63
  216. package/src/tool-manager/manager.ts +0 -562
  217. package/src/tool-manager/mcp-provider.ts +0 -509
  218. package/src/tool-manager/summaries.ts +0 -136
  219. package/src/tool-manager/types.ts +0 -389
  220. package/src/types.ts +0 -1142
@@ -1,198 +0,0 @@
1
- /**
2
- * Protocol Layer 类型定义
3
- *
4
- * Protocol 只负责:
5
- * 1. HTTP 请求发送
6
- * 2. SSE 流解析
7
- * 3. 认证处理
8
- *
9
- * 不负责:
10
- * - thinking 格式转换(由 Family 处理)
11
- * - 搜索行为差异(由 Family 处理)
12
- * - 工具调用格式差异(由 Family 处理)
13
- */
14
-
15
- import type { ModelFamilyConfig } from '../families';
16
-
17
- // ==================== 协议标识 ====================
18
-
19
- /**
20
- * 内置协议类型标识
21
- *
22
- * 默认带版本 _v1,当上游 API 有 breaking change 时新增 _v2、_v3 等。
23
- */
24
- export type ProtocolId =
25
- | 'ark_v1' | 'deepseek_v1' | 'qwen_v1' | 'glm_v1' | 'moonshot_v1' | 'minimax_v1'
26
- | 'vercel_gateway_v1' | 'anthropic_v1' | 'gemini_v1' | 'openai_v1' | 'grok_v1'
27
- ;
28
-
29
- /** 从 ProtocolId 提取 base 协议(如 anthropic_v1 → anthropic) */
30
- export function getBaseProtocol(protocol: string): string {
31
- return protocol.replace(/_v\d+$/, '');
32
- }
33
-
34
- // ==================== 原始事件类型 ====================
35
-
36
- /**
37
- * Protocol 原始事件类型
38
- *
39
- * Protocol 层产出的事件,Orchestrator 直接消费
40
- */
41
- export type RawEventType =
42
- | 'text_delta' // 文本增量
43
- | 'thinking_delta' // 思考内容增量
44
- | 'thinking_done' // 思考完成
45
- | 'tool_call_start' // 工具调用开始
46
- | 'tool_call_delta' // 工具调用参数增量
47
- | 'tool_call_done' // 工具调用完成
48
- | 'done' // 流结束
49
- | 'error'; // 错误
50
-
51
- /** 工具调用 */
52
- export interface RawToolCall {
53
- id: string;
54
- name: string;
55
- arguments: string;
56
- /** Gemini 需要的 thoughtSignature(用于工具调用循环) */
57
- thoughtSignature?: string;
58
- }
59
-
60
- /**
61
- * Protocol 原始事件
62
- */
63
- /** Token 使用统计(Protocol 层) */
64
- export interface RawTokenUsage {
65
- promptTokens?: number;
66
- completionTokens?: number;
67
- totalTokens?: number;
68
- reasoningTokens?: number;
69
- cachedTokens?: number;
70
- }
71
-
72
- /** 输出内容片段(用于图片生成、多模态结果等非纯文本产物) */
73
- export type RawOutputPart =
74
- | { type: 'text'; text: string }
75
- | { type: 'inline_data'; mimeType: string; data: string };
76
-
77
- export interface RawEvent {
78
- type: RawEventType;
79
-
80
- // text_delta / thinking_delta
81
- delta?: string;
82
-
83
- // thinking_done(Anthropic 的 thinking signature)
84
- thinkingSignature?: string;
85
-
86
- // tool_call_*
87
- toolCall?: Partial<RawToolCall>;
88
-
89
- // done
90
- finishReason?: 'stop' | 'tool_calls' | 'length' | 'error';
91
- /** Token 使用统计(done 事件携带) */
92
- usage?: RawTokenUsage;
93
- /** 完整输出片段(done 事件携带;用于图片生成等场景) */
94
- outputParts?: RawOutputPart[];
95
-
96
- // error
97
- error?: string;
98
- }
99
-
100
- // ==================== Protocol 请求类型 ====================
101
-
102
- /**
103
- * Protocol 请求消息(标准化格式)
104
- */
105
- export interface ProtocolMessage {
106
- role: 'system' | 'user' | 'assistant' | 'tool';
107
- content: string;
108
-
109
- /** 图片列表(base64 或 URL) */
110
- images?: string[];
111
-
112
- /** 多模态文件附件。Gemini 使用 fileData 引用 Files API URI。 */
113
- attachments?: ProtocolAttachment[];
114
-
115
- /** 思考内容(assistant 消息,工具调用循环需回传给 API) */
116
- thinkingContent?: string;
117
-
118
- /** 思考签名(Anthropic extended thinking 的 signature,工具调用循环需回传) */
119
- thinkingSignature?: string;
120
-
121
- /** 工具调用(assistant 消息) */
122
- toolCalls?: RawToolCall[];
123
-
124
- /** 工具调用 ID(tool 消息) */
125
- toolCallId?: string;
126
-
127
- /** 工具名称(tool 消息,Gemini 需要) */
128
- toolName?: string;
129
- }
130
-
131
- export type ProtocolAttachment =
132
- | { type: 'file_data'; mimeType: string; fileUri: string };
133
-
134
- /**
135
- * Protocol 工具定义(简化格式)
136
- */
137
- import type { JsonSchemaObject } from '../types';
138
-
139
- export interface ProtocolToolDefinition {
140
- name: string;
141
- description: string;
142
- parameters: JsonSchemaObject;
143
- }
144
-
145
- /**
146
- * Protocol 请求选项
147
- */
148
- export interface ProtocolRequestOptions {
149
- /** 模型 ID */
150
- model: string;
151
- /** 模型家族配置 */
152
- familyConfig: ModelFamilyConfig;
153
- /** 最大输出 token(从 ModelConfig.maxOutputTokens 直传) */
154
- maxOutputTokens: number;
155
- /** 是否启用 thinking */
156
- enableThinking: boolean;
157
- /** 中断信号 */
158
- signal: AbortSignal;
159
- }
160
-
161
- // ==================== Protocol 接口 ====================
162
-
163
- /**
164
- * Protocol 配置
165
- */
166
- export interface ProtocolConfig {
167
- apiKey: string;
168
- apiUrl?: string;
169
- }
170
-
171
- /**
172
- * Protocol 接口
173
- *
174
- * 只负责 HTTP/SSE 通信,不处理任何业务逻辑
175
- */
176
- export interface Protocol {
177
- /** 协议名称 */
178
- readonly name: string;
179
-
180
- /**
181
- * 发送请求并返回原始事件流
182
- *
183
- * @param messages 消息列表
184
- * @param tools 工具定义
185
- * @param options 请求选项
186
- * @returns 原始事件流
187
- */
188
- stream(
189
- messages: ProtocolMessage[],
190
- tools: ProtocolToolDefinition[],
191
- options: ProtocolRequestOptions
192
- ): AsyncGenerator<RawEvent>;
193
- }
194
-
195
- /**
196
- * Protocol 工厂函数类型
197
- */
198
- export type ProtocolFactory = (config: ProtocolConfig) => Protocol;
@@ -1,391 +0,0 @@
1
- /**
2
- * Vercel AI Gateway Protocol(LanguageModelV3)
3
- *
4
- * 调用 Vercel AI Gateway 内部协议端点 /v3/ai/language-model,
5
- * 使用 LanguageModelV3 格式,完整保留各厂商原生能力:
6
- * - Gemini: thinking + thoughtSignature(tool call 循环必需)
7
- * - GPT: reasoning summary
8
- * - Claude: reasoning
9
- *
10
- * 所有厂商返回统一的事件格式(reasoning-delta / text-delta / tool-call 等),
11
- * 厂商特有字段通过 providerMetadata 透传。
12
- */
13
-
14
- import type {
15
- Protocol,
16
- ProtocolConfig,
17
- ProtocolMessage,
18
- ProtocolToolDefinition,
19
- ProtocolRequestOptions,
20
- RawEvent,
21
- RawTokenUsage,
22
- } from './types';
23
- import { createModuleLogger } from '../logger';
24
- import { friendlyHttpError } from './error-utils';
25
- import { readSSEJsonStream } from './sse-reader';
26
- import { parseProtocolToolArguments } from './tool-arguments';
27
-
28
- const logger = createModuleLogger('VercelGateway');
29
-
30
- const GATEWAY_BASE = 'https://ai-gateway.vercel.sh/v3/ai';
31
-
32
- // ==================== 消息转换(LanguageModelV3 Prompt) ====================
33
-
34
- /**
35
- * LanguageModelV3 Prompt 格式:
36
- * - system: { role: 'system', content: string }
37
- * - user: { role: 'user', content: [{ type: 'text', text } | { type: 'file', data, mediaType }] }
38
- * - assistant: { role: 'assistant', content: [text | reasoning | tool-call] }
39
- * - tool: { role: 'tool', content: [{ type: 'tool-result', ... }] }
40
- */
41
- function convertToPrompt(messages: ProtocolMessage[]): unknown[] {
42
- const prompt: unknown[] = [];
43
-
44
- for (const msg of messages) {
45
- switch (msg.role) {
46
- case 'system':
47
- prompt.push({ role: 'system', content: msg.content });
48
- break;
49
-
50
- case 'user': {
51
- const textContent = msg.content || (msg.images?.length ? '请分析这张图片' : '');
52
- const parts: unknown[] = [{ type: 'text', text: textContent }];
53
- if (msg.images?.length) {
54
- for (const img of msg.images) {
55
- const dataUrl = img.startsWith('data:') ? img : `data:image/jpeg;base64,${img}`;
56
- parts.push({ type: 'file', data: dataUrl, mediaType: 'image/jpeg' });
57
- }
58
- }
59
- prompt.push({ role: 'user', content: parts });
60
- break;
61
- }
62
-
63
- case 'assistant': {
64
- const parts: unknown[] = [];
65
- if (msg.thinkingContent) {
66
- // 回传思考内容,Gemini 的 thoughtSignature 在 providerOptions 中
67
- const reasoningPart: Record<string, unknown> = { type: 'reasoning', text: msg.thinkingContent };
68
- if (msg.toolCalls?.[0]?.thoughtSignature) {
69
- reasoningPart.providerOptions = {
70
- google: { thoughtSignature: msg.toolCalls[0].thoughtSignature },
71
- vertex: { thoughtSignature: msg.toolCalls[0].thoughtSignature },
72
- };
73
- }
74
- parts.push(reasoningPart);
75
- }
76
- if (msg.toolCalls?.length) {
77
- if (msg.content) {
78
- parts.push({ type: 'text', text: msg.content });
79
- }
80
- for (const tc of msg.toolCalls) {
81
- // V3 协议要求 input 是对象(Gemini 需要 google.protobuf.Struct)
82
- const toolPart: Record<string, unknown> = {
83
- type: 'tool-call',
84
- toolCallId: tc.id,
85
- toolName: tc.name,
86
- input: parseProtocolToolArguments(tc.arguments, {
87
- protocol: 'vercel-gateway',
88
- toolCallId: tc.id,
89
- toolName: tc.name,
90
- }),
91
- };
92
- if (tc.thoughtSignature) {
93
- toolPart.providerOptions = {
94
- google: { thoughtSignature: tc.thoughtSignature },
95
- vertex: { thoughtSignature: tc.thoughtSignature },
96
- };
97
- }
98
- parts.push(toolPart);
99
- }
100
- } else {
101
- parts.push({ type: 'text', text: msg.content || '' });
102
- }
103
- prompt.push({ role: 'assistant', content: parts });
104
- break;
105
- }
106
-
107
- case 'tool':
108
- prompt.push({
109
- role: 'tool',
110
- content: [{
111
- type: 'tool-result',
112
- toolCallId: msg.toolCallId || '',
113
- toolName: msg.toolName || 'unknown',
114
- output: formatToolOutput(msg.content),
115
- }],
116
- });
117
- break;
118
- }
119
- }
120
-
121
- return prompt;
122
- }
123
-
124
- function formatToolOutput(content: string): { type: 'json'; value: unknown } | { type: 'text'; value: string } {
125
- try {
126
- return { type: 'json', value: JSON.parse(content) };
127
- } catch {
128
- return { type: 'text', value: content };
129
- }
130
- }
131
-
132
- // ==================== 工具转换 ====================
133
-
134
- function convertTools(tools: ProtocolToolDefinition[]): unknown[] | undefined {
135
- if (tools.length === 0) return undefined;
136
- // V3 协议用 inputSchema(非 parameters),Claude/Bedrock 严格要求此字段
137
- return tools.map(t => ({
138
- type: 'function',
139
- name: t.name,
140
- description: t.description,
141
- inputSchema: t.parameters,
142
- }));
143
- }
144
-
145
- // ==================== Provider Options(thinking 配置) ====================
146
-
147
- /**
148
- * 根据 model ID 前缀构建厂商特有的 thinking 配置:
149
- * - google/*: providerOptions.google.thinkingConfig
150
- * - openai/*: providerOptions.openai.reasoningEffort + reasoningSummary
151
- * - anthropic/*: providerOptions.anthropic.thinking
152
- */
153
- function buildProviderOptions(modelId: string, enableThinking: boolean): Record<string, unknown> | undefined {
154
- if (modelId.startsWith('google/')) {
155
- if (!enableThinking) return undefined;
156
- return {
157
- google: { thinkingConfig: { thinkingLevel: 'high', includeThoughts: true } },
158
- };
159
- }
160
- if (modelId.startsWith('openai/')) {
161
- return {
162
- openai: {
163
- reasoningEffort: enableThinking ? 'high' : 'low',
164
- reasoningSummary: enableThinking ? 'detailed' : 'auto',
165
- },
166
- };
167
- }
168
- if (modelId.startsWith('anthropic/')) {
169
- if (!enableThinking) return undefined;
170
- return {
171
- anthropic: { thinking: { type: 'enabled', budgetTokens: 10000 } },
172
- };
173
- }
174
- return undefined;
175
- }
176
-
177
- // ==================== 请求体构建 ====================
178
-
179
- function buildRequestBody(
180
- messages: ProtocolMessage[],
181
- tools: ProtocolToolDefinition[],
182
- options: ProtocolRequestOptions,
183
- ): Record<string, unknown> {
184
- const body: Record<string, unknown> = {
185
- prompt: convertToPrompt(messages),
186
- };
187
-
188
- body.maxOutputTokens = options.maxOutputTokens;
189
-
190
- const providerOptions = buildProviderOptions(options.model, options.enableThinking);
191
- if (providerOptions) {
192
- body.providerOptions = providerOptions;
193
- }
194
-
195
- const convertedTools = convertTools(tools);
196
- if (convertedTools) {
197
- body.tools = convertedTools;
198
- }
199
-
200
- return body;
201
- }
202
-
203
- // ==================== V3 SSE 流解析 ====================
204
-
205
- /**
206
- * LanguageModelV3 流事件类型:
207
- *
208
- * 思考: reasoning-start → reasoning-delta { delta } → reasoning-end
209
- * 文本: text-start → text-delta { delta } → text-end
210
- * 工具调用: tool-input-start { toolName } → tool-input-delta { delta } → tool-input-end → tool-call { toolCallId, toolName, input }
211
- * 完成: finish { finishReason, usage }
212
- * 错误: error { error }
213
- *
214
- * 所有事件都可能携带 providerMetadata(如 Gemini 的 thoughtSignature)
215
- */
216
- /**
217
- * 解析 LanguageModelV3 SSE 流
218
- *
219
- * Layer 1 负责 bytes → JSON,此处做 V3 格式的语义映射。
220
- */
221
- async function* parseV3Stream(
222
- reader: ReadableStreamDefaultReader<Uint8Array>,
223
- ): AsyncGenerator<RawEvent> {
224
- let hasToolCalls = false;
225
- const pendingCalls = new Map<string, { name: string; args: string; thoughtSignature?: string }>();
226
-
227
- for await (const event of readSSEJsonStream(reader)) {
228
- const type = event.type as string;
229
-
230
- switch (type) {
231
- case 'reasoning-delta': {
232
- const delta = event.delta as string;
233
- if (delta) {
234
- yield { type: 'thinking_delta', delta };
235
- }
236
- break;
237
- }
238
- case 'reasoning-end': {
239
- yield { type: 'thinking_done' };
240
- break;
241
- }
242
-
243
- case 'text-delta': {
244
- const delta = event.delta as string;
245
- if (delta) {
246
- yield { type: 'text_delta', delta };
247
- }
248
- break;
249
- }
250
-
251
- case 'tool-input-start': {
252
- hasToolCalls = true;
253
- const id = event.id as string;
254
- const name = event.toolName as string;
255
- const sig = extractThoughtSignature(event);
256
- pendingCalls.set(id, { name, args: '', thoughtSignature: sig });
257
- yield { type: 'tool_call_start', toolCall: { id, name } };
258
- break;
259
- }
260
-
261
- case 'tool-input-delta': {
262
- const id = event.id as string;
263
- const delta = event.delta as string;
264
- if (id && delta) {
265
- const pending = pendingCalls.get(id);
266
- if (pending) pending.args += delta;
267
- yield { type: 'tool_call_delta', toolCall: { id, arguments: delta } };
268
- }
269
- break;
270
- }
271
-
272
- case 'tool-call': {
273
- const id = event.toolCallId as string;
274
- const name = event.toolName as string;
275
- const input = (event.input ?? '{}') as string;
276
- const pending = pendingCalls.get(id);
277
- const sig = extractThoughtSignature(event) || pending?.thoughtSignature;
278
- yield {
279
- type: 'tool_call_done',
280
- toolCall: {
281
- id,
282
- name: name || pending?.name || '',
283
- arguments: input || pending?.args || '{}',
284
- ...(sig ? { thoughtSignature: sig } : {}),
285
- },
286
- };
287
- pendingCalls.delete(id);
288
- break;
289
- }
290
-
291
- case 'finish': {
292
- const rawUsage = event.usage as Record<string, unknown> | undefined;
293
- let usage: RawTokenUsage | undefined;
294
- if (rawUsage) {
295
- const input = rawUsage.inputTokens as Record<string, number> | undefined;
296
- const output = rawUsage.outputTokens as Record<string, number> | undefined;
297
- usage = {
298
- promptTokens: input?.total ?? 0,
299
- completionTokens: output?.total ?? 0,
300
- totalTokens: (input?.total ?? 0) + (output?.total ?? 0),
301
- reasoningTokens: output?.reasoning ?? 0,
302
- cachedTokens: input?.cacheRead ?? 0,
303
- };
304
- }
305
- const reason = event.finishReason as Record<string, string> | undefined;
306
- const unified = reason?.unified ?? 'stop';
307
- const finishReason = hasToolCalls || unified === 'tool-calls' ? 'tool_calls' as const
308
- : unified === 'length' ? 'length' as const
309
- : unified === 'error' ? 'error' as const
310
- : 'stop' as const;
311
- yield { type: 'done', finishReason, usage };
312
- return;
313
- }
314
-
315
- case 'error': {
316
- const err = event.error;
317
- const msg = typeof err === 'string' ? err : JSON.stringify(err);
318
- yield { type: 'error', error: msg };
319
- break;
320
- }
321
- }
322
- }
323
-
324
- yield { type: 'done', finishReason: hasToolCalls ? 'tool_calls' : 'stop' };
325
- }
326
-
327
- /** 从 providerMetadata 中提取 Gemini 的 thoughtSignature */
328
- function extractThoughtSignature(event: Record<string, unknown>): string | undefined {
329
- const meta = event.providerMetadata as Record<string, Record<string, unknown>> | undefined;
330
- const sig = meta?.vertex?.thoughtSignature ?? meta?.google?.thoughtSignature;
331
- return typeof sig === 'string' ? sig : undefined;
332
- }
333
-
334
- // ==================== Protocol 实现 ====================
335
-
336
- class VercelGatewayProtocol implements Protocol {
337
- readonly name = 'vercel_gateway';
338
- private apiKey: string;
339
-
340
- constructor(config: ProtocolConfig) {
341
- this.apiKey = config.apiKey;
342
- }
343
-
344
- async *stream(
345
- messages: ProtocolMessage[],
346
- tools: ProtocolToolDefinition[],
347
- options: ProtocolRequestOptions,
348
- ): AsyncGenerator<RawEvent> {
349
- const body = buildRequestBody(messages, tools, options);
350
-
351
- logger.debug({
352
- model: options.model,
353
- enableThinking: options.enableThinking,
354
- toolsCount: tools.length,
355
- }, 'Vercel Gateway V3 请求');
356
-
357
- const response = await fetch(`${GATEWAY_BASE}/language-model`, {
358
- method: 'POST',
359
- headers: {
360
- 'Content-Type': 'application/json',
361
- 'Authorization': `Bearer ${this.apiKey}`,
362
- 'ai-gateway-protocol-version': '0.0.1',
363
- 'ai-gateway-auth-method': 'api-key',
364
- 'ai-language-model-specification-version': '3',
365
- 'ai-language-model-id': options.model,
366
- 'ai-language-model-streaming': 'true',
367
- },
368
- body: JSON.stringify(body),
369
- signal: options.signal,
370
- });
371
-
372
- if (!response.ok) {
373
- const errorText = await response.text();
374
- logger.error({ status: response.status, body: errorText.slice(0, 500) }, 'Vercel Gateway 错误');
375
- yield { type: 'error', error: friendlyHttpError(response.status, errorText, 'Vercel Gateway') };
376
- return;
377
- }
378
-
379
- const reader = response.body?.getReader();
380
- if (!reader) {
381
- yield { type: 'error', error: '无法获取响应流' };
382
- return;
383
- }
384
-
385
- yield* parseV3Stream(reader);
386
- }
387
- }
388
-
389
- export function createVercelGatewayProtocol(config: ProtocolConfig): Protocol {
390
- return new VercelGatewayProtocol(config);
391
- }