aicodeswitch 3.9.4 → 4.0.0

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.
@@ -0,0 +1,1765 @@
1
+ "use strict";
2
+ /**
3
+ * 请求转换器统一导出文件
4
+ * 提供语义化的函数名,明确表示转换的方向
5
+ */
6
+ var __rest = (this && this.__rest) || function (s, e) {
7
+ var t = {};
8
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
9
+ t[p] = s[p];
10
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
11
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
12
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
13
+ t[p[i]] = s[p[i]];
14
+ }
15
+ return t;
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.extractTokenUsageFromClaudeUsage = exports.extractTokenUsageFromOpenAIUsage = exports.extractTokenUsageFromGeminiUsage = exports.sanitizeSchemaForGeminiFunctionDeclaration = exports.applyPayloadOverride = exports.applyToolsOverride = exports.applyModelOverride = exports.isRequestOpenAIModels = exports.shouldUseDeveloperRoleAsSystemRole = exports.isResponsesRequest = void 0;
19
+ exports.transformRequestFromResponsesToGemini = transformRequestFromResponsesToGemini;
20
+ exports.transformRequestFromResponsesToClaude = transformRequestFromResponsesToClaude;
21
+ exports.transformRequestFromResponsesToChatCompletions = transformRequestFromResponsesToChatCompletions;
22
+ exports.transformRequestFromClaudeToGemini = transformRequestFromClaudeToGemini;
23
+ exports.transformRequestFromClaudeToResponses = transformRequestFromClaudeToResponses;
24
+ exports.transformRequestFromClaudeToChatCompletions = transformRequestFromClaudeToChatCompletions;
25
+ exports.transformResponseFromChatCompletionsToResponses = transformResponseFromChatCompletionsToResponses;
26
+ exports.transformResponseFromClaudeToResponses = transformResponseFromClaudeToResponses;
27
+ exports.transformResponseFromGeminiToResponses = transformResponseFromGeminiToResponses;
28
+ exports.transformResponseFromChatCompletionsToClaude = transformResponseFromChatCompletionsToClaude;
29
+ exports.transformResponseFromResponsesToClaude = transformResponseFromResponsesToClaude;
30
+ exports.transformResponseFromGeminiToClaude = transformResponseFromGeminiToClaude;
31
+ /**
32
+ * 判断请求是否为 Responses API 的请求格式
33
+ */
34
+ const isResponsesRequest = (data) => {
35
+ // Responses API 格式的特征:有 input 字段,没有 messages 字段
36
+ return data && typeof data === 'object' &&
37
+ 'input' in data &&
38
+ !('messages' in data);
39
+ };
40
+ exports.isResponsesRequest = isResponsesRequest;
41
+ /**
42
+ * 判断是否使用developer作为系统提示词角色,而不使用system作为角色
43
+ * @param model
44
+ * @returns
45
+ */
46
+ const shouldUseDeveloperRoleAsSystemRole = (model) => {
47
+ const modelsToUseSystemPrefix = `gpt-2,gpt-3,gpt-4`.split(',');
48
+ if (modelsToUseSystemPrefix.some(item => model.toLowerCase().startsWith(item))) {
49
+ return false;
50
+ }
51
+ // gpt-的更高版本模型都是developer
52
+ const modelsToUseDeveloper = `o1,o2,o3,gpt-`.split(',');
53
+ if (modelsToUseDeveloper.some(item => model.toLowerCase().startsWith(item))) {
54
+ return true;
55
+ }
56
+ // 其他非openai的模型都是system
57
+ return false;
58
+ };
59
+ exports.shouldUseDeveloperRoleAsSystemRole = shouldUseDeveloperRoleAsSystemRole;
60
+ const isRequestOpenAIModels = (model) => {
61
+ if (!model || typeof model !== 'string') {
62
+ return false;
63
+ }
64
+ const gptModelNames = 'gpt-,o1,o2,o3'.split(',');
65
+ return gptModelNames.some(item => model.toLowerCase().startsWith(item));
66
+ };
67
+ exports.isRequestOpenAIModels = isRequestOpenAIModels;
68
+ /**
69
+ * 对模型属性进行覆盖
70
+ * @param data
71
+ * @param realModelName 真正提交到API接口的模型名称
72
+ * @returns
73
+ */
74
+ const applyModelOverride = (data, realModelName) => {
75
+ if (!data || typeof data !== 'object') {
76
+ return data;
77
+ }
78
+ if (!realModelName) {
79
+ return data;
80
+ }
81
+ return Object.assign(Object.assign({}, data), { model: realModelName });
82
+ };
83
+ exports.applyModelOverride = applyModelOverride;
84
+ /**
85
+ * 对工具属性进行覆盖
86
+ * @param tools
87
+ * @param realModelName 提交到API的真实模型名称
88
+ */
89
+ const applyToolsOverride = (tools, realModelName) => {
90
+ if (!tools) {
91
+ return;
92
+ }
93
+ if ((0, exports.isRequestOpenAIModels)(realModelName)) {
94
+ return tools;
95
+ }
96
+ return tools.map((tool) => {
97
+ const { type, parameters, format, description } = tool, others = __rest(tool, ["type", "parameters", "format", "description"]);
98
+ if (type === 'custom') {
99
+ return Object.assign(Object.assign({}, others), { type: 'function', description: `${description}${format ? '\n\nFormat: ' + JSON.stringify(format) : ''}`, parameters: parameters || {} });
100
+ }
101
+ return tool;
102
+ }).filter(item => item.type === 'function');
103
+ };
104
+ exports.applyToolsOverride = applyToolsOverride;
105
+ /**
106
+ * 对 payload 进行简单处理
107
+ * @param data
108
+ * @param realModelName 提交到API的真实模型名称
109
+ * @returns
110
+ */
111
+ const applyPayloadOverride = (data, realModelName) => {
112
+ if ((0, exports.isRequestOpenAIModels)(realModelName)) {
113
+ return data;
114
+ }
115
+ const overrided = (0, exports.applyModelOverride)(data, realModelName);
116
+ return overrided;
117
+ // const tools = applyToolsOverride(data.tools, realModelName);
118
+ // if (overrided.text) {
119
+ // delete overrided.text.verbosity;
120
+ // }
121
+ // delete overrided.prompt_cache_key;
122
+ // delete overrided.include;
123
+ // return {
124
+ // ...overrided,
125
+ // tools,
126
+ // };
127
+ };
128
+ exports.applyPayloadOverride = applyPayloadOverride;
129
+ const GEMINI_ALLOWED_SCHEMA_KEYS = new Set([
130
+ 'type',
131
+ 'format',
132
+ 'description',
133
+ 'nullable',
134
+ 'enum',
135
+ 'properties',
136
+ 'required',
137
+ 'items',
138
+ 'minimum',
139
+ 'maximum',
140
+ 'minLength',
141
+ 'maxLength',
142
+ 'pattern',
143
+ 'minItems',
144
+ 'maxItems',
145
+ ]);
146
+ /**
147
+ * Gemini FunctionDeclaration.parameters 仅支持 OpenAPI 子集。
148
+ * 这里将通用 JSON Schema 清洗为 Gemini 可接受的结构,避免 400 Unknown name 错误。
149
+ */
150
+ const sanitizeSchemaForGeminiFunctionDeclaration = (schema) => {
151
+ const sanitize = (value) => {
152
+ if (!value || typeof value !== 'object') {
153
+ return undefined;
154
+ }
155
+ if (Array.isArray(value)) {
156
+ return value.map((item) => sanitize(item)).filter((item) => item !== undefined);
157
+ }
158
+ const result = {};
159
+ const sourceType = value.type;
160
+ // JSON Schema type 允许数组(如 ["object", "null"]),Gemini 仅接受字符串
161
+ if (Array.isArray(sourceType)) {
162
+ const nonNullType = sourceType.find((t) => typeof t === 'string' && t !== 'null');
163
+ if (typeof nonNullType === 'string') {
164
+ result.type = nonNullType;
165
+ }
166
+ if (sourceType.includes('null')) {
167
+ result.nullable = true;
168
+ }
169
+ }
170
+ else if (typeof sourceType === 'string') {
171
+ result.type = sourceType;
172
+ }
173
+ // const 在 Gemini schema 中不被接受,降级为单值 enum
174
+ if (value.const !== undefined) {
175
+ result.enum = [value.const];
176
+ }
177
+ for (const key of Object.keys(value)) {
178
+ if (!GEMINI_ALLOWED_SCHEMA_KEYS.has(key)) {
179
+ continue;
180
+ }
181
+ // type 已在上方做过标准化(string / nullable)
182
+ if (key === 'type') {
183
+ continue;
184
+ }
185
+ if (key === 'properties' && value.properties && typeof value.properties === 'object' && !Array.isArray(value.properties)) {
186
+ const cleanedProperties = {};
187
+ for (const [propKey, propValue] of Object.entries(value.properties)) {
188
+ const cleanedProperty = sanitize(propValue);
189
+ if (cleanedProperty !== undefined) {
190
+ cleanedProperties[propKey] = cleanedProperty;
191
+ }
192
+ }
193
+ result.properties = cleanedProperties;
194
+ continue;
195
+ }
196
+ if (key === 'items') {
197
+ const cleanedItems = sanitize(value.items);
198
+ if (cleanedItems !== undefined) {
199
+ result.items = cleanedItems;
200
+ }
201
+ continue;
202
+ }
203
+ result[key] = value[key];
204
+ }
205
+ if (!result.type) {
206
+ if (result.properties) {
207
+ result.type = 'object';
208
+ }
209
+ else if (result.items) {
210
+ result.type = 'array';
211
+ }
212
+ }
213
+ return Object.keys(result).length > 0 ? result : undefined;
214
+ };
215
+ return sanitize(schema) || { type: 'object', properties: {} };
216
+ };
217
+ exports.sanitizeSchemaForGeminiFunctionDeclaration = sanitizeSchemaForGeminiFunctionDeclaration;
218
+ const isValidThinkingBudget = (value) => typeof value === 'number' && Number.isFinite(value) && value > 0;
219
+ const createGeminiThinkingConfigFromClaudeThinking = (thinking) => {
220
+ if (!thinking || typeof thinking !== 'object') {
221
+ return undefined;
222
+ }
223
+ const hasBudget = isValidThinkingBudget(thinking.budget_tokens);
224
+ const thinkingConfig = {};
225
+ if (thinking.type === 'enabled') {
226
+ thinkingConfig.includeThoughts = true;
227
+ if (hasBudget) {
228
+ thinkingConfig.thinkingBudget = thinking.budget_tokens;
229
+ }
230
+ else {
231
+ thinkingConfig.thinkingLevel = 'HIGH';
232
+ }
233
+ }
234
+ else if (thinking.type === 'auto') {
235
+ thinkingConfig.includeThoughts = true;
236
+ if (hasBudget) {
237
+ thinkingConfig.thinkingBudget = thinking.budget_tokens;
238
+ }
239
+ else {
240
+ thinkingConfig.thinkingLevel = 'LOW';
241
+ }
242
+ }
243
+ else if (thinking.type === 'disabled') {
244
+ thinkingConfig.includeThoughts = false;
245
+ }
246
+ return Object.keys(thinkingConfig).length > 0 ? thinkingConfig : undefined;
247
+ };
248
+ const createGeminiThinkingConfigFromResponsesReasoning = (reasoning) => {
249
+ if (!reasoning || typeof reasoning !== 'object') {
250
+ return undefined;
251
+ }
252
+ const hasBudget = isValidThinkingBudget(reasoning.budget_tokens);
253
+ const thinkingConfig = {};
254
+ if (reasoning.type === 'enabled' || reasoning.type === 'auto') {
255
+ thinkingConfig.includeThoughts = true;
256
+ if (hasBudget) {
257
+ thinkingConfig.thinkingBudget = reasoning.budget_tokens;
258
+ }
259
+ else if (reasoning.effort === 'low') {
260
+ thinkingConfig.thinkingLevel = 'LOW';
261
+ }
262
+ else if (reasoning.effort === 'medium') {
263
+ thinkingConfig.thinkingLevel = 'MEDIUM';
264
+ }
265
+ else if (reasoning.effort === 'high') {
266
+ thinkingConfig.thinkingLevel = 'HIGH';
267
+ }
268
+ }
269
+ else if (reasoning.type === 'disabled') {
270
+ thinkingConfig.includeThoughts = false;
271
+ }
272
+ return Object.keys(thinkingConfig).length > 0 ? thinkingConfig : undefined;
273
+ };
274
+ /**
275
+ * 从 Gemini usage 中提取 TokenUsage
276
+ */
277
+ const extractTokenUsageFromGeminiUsage = (usage) => {
278
+ if (!usage) {
279
+ return undefined;
280
+ }
281
+ return {
282
+ inputTokens: usage.promptTokenCount,
283
+ outputTokens: usage.candidatesTokenCount,
284
+ totalTokens: usage.totalTokenCount,
285
+ cacheReadInputTokens: usage.cachedContentTokenCount,
286
+ };
287
+ };
288
+ exports.extractTokenUsageFromGeminiUsage = extractTokenUsageFromGeminiUsage;
289
+ const extractTokenUsageFromOpenAIUsage = (usage) => {
290
+ if (!usage) {
291
+ return undefined;
292
+ }
293
+ return {
294
+ inputTokens: usage.input_tokens,
295
+ outputTokens: usage.output_tokens || usage.completion_tokens,
296
+ totalTokens: usage.total_tokens,
297
+ cacheReadInputTokens: usage.cached_tokens,
298
+ };
299
+ };
300
+ exports.extractTokenUsageFromOpenAIUsage = extractTokenUsageFromOpenAIUsage;
301
+ const extractTokenUsageFromClaudeUsage = (usage) => {
302
+ var _a, _b;
303
+ if (!usage) {
304
+ return undefined;
305
+ }
306
+ return {
307
+ inputTokens: (_a = usage.input_tokens) !== null && _a !== void 0 ? _a : 0,
308
+ outputTokens: (_b = usage.output_tokens) !== null && _b !== void 0 ? _b : 0,
309
+ totalTokens: usage.input_tokens !== undefined && usage.output_tokens !== undefined
310
+ ? usage.input_tokens + usage.output_tokens
311
+ : undefined,
312
+ cacheReadInputTokens: usage.cache_read_input_tokens,
313
+ };
314
+ };
315
+ exports.extractTokenUsageFromClaudeUsage = extractTokenUsageFromClaudeUsage;
316
+ // ------------------------- codex 发起请求 -------------------------
317
+ /**
318
+ * 将 codex 发起的对 Responses API 的请求转换为对 Gemini API 的请求的数据格式
319
+ */
320
+ function transformRequestFromResponsesToGemini(body, _targetModel) {
321
+ var _a;
322
+ const { instructions, input, max_output_tokens, max_tokens, temperature, top_p, stop, tools, tool_choice, reasoning } = body;
323
+ const geminiRequest = {
324
+ contents: [],
325
+ };
326
+ // 处理 instructions 字段(系统提示词)
327
+ if (instructions && typeof instructions === 'string') {
328
+ geminiRequest.systemInstruction = {
329
+ role: 'user',
330
+ parts: [{ text: instructions }],
331
+ };
332
+ }
333
+ // 处理 input 字段(消息数组)
334
+ if (Array.isArray(input)) {
335
+ for (const msg of input) {
336
+ if (!msg || msg.type !== 'message') {
337
+ continue;
338
+ }
339
+ // Gemini API 不支持 developer 角色,映射为 user
340
+ const geminiRole = msg.role === 'assistant' ? 'model' : 'user';
341
+ const geminiContent = {
342
+ role: geminiRole,
343
+ parts: [],
344
+ };
345
+ // 处理 content 数组
346
+ if (Array.isArray(msg.content)) {
347
+ for (const contentItem of msg.content) {
348
+ if (!contentItem || typeof contentItem !== 'object') {
349
+ continue;
350
+ }
351
+ // 处理文本内容: input_text -> text
352
+ if (contentItem.type === 'input_text' && typeof contentItem.text === 'string') {
353
+ geminiContent.parts.push({ text: contentItem.text });
354
+ }
355
+ // 处理图像内容: input_image -> inlineData
356
+ if (contentItem.type === 'input_image' && contentItem.image_url) {
357
+ const imageUrl = contentItem.image_url.url;
358
+ if (typeof imageUrl === 'string') {
359
+ if (imageUrl.startsWith('data:')) {
360
+ // 处理 base64 格式图像
361
+ const match = imageUrl.match(/^data:([^;]+);base64,(.+)$/);
362
+ if (match) {
363
+ geminiContent.parts.push({
364
+ inlineData: {
365
+ mimeType: match[1],
366
+ data: match[2],
367
+ },
368
+ });
369
+ }
370
+ }
371
+ // URL 格式需要下载后转换,这里暂时跳过
372
+ }
373
+ }
374
+ }
375
+ }
376
+ // 处理字符串格式 content
377
+ else if (typeof msg.content === 'string') {
378
+ geminiContent.parts.push({ text: msg.content });
379
+ }
380
+ // 确保至少有一个 part
381
+ if (geminiContent.parts.length === 0) {
382
+ geminiContent.parts.push({ text: '' });
383
+ }
384
+ geminiRequest.contents.push(geminiContent);
385
+ }
386
+ }
387
+ // 构建生成配置
388
+ const generationConfig = {};
389
+ if (typeof temperature === 'number') {
390
+ generationConfig.temperature = temperature;
391
+ }
392
+ if (typeof top_p === 'number') {
393
+ generationConfig.topP = top_p;
394
+ }
395
+ if (typeof max_output_tokens === 'number') {
396
+ generationConfig.maxOutputTokens = max_output_tokens;
397
+ }
398
+ else if (typeof max_tokens === 'number') {
399
+ generationConfig.maxOutputTokens = max_tokens;
400
+ }
401
+ // 处理 stop: Responses API 是数组,Gemini 也是数组
402
+ if (Array.isArray(stop)) {
403
+ generationConfig.stopSequences = stop;
404
+ }
405
+ else if (typeof stop === 'string') {
406
+ generationConfig.stopSequences = [stop];
407
+ }
408
+ // 处理 reasoning -> thinkingConfig
409
+ if (reasoning) {
410
+ const thinkingConfig = createGeminiThinkingConfigFromResponsesReasoning(reasoning);
411
+ if (thinkingConfig) {
412
+ generationConfig.thinkingConfig = thinkingConfig;
413
+ }
414
+ }
415
+ if (Object.keys(generationConfig).length > 0) {
416
+ geminiRequest.generationConfig = generationConfig;
417
+ }
418
+ // 转换 tools
419
+ if (Array.isArray(tools)) {
420
+ const functionDeclarations = [];
421
+ for (const tool of tools) {
422
+ if (tool && tool.type === 'function' && tool.function) {
423
+ functionDeclarations.push({
424
+ name: tool.function.name,
425
+ description: tool.function.description || '',
426
+ parameters: (0, exports.sanitizeSchemaForGeminiFunctionDeclaration)(tool.function.parameters || { type: 'object', properties: {}, required: [] }),
427
+ });
428
+ }
429
+ }
430
+ if (functionDeclarations.length > 0) {
431
+ geminiRequest.tools = [{ functionDeclarations }];
432
+ }
433
+ }
434
+ // 转换 tool_choice -> toolConfig
435
+ if (tool_choice !== undefined) {
436
+ const toolConfig = { functionCallingConfig: {} };
437
+ if (tool_choice === 'auto') {
438
+ toolConfig.functionCallingConfig.mode = 'AUTO';
439
+ }
440
+ else if (tool_choice === 'required' || tool_choice === 'any') {
441
+ toolConfig.functionCallingConfig.mode = 'ANY';
442
+ }
443
+ else if (tool_choice === 'none') {
444
+ toolConfig.functionCallingConfig.mode = 'NONE';
445
+ }
446
+ else if (typeof tool_choice === 'object' && tool_choice.type === 'function') {
447
+ const tc = tool_choice;
448
+ if ((_a = tc.function) === null || _a === void 0 ? void 0 : _a.name) {
449
+ toolConfig.functionCallingConfig.mode = 'ANY';
450
+ toolConfig.functionCallingConfig.allowedFunctionNames = [tc.function.name];
451
+ }
452
+ }
453
+ if (Object.keys(toolConfig.functionCallingConfig).length > 0) {
454
+ geminiRequest.toolConfig = toolConfig;
455
+ }
456
+ }
457
+ return geminiRequest;
458
+ }
459
+ /**
460
+ * 将 codex 发起的对 Responses API 的请求转换为对 Claude API 的请求的数据格式
461
+ */
462
+ function transformRequestFromResponsesToClaude(body, targetModel) {
463
+ var _a;
464
+ const { model, instructions, input, max_output_tokens, max_tokens, temperature, top_p, stop, tools, tool_choice } = body;
465
+ const messages = [];
466
+ // 1. 处理 instructions 字段(系统提示词)
467
+ // Claude API 使用 system 字段,不在 messages 中
468
+ let system = '';
469
+ if (instructions && typeof instructions === 'string') {
470
+ system = instructions;
471
+ }
472
+ // 2. 处理 input 字段(消息数组)
473
+ if (Array.isArray(input)) {
474
+ for (const msg of input) {
475
+ if (!msg || msg.type !== 'message') {
476
+ continue;
477
+ }
478
+ // 提取 content 数组中的内容
479
+ const contentBlocks = [];
480
+ if (Array.isArray(msg.content)) {
481
+ for (const contentItem of msg.content) {
482
+ if (!contentItem || typeof contentItem !== 'object') {
483
+ continue;
484
+ }
485
+ // input_text -> text
486
+ if (contentItem.type === 'input_text' && typeof contentItem.text === 'string') {
487
+ contentBlocks.push({ type: 'text', text: contentItem.text });
488
+ }
489
+ // input_image -> image(Claude 格式)
490
+ if (contentItem.type === 'input_image' && contentItem.image_url) {
491
+ const imageUrl = contentItem.image_url.url;
492
+ if (typeof imageUrl === 'string') {
493
+ if (imageUrl.startsWith('data:')) {
494
+ const match = imageUrl.match(/^data:([^;]+);base64,(.+)$/);
495
+ if (match) {
496
+ contentBlocks.push({
497
+ type: 'image',
498
+ source: {
499
+ type: 'base64',
500
+ media_type: match[1],
501
+ data: match[2],
502
+ },
503
+ });
504
+ }
505
+ }
506
+ else {
507
+ // URL 格式
508
+ contentBlocks.push({
509
+ type: 'image',
510
+ source: {
511
+ type: 'url',
512
+ url: imageUrl,
513
+ },
514
+ });
515
+ }
516
+ }
517
+ }
518
+ }
519
+ }
520
+ else if (typeof msg.content === 'string') {
521
+ contentBlocks.push({ type: 'text', text: msg.content });
522
+ }
523
+ // 映射角色: developer -> user
524
+ const role = msg.role === 'developer' ? 'user' : msg.role;
525
+ // 添加到 messages 数组
526
+ if (contentBlocks.length > 0) {
527
+ messages.push({
528
+ role,
529
+ content: contentBlocks,
530
+ });
531
+ }
532
+ }
533
+ }
534
+ // 3. 构建转换后的请求
535
+ const transformed = {
536
+ model: targetModel || model,
537
+ max_tokens: max_output_tokens || max_tokens,
538
+ };
539
+ // 添加 messages
540
+ if (messages.length > 0) {
541
+ transformed.messages = messages;
542
+ }
543
+ // 添加 system
544
+ if (system) {
545
+ transformed.system = system;
546
+ }
547
+ // 4. 处理工具定义转换
548
+ // Responses API: { type: "function", function: { name, description, parameters } }
549
+ // Claude: { name, description, input_schema: parameters }
550
+ if (Array.isArray(tools)) {
551
+ transformed.tools = tools.map((tool) => {
552
+ if (tool && tool.type === 'function' && tool.function) {
553
+ return {
554
+ name: tool.function.name,
555
+ description: tool.function.description || '',
556
+ input_schema: tool.function.parameters || { type: 'object', properties: {}, required: [] },
557
+ };
558
+ }
559
+ return null;
560
+ }).filter(Boolean);
561
+ }
562
+ // 5. 处理 tool_choice 映射
563
+ // Responses API: "auto" | "required" | "none" | { type: "function", function: { name } }
564
+ // Claude: "auto" | "any" | "none" | { type: "tool", name: string }
565
+ if (tool_choice !== undefined) {
566
+ if (tool_choice === 'auto') {
567
+ transformed.tool_choice = 'auto';
568
+ }
569
+ else if (tool_choice === 'required') {
570
+ transformed.tool_choice = 'any';
571
+ }
572
+ else if (tool_choice === 'none') {
573
+ transformed.tool_choice = 'none';
574
+ }
575
+ else if (typeof tool_choice === 'object' && tool_choice.type === 'function') {
576
+ const tc = tool_choice;
577
+ if ((_a = tc.function) === null || _a === void 0 ? void 0 : _a.name) {
578
+ transformed.tool_choice = {
579
+ type: 'tool',
580
+ name: tc.function.name,
581
+ };
582
+ }
583
+ }
584
+ }
585
+ // 6. 处理其他参数
586
+ if (typeof temperature === 'number') {
587
+ transformed.temperature = temperature;
588
+ }
589
+ if (typeof top_p === 'number') {
590
+ transformed.top_p = top_p;
591
+ }
592
+ if (body.stream !== undefined) {
593
+ transformed.stream = body.stream;
594
+ }
595
+ // 处理 stop: Responses API 是数组,Claude 是 stop_sequences
596
+ if (Array.isArray(stop)) {
597
+ transformed.stop_sequences = stop;
598
+ }
599
+ else if (typeof stop === 'string') {
600
+ transformed.stop_sequences = [stop];
601
+ }
602
+ return transformed;
603
+ }
604
+ /**
605
+ * 将 codex 发起的对 Responses API 的请求转换为对 Chat Completions API 的请求的数据格式
606
+ * @param body Responses API 格式的请求体
607
+ * @param targetModel 目标模型名称(可选)
608
+ * @returns Chat Completions API 格式的请求体
609
+ */
610
+ function transformRequestFromResponsesToChatCompletions(body, targetModel) {
611
+ var _a;
612
+ const { model, instructions, input, max_output_tokens, reasoning, tools, tool_choice, parallel_tool_calls, max_tool_calls } = body, others = __rest(body, ["model", "instructions", "input", "max_output_tokens", "reasoning", "tools", "tool_choice", "parallel_tool_calls", "max_tool_calls"]);
613
+ /**
614
+ * 将 Responses API 的 content item 转换为 Chat Completions 格式
615
+ * Responses API: { type: "input_text", text: "..." }
616
+ * Chat Completions: { type: "text", text: "..." }
617
+ * Responses API: { type: "input_image", image_url: { url: "..." } }
618
+ * Chat Completions: { type: "image_url", image_url: { url: "..." } }
619
+ */
620
+ const transformResponsesContentItemToChatCompletionContentItem = (item) => {
621
+ if (!item || typeof item !== 'object') {
622
+ return null;
623
+ }
624
+ if (item.type === 'input_text') {
625
+ return { type: 'text', text: item.text };
626
+ }
627
+ if (item.type === 'input_image' && item.image_url) {
628
+ return { type: 'image_url', image_url: item.image_url };
629
+ }
630
+ // 其他类型直接返回
631
+ return item;
632
+ };
633
+ // 输入验证:检查 input 是否为数组
634
+ if (!Array.isArray(input)) {
635
+ // 如果 input 不是数组,尝试处理字符串格式
636
+ const messages = [];
637
+ const systemRole = (0, exports.shouldUseDeveloperRoleAsSystemRole)(targetModel || model) ? 'developer' : 'system';
638
+ // 处理 instructions
639
+ if (instructions && typeof instructions === 'string') {
640
+ messages.push({
641
+ role: systemRole,
642
+ content: instructions,
643
+ });
644
+ }
645
+ // 处理 input(如果是字符串)
646
+ if (typeof input === 'string' && input) {
647
+ messages.push({
648
+ role: 'user',
649
+ content: input,
650
+ });
651
+ }
652
+ // 构建转换后的请求
653
+ const result = {
654
+ model: targetModel || model,
655
+ messages,
656
+ };
657
+ // 处理 max_tokens(Responses API 使用 max_output_tokens)
658
+ if (typeof max_output_tokens === 'number') {
659
+ result.max_tokens = max_output_tokens;
660
+ }
661
+ else if (typeof others.max_tokens === 'number') {
662
+ result.max_tokens = others.max_tokens;
663
+ }
664
+ // 处理 tools
665
+ if (Array.isArray(tools)) {
666
+ result.tools = tools;
667
+ }
668
+ // 处理 tool_choice
669
+ if (tool_choice !== undefined) {
670
+ result.tool_choice = tool_choice;
671
+ }
672
+ // 处理 parallel_tool_calls
673
+ if (parallel_tool_calls !== undefined) {
674
+ result.parallel_tool_calls = parallel_tool_calls;
675
+ }
676
+ // 处理 reasoning(Chat Completions API 可能不直接支持,但保留用于兼容)
677
+ if (reasoning) {
678
+ result.reasoning = reasoning;
679
+ }
680
+ // 添加其他兼容的字段(temperature, top_p, stream 等)
681
+ const compatibleFields = ['temperature', 'top_p', 'stream', 'stop', 'frequency_penalty', 'presence_penalty', 'seed', 'user', 'response_format'];
682
+ for (const field of compatibleFields) {
683
+ if (others[field] !== undefined) {
684
+ result[field] = others[field];
685
+ }
686
+ }
687
+ return result;
688
+ }
689
+ // 提取 developer 消息和普通消息
690
+ const developerItems = input.filter((item) => item.type === 'message' && item.role === 'developer');
691
+ const nonDeveloperItems = input.filter((item) => item.type === 'message' && item.role !== 'developer');
692
+ // 构建 messages 数组
693
+ const messages = [];
694
+ // 处理系统/developer 消息
695
+ const systemRole = (0, exports.shouldUseDeveloperRoleAsSystemRole)(targetModel || model) ? 'developer' : 'system';
696
+ const systemContentItems = [];
697
+ // 添加 instructions
698
+ if (instructions && typeof instructions === 'string') {
699
+ systemContentItems.push({ type: 'text', text: instructions });
700
+ }
701
+ // 添加 developer 消息中的内容
702
+ for (const item of developerItems) {
703
+ if (!item)
704
+ continue;
705
+ const itemContent = Array.isArray(item.content)
706
+ ? item.content.map(transformResponsesContentItemToChatCompletionContentItem).filter(Boolean)
707
+ : (typeof item.content === 'string' ? [{ type: 'text', text: item.content }] : []);
708
+ systemContentItems.push(...itemContent);
709
+ }
710
+ // 只有当有系统内容时才添加系统消息
711
+ if (systemContentItems.length > 0) {
712
+ messages.push({
713
+ role: systemRole,
714
+ content: systemContentItems,
715
+ });
716
+ }
717
+ // 处理非 developer 消息
718
+ for (const item of nonDeveloperItems) {
719
+ if (!item || item.type !== 'message')
720
+ continue;
721
+ const messageContent = Array.isArray(item.content)
722
+ ? item.content.map(transformResponsesContentItemToChatCompletionContentItem).filter(Boolean)
723
+ : (typeof item.content === 'string' ? item.content : []);
724
+ messages.push({
725
+ role: item.role,
726
+ content: messageContent,
727
+ });
728
+ }
729
+ // 构建转换后的请求
730
+ const result = {
731
+ model: targetModel || model,
732
+ messages,
733
+ };
734
+ // 处理 max_tokens(Responses API 使用 max_output_tokens)
735
+ if (typeof max_output_tokens === 'number') {
736
+ result.max_tokens = max_output_tokens;
737
+ }
738
+ else if (typeof others.max_tokens === 'number') {
739
+ result.max_tokens = others.max_tokens;
740
+ }
741
+ // 处理 tools:需要确保格式正确且不包含空函数
742
+ if (Array.isArray(tools) && tools.length > 0) {
743
+ const validTools = tools.map((tool) => {
744
+ if (tool && tool.type === 'function' && tool.function) {
745
+ const fn = tool.function;
746
+ // 验证必需字段
747
+ if (!fn.name || typeof fn.name !== 'string') {
748
+ return null;
749
+ }
750
+ // 确保参数格式正确
751
+ const params = fn.parameters || { type: 'object', properties: {}, required: [] };
752
+ if (typeof params !== 'object' || params.type !== 'object') {
753
+ return null;
754
+ }
755
+ return {
756
+ type: 'function',
757
+ function: Object.assign({ name: fn.name, description: fn.description || '', parameters: params }, (fn.strict !== undefined && { strict: fn.strict }))
758
+ };
759
+ }
760
+ return null;
761
+ }).filter(Boolean);
762
+ // 只有当有有效工具时才添加 tools 字段
763
+ if (validTools.length > 0) {
764
+ result.tools = validTools;
765
+ }
766
+ }
767
+ // 处理 tool_choice
768
+ if (tool_choice !== undefined) {
769
+ // 验证 tool_choice 格式
770
+ if (typeof tool_choice === 'string' && ['auto', 'none', 'required'].includes(tool_choice)) {
771
+ result.tool_choice = tool_choice;
772
+ }
773
+ else if (typeof tool_choice === 'object' && tool_choice.type === 'function' && ((_a = tool_choice.function) === null || _a === void 0 ? void 0 : _a.name)) {
774
+ result.tool_choice = {
775
+ type: 'function',
776
+ function: { name: tool_choice.function.name }
777
+ };
778
+ }
779
+ }
780
+ // 处理 parallel_tool_calls
781
+ if (parallel_tool_calls !== undefined) {
782
+ result.parallel_tool_calls = parallel_tool_calls;
783
+ }
784
+ // 处理 reasoning(Chat Completions API 可能不直接支持,但保留用于兼容)
785
+ if (reasoning) {
786
+ result.reasoning = reasoning;
787
+ }
788
+ // 添加其他兼容的字段(temperature, top_p, stream 等)
789
+ const compatibleFields = ['temperature', 'top_p', 'stream', 'stop', 'frequency_penalty', 'presence_penalty', 'seed', 'user', 'response_format'];
790
+ for (const field of compatibleFields) {
791
+ if (others[field] !== undefined) {
792
+ result[field] = others[field];
793
+ }
794
+ }
795
+ return result;
796
+ }
797
+ // ----------------------- claude code 发起的请求转换 -----------------------
798
+ /**
799
+ * 将 claude code 发起的请求转换成对 gemini API 的请求
800
+ * @param body
801
+ * @param _model
802
+ */
803
+ function transformRequestFromClaudeToGemini(body, _model) {
804
+ const { system, messages, max_tokens, temperature, top_p, stop_sequences, tools, tool_choice, thinking } = body;
805
+ const geminiRequest = {
806
+ contents: [],
807
+ };
808
+ // 处理 system 指令
809
+ if (system) {
810
+ let systemText = '';
811
+ if (typeof system === 'string') {
812
+ systemText = system;
813
+ }
814
+ else if (Array.isArray(system)) {
815
+ const textParts = [];
816
+ for (const block of system) {
817
+ if (block && block.type === 'text' && typeof block.text === 'string') {
818
+ textParts.push(block.text);
819
+ }
820
+ }
821
+ systemText = textParts.join('\n\n');
822
+ }
823
+ else if (system && typeof system === 'object' && system.type === 'text') {
824
+ systemText = system.text;
825
+ }
826
+ if (systemText) {
827
+ geminiRequest.systemInstruction = {
828
+ role: 'user',
829
+ parts: [{ text: systemText }]
830
+ };
831
+ }
832
+ }
833
+ // 转换 messages
834
+ if (Array.isArray(messages)) {
835
+ for (const msg of messages) {
836
+ if (!msg || typeof msg !== 'object')
837
+ continue;
838
+ const geminiRole = msg.role === 'assistant' ? 'model' :
839
+ msg.role === 'tool' ? 'function' : 'user';
840
+ const geminiContent = {
841
+ role: geminiRole,
842
+ parts: [],
843
+ };
844
+ if (typeof msg.content === 'string') {
845
+ geminiContent.parts.push({ text: msg.content });
846
+ }
847
+ else if (Array.isArray(msg.content)) {
848
+ for (const block of msg.content) {
849
+ if (!block || typeof block !== 'object')
850
+ continue;
851
+ // text → text
852
+ if (block.type === 'text' && typeof block.text === 'string') {
853
+ geminiContent.parts.push({ text: block.text });
854
+ }
855
+ // image → inlineData
856
+ if (block.type === 'image' && block.source) {
857
+ const source = block.source;
858
+ if (source.type === 'base64' && source.data && source.media_type) {
859
+ geminiContent.parts.push({
860
+ inlineData: {
861
+ mimeType: source.media_type,
862
+ data: source.data
863
+ }
864
+ });
865
+ }
866
+ else if (source.type === 'url' && source.url) {
867
+ // URL 格式需要特殊处理,这里暂时跳过
868
+ }
869
+ }
870
+ // tool_use → functionCall
871
+ if (block.type === 'tool_use') {
872
+ geminiContent.parts.push({
873
+ functionCall: {
874
+ name: block.name || 'tool',
875
+ args: block.input || {}
876
+ }
877
+ });
878
+ }
879
+ // tool_result → functionResponse
880
+ if (block.type === 'tool_result') {
881
+ // Claude 的 tool_result 包含 tool_use_id,但 Gemini 需要的是函数名
882
+ // 这里暂时使用 'tool' 作为函数名,实际应该从上下文中获取正确的函数名
883
+ geminiContent.parts.push({
884
+ functionResponse: {
885
+ name: 'tool', // TODO: 应该从之前的 tool_use 中获取正确的函数名
886
+ response: typeof msg.content === 'string' ? msg.content : msg.content || {}
887
+ }
888
+ });
889
+ }
890
+ }
891
+ }
892
+ else if (typeof msg.content === 'string') {
893
+ // tool 消息的处理
894
+ geminiContent.parts.push({
895
+ functionResponse: {
896
+ name: 'tool', // TODO: 应该从 tool_use_id 对应的函数中获取
897
+ response: msg.content || {}
898
+ }
899
+ });
900
+ }
901
+ // 确保至少有一个 part
902
+ if (geminiContent.parts.length === 0) {
903
+ geminiContent.parts.push({ text: '' });
904
+ }
905
+ geminiRequest.contents.push(geminiContent);
906
+ }
907
+ }
908
+ // 构建生成配置
909
+ const generationConfig = {};
910
+ if (typeof temperature === 'number') {
911
+ generationConfig.temperature = temperature;
912
+ }
913
+ if (typeof top_p === 'number') {
914
+ generationConfig.topP = top_p;
915
+ }
916
+ if (typeof max_tokens === 'number') {
917
+ generationConfig.maxOutputTokens = max_tokens;
918
+ }
919
+ // 处理 stop_sequences -> stopSequences
920
+ if (Array.isArray(stop_sequences)) {
921
+ generationConfig.stopSequences = stop_sequences;
922
+ }
923
+ // 转换 thinking → thinkingConfig
924
+ if (thinking) {
925
+ const thinkingConfig = createGeminiThinkingConfigFromClaudeThinking(thinking);
926
+ if (thinkingConfig) {
927
+ generationConfig.thinkingConfig = thinkingConfig;
928
+ }
929
+ }
930
+ if (Object.keys(generationConfig).length > 0) {
931
+ geminiRequest.generationConfig = generationConfig;
932
+ }
933
+ // 转换 tools
934
+ // Claude: { name, description, input_schema }
935
+ // Gemini: { functionDeclarations: [{ name, description, parameters }] }
936
+ if (Array.isArray(tools)) {
937
+ const functionDeclarations = [];
938
+ for (const tool of tools) {
939
+ if (tool && tool.name) {
940
+ functionDeclarations.push({
941
+ name: tool.name,
942
+ description: tool.description || '',
943
+ parameters: (0, exports.sanitizeSchemaForGeminiFunctionDeclaration)(tool.input_schema || { type: 'object', properties: {}, required: [] })
944
+ });
945
+ }
946
+ }
947
+ if (functionDeclarations.length > 0) {
948
+ geminiRequest.tools = [{ functionDeclarations }];
949
+ }
950
+ }
951
+ // 转换 tool_choice
952
+ if (tool_choice) {
953
+ const toolConfig = { functionCallingConfig: {} };
954
+ if (tool_choice === 'auto') {
955
+ toolConfig.functionCallingConfig.mode = 'AUTO';
956
+ }
957
+ else if (tool_choice === 'any' || tool_choice === 'required') {
958
+ toolConfig.functionCallingConfig.mode = 'ANY';
959
+ }
960
+ else if (tool_choice === 'none') {
961
+ toolConfig.functionCallingConfig.mode = 'NONE';
962
+ }
963
+ else if (typeof tool_choice === 'object') {
964
+ const tc = tool_choice;
965
+ if (tc.type === 'tool' && tc.name) {
966
+ toolConfig.functionCallingConfig.mode = 'ANY';
967
+ toolConfig.functionCallingConfig.allowedFunctionNames = [tc.name];
968
+ }
969
+ }
970
+ if (Object.keys(toolConfig.functionCallingConfig).length > 0) {
971
+ geminiRequest.toolConfig = toolConfig;
972
+ }
973
+ }
974
+ return geminiRequest;
975
+ }
976
+ /**
977
+ * 将 claude code 发起的请求转换成对 responses API 的请求
978
+ * @param body
979
+ * @param model
980
+ */
981
+ function transformRequestFromClaudeToResponses(body, model) {
982
+ const { system, messages, max_tokens, temperature, top_p, stop_sequences, tools, tool_choice } = body;
983
+ const input = [];
984
+ let instructions = '';
985
+ // 处理 system 指令
986
+ if (system) {
987
+ if (typeof system === 'string') {
988
+ instructions = system;
989
+ }
990
+ else if (Array.isArray(system)) {
991
+ const textParts = [];
992
+ for (const block of system) {
993
+ if (block && block.type === 'text' && typeof block.text === 'string') {
994
+ textParts.push(block.text);
995
+ }
996
+ }
997
+ instructions = textParts.join('\n\n');
998
+ }
999
+ else if (system && typeof system === 'object' && system.type === 'text') {
1000
+ instructions = system.text;
1001
+ }
1002
+ }
1003
+ // 转换 messages
1004
+ if (Array.isArray(messages)) {
1005
+ for (const msg of messages) {
1006
+ if (!msg || typeof msg !== 'object')
1007
+ continue;
1008
+ const content = [];
1009
+ if (typeof msg.content === 'string') {
1010
+ content.push({
1011
+ type: 'input_text',
1012
+ text: msg.content
1013
+ });
1014
+ }
1015
+ else if (Array.isArray(msg.content)) {
1016
+ for (const block of msg.content) {
1017
+ if (!block || typeof block !== 'object')
1018
+ continue;
1019
+ // text → input_text
1020
+ if (block.type === 'text' && typeof block.text === 'string') {
1021
+ content.push({
1022
+ type: 'input_text',
1023
+ text: block.text
1024
+ });
1025
+ }
1026
+ // image → input_image
1027
+ if (block.type === 'image' && block.source) {
1028
+ const source = block.source;
1029
+ if (source.type === 'base64' && source.data && source.media_type) {
1030
+ const dataUrl = `data:${source.media_type};base64,${source.data}`;
1031
+ content.push({
1032
+ type: 'input_image',
1033
+ image_url: { url: dataUrl }
1034
+ });
1035
+ }
1036
+ else if (source.type === 'url' && source.url) {
1037
+ content.push({
1038
+ type: 'input_image',
1039
+ image_url: { url: source.url }
1040
+ });
1041
+ }
1042
+ }
1043
+ // tool_use → function_call (Responses API 格式)
1044
+ if (block.type === 'tool_use') {
1045
+ // Responses API 在 output 中包含 function_call,不是在 input 中
1046
+ // 所以这里不转换 tool_use,只保留文本和图像
1047
+ }
1048
+ }
1049
+ }
1050
+ input.push({
1051
+ type: 'message',
1052
+ role: msg.role,
1053
+ content: content
1054
+ });
1055
+ }
1056
+ }
1057
+ const result = {
1058
+ model: model || body.model,
1059
+ input,
1060
+ };
1061
+ if (instructions) {
1062
+ result.instructions = instructions;
1063
+ }
1064
+ if (typeof temperature === 'number') {
1065
+ result.temperature = temperature;
1066
+ }
1067
+ if (typeof top_p === 'number') {
1068
+ result.top_p = top_p;
1069
+ }
1070
+ if (typeof max_tokens === 'number') {
1071
+ result.max_output_tokens = max_tokens;
1072
+ }
1073
+ // 处理 stop_sequences -> stop
1074
+ if (Array.isArray(stop_sequences)) {
1075
+ result.stop = stop_sequences;
1076
+ }
1077
+ else if (typeof stop_sequences === 'string') {
1078
+ result.stop = [stop_sequences];
1079
+ }
1080
+ // 处理 tools: Claude 格式 → Responses API 格式
1081
+ // Claude: { name, description, input_schema }
1082
+ // Responses: { type: "function", function: { name, description, parameters } }
1083
+ if (Array.isArray(tools)) {
1084
+ result.tools = tools.map((tool) => {
1085
+ if (tool && tool.name) {
1086
+ return {
1087
+ type: 'function',
1088
+ function: {
1089
+ name: tool.name,
1090
+ description: tool.description || '',
1091
+ parameters: tool.input_schema || { type: 'object', properties: {}, required: [] },
1092
+ },
1093
+ };
1094
+ }
1095
+ return null;
1096
+ }).filter(Boolean);
1097
+ }
1098
+ // 处理 tool_choice
1099
+ // Claude: "auto" | "any" | "none" | { type: "tool", name }
1100
+ // Responses: "auto" | "required" | "none" | { type: "function", function: { name } }
1101
+ if (tool_choice !== undefined) {
1102
+ if (tool_choice === 'auto') {
1103
+ result.tool_choice = 'auto';
1104
+ }
1105
+ else if (tool_choice === 'any') {
1106
+ result.tool_choice = 'required';
1107
+ }
1108
+ else if (tool_choice === 'none') {
1109
+ result.tool_choice = 'none';
1110
+ }
1111
+ else if (typeof tool_choice === 'object' && tool_choice.type === 'tool') {
1112
+ const tc = tool_choice;
1113
+ if (tc.name) {
1114
+ result.tool_choice = {
1115
+ type: 'function',
1116
+ function: { name: tc.name },
1117
+ };
1118
+ }
1119
+ }
1120
+ }
1121
+ return result;
1122
+ }
1123
+ /**
1124
+ * 将 claude code 发起的请求转换成对 chat-completions API 的请求
1125
+ * @param body
1126
+ * @param model
1127
+ */
1128
+ function transformRequestFromClaudeToChatCompletions(body, model) {
1129
+ const { system, messages, max_tokens, temperature, top_p, stop_sequences, tools, tool_choice, thinking } = body;
1130
+ const transformedMessages = [];
1131
+ let systemText = '';
1132
+ // 处理 system 指令
1133
+ if (system) {
1134
+ if (typeof system === 'string') {
1135
+ systemText = system;
1136
+ }
1137
+ else if (Array.isArray(system)) {
1138
+ const textParts = [];
1139
+ for (const block of system) {
1140
+ if (block && block.type === 'text' && typeof block.text === 'string') {
1141
+ textParts.push(block.text);
1142
+ }
1143
+ }
1144
+ systemText = textParts.join('\n\n');
1145
+ }
1146
+ else if (system && typeof system === 'object' && system.type === 'text') {
1147
+ systemText = system.text;
1148
+ }
1149
+ }
1150
+ // 转换 messages
1151
+ if (Array.isArray(messages)) {
1152
+ for (const msg of messages) {
1153
+ if (!msg || typeof msg !== 'object')
1154
+ continue;
1155
+ const transformedMsg = {
1156
+ role: msg.role,
1157
+ };
1158
+ if (typeof msg.content === 'string') {
1159
+ transformedMsg.content = msg.content;
1160
+ }
1161
+ else if (Array.isArray(msg.content)) {
1162
+ const content = [];
1163
+ for (const block of msg.content) {
1164
+ if (!block || typeof block !== 'object')
1165
+ continue;
1166
+ // text → text
1167
+ if (block.type === 'text' && typeof block.text === 'string') {
1168
+ content.push({ type: 'text', text: block.text });
1169
+ }
1170
+ // image → image_url
1171
+ if (block.type === 'image' && block.source) {
1172
+ const source = block.source;
1173
+ if (source.type === 'base64' && source.data && source.media_type) {
1174
+ const dataUrl = `data:${source.media_type};base64,${source.data}`;
1175
+ content.push({
1176
+ type: 'image_url',
1177
+ image_url: { url: dataUrl }
1178
+ });
1179
+ }
1180
+ else if (source.type === 'url' && source.url) {
1181
+ content.push({
1182
+ type: 'image_url',
1183
+ image_url: { url: source.url }
1184
+ });
1185
+ }
1186
+ }
1187
+ // tool_use → tool_calls
1188
+ if (block.type === 'tool_use') {
1189
+ if (!transformedMsg.tool_calls) {
1190
+ transformedMsg.tool_calls = [];
1191
+ }
1192
+ transformedMsg.tool_calls.push({
1193
+ id: block.id,
1194
+ type: 'function',
1195
+ function: {
1196
+ name: block.name || 'tool',
1197
+ arguments: JSON.stringify(block.input || {})
1198
+ }
1199
+ });
1200
+ }
1201
+ // thinking → thinking(Chat Completions API 可能不支持,但保留)
1202
+ if (block.type === 'thinking') {
1203
+ content.push({
1204
+ type: 'thinking',
1205
+ thinking: block.thinking
1206
+ });
1207
+ }
1208
+ }
1209
+ if (content.length > 0 || !transformedMsg.tool_calls) {
1210
+ transformedMsg.content = content.length > 0 ? content : '';
1211
+ }
1212
+ }
1213
+ // tool_result → tool 消息
1214
+ if (msg.role === 'tool') {
1215
+ if (typeof msg.content === 'string') {
1216
+ transformedMsg.content = msg.content;
1217
+ }
1218
+ else if (Array.isArray(msg.content)) {
1219
+ const toolContent = [];
1220
+ for (const block of msg.content) {
1221
+ if (block && block.type === 'text' && typeof block.text === 'string') {
1222
+ toolContent.push(block.text);
1223
+ }
1224
+ }
1225
+ transformedMsg.content = toolContent.join('\n');
1226
+ }
1227
+ transformedMsg.tool_call_id = msg.tool_use_id || '';
1228
+ }
1229
+ transformedMessages.push(transformedMsg);
1230
+ }
1231
+ }
1232
+ const result = {
1233
+ model: model || body.model,
1234
+ messages: transformedMessages,
1235
+ };
1236
+ // 处理 system
1237
+ if (systemText) {
1238
+ result.system = systemText;
1239
+ }
1240
+ // 处理 max_tokens
1241
+ if (typeof max_tokens === 'number') {
1242
+ result.max_tokens = max_tokens;
1243
+ }
1244
+ // 处理 temperature
1245
+ if (typeof temperature === 'number') {
1246
+ result.temperature = temperature;
1247
+ }
1248
+ // 处理 top_p
1249
+ if (typeof top_p === 'number') {
1250
+ result.top_p = top_p;
1251
+ }
1252
+ // 处理 stop_sequences -> stop
1253
+ if (Array.isArray(stop_sequences)) {
1254
+ result.stop = stop_sequences;
1255
+ }
1256
+ else if (typeof stop_sequences === 'string') {
1257
+ result.stop = [stop_sequences];
1258
+ }
1259
+ // 转换 tools: Claude 格式 → Chat Completions 格式
1260
+ // Claude: { name, description, input_schema }
1261
+ // Chat Completions: { type: "function", function: { name, description, parameters } }
1262
+ if (Array.isArray(tools)) {
1263
+ result.tools = tools.map((tool) => {
1264
+ if (tool && tool.name) {
1265
+ return {
1266
+ type: 'function',
1267
+ function: {
1268
+ name: tool.name,
1269
+ description: tool.description || '',
1270
+ parameters: tool.input_schema || { type: 'object', properties: {}, required: [] }
1271
+ }
1272
+ };
1273
+ }
1274
+ return null;
1275
+ }).filter(Boolean);
1276
+ }
1277
+ // 转换 tool_choice
1278
+ // Claude: "auto" | "any" | "none" | { type: "tool", name }
1279
+ // Chat Completions: "auto" | "required" | "none" | { type: "function", function: { name } }
1280
+ if (tool_choice !== undefined) {
1281
+ if (tool_choice === 'auto') {
1282
+ result.tool_choice = 'auto';
1283
+ }
1284
+ else if (tool_choice === 'any') {
1285
+ result.tool_choice = 'required';
1286
+ }
1287
+ else if (tool_choice === 'none') {
1288
+ result.tool_choice = 'none';
1289
+ }
1290
+ else if (typeof tool_choice === 'object' && tool_choice.type === 'tool') {
1291
+ const tc = tool_choice;
1292
+ if (tc.name) {
1293
+ result.tool_choice = {
1294
+ type: 'function',
1295
+ function: { name: tc.name }
1296
+ };
1297
+ }
1298
+ }
1299
+ }
1300
+ // 转换 thinking → reasoning
1301
+ if (thinking) {
1302
+ result.reasoning = thinking;
1303
+ }
1304
+ return result;
1305
+ }
1306
+ // ===================== codex 得到 responses 数据 =======================
1307
+ function transformResponseFromChatCompletionsToResponses(response) {
1308
+ if (!response || typeof response !== 'object') {
1309
+ return response;
1310
+ }
1311
+ const choice = Array.isArray(response.choices) && response.choices.length > 0 ? response.choices[0] : null;
1312
+ const output = [];
1313
+ // 转换消息内容
1314
+ if (choice === null || choice === void 0 ? void 0 : choice.message) {
1315
+ const message = choice.message;
1316
+ const messageContent = [];
1317
+ // 处理文本内容
1318
+ if (typeof message.content === 'string') {
1319
+ messageContent.push({
1320
+ type: 'output_text',
1321
+ text: message.content
1322
+ });
1323
+ }
1324
+ else if (Array.isArray(message.content)) {
1325
+ for (const item of message.content) {
1326
+ if (!item || typeof item !== 'object')
1327
+ continue;
1328
+ if (item.type === 'text' && typeof item.text === 'string') {
1329
+ messageContent.push({
1330
+ type: 'output_text',
1331
+ text: item.text
1332
+ });
1333
+ }
1334
+ if (item.type === 'image_url' && item.image_url) {
1335
+ messageContent.push({
1336
+ type: 'image',
1337
+ source: {
1338
+ type: 'url',
1339
+ url: item.image_url.url
1340
+ }
1341
+ });
1342
+ }
1343
+ }
1344
+ }
1345
+ if (messageContent.length > 0) {
1346
+ output.push({
1347
+ type: 'message',
1348
+ role: 'assistant',
1349
+ content: messageContent
1350
+ });
1351
+ }
1352
+ // 处理工具调用
1353
+ if (Array.isArray(message.tool_calls)) {
1354
+ for (const toolCall of message.tool_calls) {
1355
+ if (toolCall && toolCall.type === 'function') {
1356
+ output.push({
1357
+ type: 'function_call',
1358
+ id: toolCall.id,
1359
+ name: toolCall.function.name,
1360
+ arguments: toolCall.function.arguments || '{}'
1361
+ });
1362
+ }
1363
+ }
1364
+ }
1365
+ }
1366
+ // 如果没有内容,添加空消息
1367
+ if (output.length === 0) {
1368
+ output.push({
1369
+ type: 'message',
1370
+ role: 'assistant',
1371
+ content: [{
1372
+ type: 'output_text',
1373
+ text: ''
1374
+ }]
1375
+ });
1376
+ }
1377
+ // 映射 finish reason 到 status
1378
+ // Chat Completions: "stop" | "length" | "tool_calls" | "content_filter"
1379
+ // Responses: "completed" | "incomplete"
1380
+ let status = 'completed';
1381
+ if ((choice === null || choice === void 0 ? void 0 : choice.finish_reason) === 'length' || (choice === null || choice === void 0 ? void 0 : choice.finish_reason) === 'max_tokens') {
1382
+ status = 'incomplete';
1383
+ }
1384
+ return {
1385
+ id: response.id || `response_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`,
1386
+ object: 'response',
1387
+ created_at: response.created || Math.floor(Date.now() / 1000),
1388
+ model: response.model,
1389
+ output,
1390
+ status,
1391
+ incomplete_details: status === 'incomplete' ? { reason: 'max_tokens' } : undefined,
1392
+ usage: response.usage ? Object.assign({ input_tokens: response.usage.prompt_tokens, output_tokens: response.usage.completion_tokens, total_tokens: response.usage.total_tokens }, (response.usage.cached_tokens && { input_tokens_details: { cached_tokens: response.usage.cached_tokens } })) : undefined
1393
+ };
1394
+ }
1395
+ function transformResponseFromClaudeToResponses(response) {
1396
+ if (!response || typeof response !== 'object') {
1397
+ return response;
1398
+ }
1399
+ const output = [];
1400
+ // 转换 content blocks
1401
+ if (Array.isArray(response.content)) {
1402
+ const messageContent = [];
1403
+ for (const block of response.content) {
1404
+ if (!block || typeof block !== 'object')
1405
+ continue;
1406
+ if (block.type === 'text' && typeof block.text === 'string') {
1407
+ messageContent.push({
1408
+ type: 'output_text',
1409
+ text: block.text
1410
+ });
1411
+ }
1412
+ if (block.type === 'image' && block.source) {
1413
+ messageContent.push({
1414
+ type: 'image',
1415
+ source: block.source
1416
+ });
1417
+ }
1418
+ if (block.type === 'tool_use') {
1419
+ output.push({
1420
+ type: 'function_call',
1421
+ id: block.id,
1422
+ name: block.name,
1423
+ arguments: JSON.stringify(block.input || {})
1424
+ });
1425
+ }
1426
+ }
1427
+ if (messageContent.length > 0) {
1428
+ output.push({
1429
+ type: 'message',
1430
+ role: 'assistant',
1431
+ content: messageContent
1432
+ });
1433
+ }
1434
+ }
1435
+ // 如果没有内容,添加空消息
1436
+ if (output.length === 0) {
1437
+ output.push({
1438
+ type: 'message',
1439
+ role: 'assistant',
1440
+ content: [{
1441
+ type: 'output_text',
1442
+ text: ''
1443
+ }]
1444
+ });
1445
+ }
1446
+ // 映射 stop_reason 为 status
1447
+ // Claude: "end_turn" | "max_tokens" | "tool_use" | "stop_sequence" | "max_thinking_length"
1448
+ // Responses: "completed" | "incomplete"
1449
+ let status = 'completed';
1450
+ if (response.stop_reason === 'max_tokens' || response.stop_reason === 'max_thinking_length') {
1451
+ status = 'incomplete';
1452
+ }
1453
+ return {
1454
+ id: response.id || `response_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`,
1455
+ object: 'response',
1456
+ created_at: Math.floor(Date.now() / 1000),
1457
+ model: response.model,
1458
+ output,
1459
+ status,
1460
+ incomplete_details: status === 'incomplete' ? { reason: 'max_tokens' } : undefined,
1461
+ usage: response.usage ? {
1462
+ input_tokens: response.usage.input_tokens,
1463
+ output_tokens: response.usage.output_tokens,
1464
+ total_tokens: response.usage.total_tokens
1465
+ } : undefined
1466
+ };
1467
+ }
1468
+ function transformResponseFromGeminiToResponses(response) {
1469
+ var _a;
1470
+ if (!response || typeof response !== 'object') {
1471
+ return response;
1472
+ }
1473
+ const candidate = Array.isArray(response.candidates) && response.candidates.length > 0 ? response.candidates[0] : null;
1474
+ const output = [];
1475
+ // 转换 content parts
1476
+ if ((_a = candidate === null || candidate === void 0 ? void 0 : candidate.content) === null || _a === void 0 ? void 0 : _a.parts) {
1477
+ const messageContent = [];
1478
+ for (const part of candidate.content.parts) {
1479
+ const p = part;
1480
+ if (p.text && typeof p.text === 'string') {
1481
+ messageContent.push({
1482
+ type: 'output_text',
1483
+ text: p.text
1484
+ });
1485
+ }
1486
+ if (p.inlineData) {
1487
+ messageContent.push({
1488
+ type: 'image',
1489
+ source: {
1490
+ type: 'base64',
1491
+ media_type: p.inlineData.mimeType,
1492
+ data: p.inlineData.data
1493
+ }
1494
+ });
1495
+ }
1496
+ if (p.functionCall) {
1497
+ output.push({
1498
+ type: 'function_call',
1499
+ id: `call_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`,
1500
+ name: p.functionCall.name || 'tool',
1501
+ arguments: JSON.stringify(p.functionCall.args || {})
1502
+ });
1503
+ }
1504
+ }
1505
+ if (messageContent.length > 0) {
1506
+ output.push({
1507
+ type: 'message',
1508
+ role: 'assistant',
1509
+ content: messageContent
1510
+ });
1511
+ }
1512
+ }
1513
+ // 如果没有内容,添加空消息
1514
+ if (output.length === 0) {
1515
+ output.push({
1516
+ type: 'message',
1517
+ role: 'assistant',
1518
+ content: [{
1519
+ type: 'output_text',
1520
+ text: ''
1521
+ }]
1522
+ });
1523
+ }
1524
+ // 映射 finishReason 为 status
1525
+ // Gemini: "STOP" | "MAX_TOKENS" | "SAFETY" | "RECITATION" | "OTHER" | "MALFORMED_FUNCTION_CALL"
1526
+ // Responses: "completed" | "incomplete"
1527
+ let status = 'completed';
1528
+ if ((candidate === null || candidate === void 0 ? void 0 : candidate.finishReason) === 'MAX_TOKENS') {
1529
+ status = 'incomplete';
1530
+ }
1531
+ return {
1532
+ id: `response_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`,
1533
+ object: 'response',
1534
+ created_at: Math.floor(Date.now() / 1000),
1535
+ model: response.model || 'gemini',
1536
+ output,
1537
+ status,
1538
+ incomplete_details: status === 'incomplete' ? { reason: 'max_tokens' } : undefined,
1539
+ usage: response.usageMetadata ? {
1540
+ input_tokens: response.usageMetadata.promptTokenCount,
1541
+ output_tokens: response.usageMetadata.candidatesTokenCount,
1542
+ total_tokens: response.usageMetadata.totalTokenCount
1543
+ } : undefined
1544
+ };
1545
+ }
1546
+ // ===================== claude code 得到 claude 数据 =======================
1547
+ function transformResponseFromChatCompletionsToClaude(response) {
1548
+ if (!response || typeof response !== 'object') {
1549
+ return response;
1550
+ }
1551
+ const choice = Array.isArray(response.choices) && response.choices.length > 0 ? response.choices[0] : null;
1552
+ const contentBlocks = [];
1553
+ // 转换消息内容
1554
+ if (choice === null || choice === void 0 ? void 0 : choice.message) {
1555
+ const message = choice.message;
1556
+ if (typeof message.content === 'string') {
1557
+ contentBlocks.push({ type: 'text', text: message.content });
1558
+ }
1559
+ else if (Array.isArray(message.content)) {
1560
+ for (const item of message.content) {
1561
+ if (!item || typeof item !== 'object')
1562
+ continue;
1563
+ if (item.type === 'text' && typeof item.text === 'string') {
1564
+ contentBlocks.push({ type: 'text', text: item.text });
1565
+ }
1566
+ if (item.type === 'image_url' && item.image_url) {
1567
+ const url = item.image_url.url;
1568
+ if (typeof url === 'string') {
1569
+ if (url.startsWith('data:')) {
1570
+ const match = url.match(/^data:([^;]+);base64,(.+)$/);
1571
+ if (match) {
1572
+ contentBlocks.push({
1573
+ type: 'image',
1574
+ source: {
1575
+ type: 'base64',
1576
+ media_type: match[1],
1577
+ data: match[2]
1578
+ }
1579
+ });
1580
+ }
1581
+ }
1582
+ else {
1583
+ contentBlocks.push({
1584
+ type: 'image',
1585
+ source: {
1586
+ type: 'url',
1587
+ url: url
1588
+ }
1589
+ });
1590
+ }
1591
+ }
1592
+ }
1593
+ }
1594
+ }
1595
+ // 处理工具调用
1596
+ if (Array.isArray(message.tool_calls)) {
1597
+ for (const toolCall of message.tool_calls) {
1598
+ if (toolCall && toolCall.type === 'function') {
1599
+ contentBlocks.push({
1600
+ type: 'tool_use',
1601
+ id: toolCall.id,
1602
+ name: toolCall.function.name,
1603
+ input: JSON.parse(toolCall.function.arguments || '{}')
1604
+ });
1605
+ }
1606
+ }
1607
+ }
1608
+ }
1609
+ // 如果没有内容,添加空文本
1610
+ if (contentBlocks.length === 0) {
1611
+ contentBlocks.push({ type: 'text', text: '' });
1612
+ }
1613
+ // 转换 usage
1614
+ const usage = response.usage ? {
1615
+ input_tokens: response.usage.prompt_tokens,
1616
+ output_tokens: response.usage.completion_tokens,
1617
+ total_tokens: response.usage.total_tokens,
1618
+ } : undefined;
1619
+ // 映射 finish reason
1620
+ const stopReasonMap = {
1621
+ 'stop': 'end_turn',
1622
+ 'length': 'max_tokens',
1623
+ 'content_filter': 'content_filter',
1624
+ };
1625
+ return {
1626
+ id: response.id,
1627
+ type: 'message',
1628
+ role: 'assistant',
1629
+ model: response.model,
1630
+ content: contentBlocks,
1631
+ stop_reason: stopReasonMap[choice === null || choice === void 0 ? void 0 : choice.finish_reason] || 'end_turn',
1632
+ stop_sequence: null,
1633
+ usage: usage || {
1634
+ input_tokens: 0,
1635
+ output_tokens: 0,
1636
+ cache_read_input_tokens: 0,
1637
+ },
1638
+ };
1639
+ }
1640
+ function transformResponseFromResponsesToClaude(response) {
1641
+ var _a;
1642
+ if (!response || typeof response !== 'object') {
1643
+ return response;
1644
+ }
1645
+ const contentBlocks = [];
1646
+ // 遍历 output 数组
1647
+ if (Array.isArray(response.output)) {
1648
+ for (const outputItem of response.output) {
1649
+ if (outputItem.type === 'message' && Array.isArray(outputItem.content)) {
1650
+ for (const part of outputItem.content) {
1651
+ if (part.type === 'output_text' && typeof part.text === 'string') {
1652
+ contentBlocks.push({ type: 'text', text: part.text });
1653
+ }
1654
+ if (part.type === 'image' && part.source) {
1655
+ contentBlocks.push({ type: 'image', source: part.source });
1656
+ }
1657
+ }
1658
+ }
1659
+ if (outputItem.type === 'function_call') {
1660
+ contentBlocks.push({
1661
+ type: 'tool_use',
1662
+ id: outputItem.id,
1663
+ name: outputItem.name,
1664
+ input: JSON.parse(outputItem.arguments || '{}')
1665
+ });
1666
+ }
1667
+ }
1668
+ }
1669
+ // 如果没有内容,添加空文本
1670
+ if (contentBlocks.length === 0) {
1671
+ contentBlocks.push({ type: 'text', text: '' });
1672
+ }
1673
+ // 转换 usage
1674
+ const usage = response.usage ? {
1675
+ input_tokens: response.usage.input_tokens,
1676
+ output_tokens: response.usage.output_tokens,
1677
+ total_tokens: response.usage.total_tokens,
1678
+ } : undefined;
1679
+ // 转换 stop_reason
1680
+ let stop_reason = 'end_turn';
1681
+ if (response.status === 'incomplete') {
1682
+ stop_reason = ((_a = response.incomplete_details) === null || _a === void 0 ? void 0 : _a.reason) === 'max_tokens' ? 'max_tokens' : 'end_turn';
1683
+ }
1684
+ return {
1685
+ id: response.id,
1686
+ type: 'message',
1687
+ role: 'assistant',
1688
+ model: response.model,
1689
+ content: contentBlocks,
1690
+ stop_reason,
1691
+ stop_sequence: null,
1692
+ usage: usage || {
1693
+ input_tokens: 0,
1694
+ output_tokens: 0,
1695
+ cache_read_input_tokens: 0,
1696
+ },
1697
+ };
1698
+ }
1699
+ function transformResponseFromGeminiToClaude(response) {
1700
+ var _a;
1701
+ if (!response || typeof response !== 'object') {
1702
+ return response;
1703
+ }
1704
+ const candidate = Array.isArray(response.candidates) && response.candidates.length > 0 ? response.candidates[0] : null;
1705
+ const contentBlocks = [];
1706
+ // 转换 content parts
1707
+ if ((_a = candidate === null || candidate === void 0 ? void 0 : candidate.content) === null || _a === void 0 ? void 0 : _a.parts) {
1708
+ for (const part of candidate.content.parts) {
1709
+ const p = part;
1710
+ if (p.text && typeof p.text === 'string') {
1711
+ contentBlocks.push({ type: 'text', text: p.text });
1712
+ }
1713
+ if (p.inlineData) {
1714
+ contentBlocks.push({
1715
+ type: 'image',
1716
+ source: {
1717
+ type: 'base64',
1718
+ media_type: p.inlineData.mimeType,
1719
+ data: p.inlineData.data
1720
+ }
1721
+ });
1722
+ }
1723
+ if (p.functionCall) {
1724
+ contentBlocks.push({
1725
+ type: 'tool_use',
1726
+ id: `tool_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`,
1727
+ name: p.functionCall.name || 'tool',
1728
+ input: p.functionCall.args || {}
1729
+ });
1730
+ }
1731
+ }
1732
+ }
1733
+ // 如果没有内容,添加空文本
1734
+ if (contentBlocks.length === 0) {
1735
+ contentBlocks.push({ type: 'text', text: '' });
1736
+ }
1737
+ // 转换 usage
1738
+ const usage = response.usageMetadata ? {
1739
+ input_tokens: response.usageMetadata.promptTokenCount,
1740
+ output_tokens: response.usageMetadata.candidatesTokenCount,
1741
+ total_tokens: response.usageMetadata.totalTokenCount,
1742
+ cache_read_input_tokens: response.usageMetadata.cachedContentTokenCount,
1743
+ } : undefined;
1744
+ // 映射 finish reason
1745
+ const stopReasonMap = {
1746
+ 'STOP': 'end_turn',
1747
+ 'MAX_TOKENS': 'max_tokens',
1748
+ 'SAFETY': 'content_filter',
1749
+ 'RECITATION': 'content_filter',
1750
+ };
1751
+ return {
1752
+ id: `msg_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`,
1753
+ type: 'message',
1754
+ role: 'assistant',
1755
+ model: 'gemini',
1756
+ content: contentBlocks,
1757
+ stop_reason: stopReasonMap[candidate === null || candidate === void 0 ? void 0 : candidate.finishReason] || 'end_turn',
1758
+ stop_sequence: null,
1759
+ usage: usage || {
1760
+ input_tokens: 0,
1761
+ output_tokens: 0,
1762
+ cache_read_input_tokens: 0,
1763
+ },
1764
+ };
1765
+ }