aicodeswitch 1.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.
- package/README.md +176 -0
- package/bin/cli.js +29 -0
- package/bin/restart.js +232 -0
- package/bin/start.js +166 -0
- package/bin/stop.js +90 -0
- package/dist/server/auth.js +77 -0
- package/dist/server/database.js +480 -0
- package/dist/server/main.js +382 -0
- package/dist/server/proxy-server.js +889 -0
- package/dist/server/transformers/chunk-collector.js +39 -0
- package/dist/server/transformers/claude-openai.js +231 -0
- package/dist/server/transformers/openai-responses.js +392 -0
- package/dist/server/transformers/streaming.js +888 -0
- package/dist/types/index.js +2 -0
- package/dist/ui/assets/index-BN77E7-U.js +259 -0
- package/dist/ui/assets/index-CaNSVfpD.css +1 -0
- package/dist/ui/index.html +13 -0
- package/package.json +59 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ChunkCollectorTransform = void 0;
|
|
4
|
+
const stream_1 = require("stream");
|
|
5
|
+
/**
|
|
6
|
+
* ChunkCollectorTransform - 收集stream chunks用于日志记录
|
|
7
|
+
* 这个Transform会记录所有经过它的数据块,同时将数据原封不动地传递给下一个stream
|
|
8
|
+
*/
|
|
9
|
+
class ChunkCollectorTransform extends stream_1.Transform {
|
|
10
|
+
constructor() {
|
|
11
|
+
super();
|
|
12
|
+
Object.defineProperty(this, "chunks", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
configurable: true,
|
|
15
|
+
writable: true,
|
|
16
|
+
value: []
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
_transform(chunk, _encoding, callback) {
|
|
20
|
+
// 收集chunk数据
|
|
21
|
+
this.chunks.push(chunk.toString('utf8'));
|
|
22
|
+
// 将chunk传递给下一个stream
|
|
23
|
+
this.push(chunk);
|
|
24
|
+
callback();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 获取收集的所有chunks
|
|
28
|
+
*/
|
|
29
|
+
getChunks() {
|
|
30
|
+
return this.chunks;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 清空已收集的chunks
|
|
34
|
+
*/
|
|
35
|
+
clearChunks() {
|
|
36
|
+
this.chunks = [];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.ChunkCollectorTransform = ChunkCollectorTransform;
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractTokenUsageFromClaudeUsage = exports.extractTokenUsageFromOpenAIUsage = exports.transformOpenAIChatResponseToClaude = exports.transformClaudeRequestToOpenAIChat = exports.mapStopReason = exports.convertOpenAIUsageToClaude = void 0;
|
|
4
|
+
const toTextContent = (content) => {
|
|
5
|
+
if (typeof content === 'string')
|
|
6
|
+
return content;
|
|
7
|
+
if (!Array.isArray(content))
|
|
8
|
+
return null;
|
|
9
|
+
const parts = [];
|
|
10
|
+
for (const item of content) {
|
|
11
|
+
if (item && typeof item === 'object' && item.type === 'text' && typeof item.text === 'string') {
|
|
12
|
+
parts.push(item.text);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return parts.length > 0 ? parts.join('') : null;
|
|
16
|
+
};
|
|
17
|
+
const mapClaudeToolChoiceToOpenAI = (toolChoice) => {
|
|
18
|
+
if (toolChoice === 'auto' || toolChoice === 'none' || toolChoice === 'required') {
|
|
19
|
+
return toolChoice;
|
|
20
|
+
}
|
|
21
|
+
if (toolChoice && typeof toolChoice === 'object' && toolChoice.name) {
|
|
22
|
+
return {
|
|
23
|
+
type: 'function',
|
|
24
|
+
function: { name: toolChoice.name },
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return toolChoice;
|
|
28
|
+
};
|
|
29
|
+
const convertOpenAIUsageToClaude = (usage) => {
|
|
30
|
+
var _a;
|
|
31
|
+
const cached = ((_a = usage === null || usage === void 0 ? void 0 : usage.prompt_tokens_details) === null || _a === void 0 ? void 0 : _a.cached_tokens) || 0;
|
|
32
|
+
return {
|
|
33
|
+
input_tokens: ((usage === null || usage === void 0 ? void 0 : usage.prompt_tokens) || 0) - cached,
|
|
34
|
+
output_tokens: (usage === null || usage === void 0 ? void 0 : usage.completion_tokens) || 0,
|
|
35
|
+
cache_read_input_tokens: cached,
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
exports.convertOpenAIUsageToClaude = convertOpenAIUsageToClaude;
|
|
39
|
+
const mapStopReason = (finishReason) => {
|
|
40
|
+
switch (finishReason) {
|
|
41
|
+
case 'stop':
|
|
42
|
+
return 'end_turn';
|
|
43
|
+
case 'length':
|
|
44
|
+
return 'max_tokens';
|
|
45
|
+
case 'tool_calls':
|
|
46
|
+
return 'tool_use';
|
|
47
|
+
case 'content_filter':
|
|
48
|
+
return 'content_filter';
|
|
49
|
+
default:
|
|
50
|
+
return 'end_turn';
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
exports.mapStopReason = mapStopReason;
|
|
54
|
+
const transformClaudeRequestToOpenAIChat = (body, targetModel) => {
|
|
55
|
+
var _a;
|
|
56
|
+
const messages = [];
|
|
57
|
+
if (body.system) {
|
|
58
|
+
const systemText = toTextContent(body.system);
|
|
59
|
+
if (systemText) {
|
|
60
|
+
messages.push({ role: 'system', content: systemText });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (Array.isArray(body.messages)) {
|
|
64
|
+
for (const message of body.messages) {
|
|
65
|
+
if (typeof message.content === 'string' || message.content === null) {
|
|
66
|
+
messages.push({ role: message.role, content: message.content });
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (Array.isArray(message.content)) {
|
|
70
|
+
const textParts = [];
|
|
71
|
+
const toolCalls = [];
|
|
72
|
+
const toolResultMessages = [];
|
|
73
|
+
for (const block of message.content) {
|
|
74
|
+
if (block && typeof block === 'object') {
|
|
75
|
+
if (block.type === 'text' && typeof block.text === 'string') {
|
|
76
|
+
textParts.push(block.text);
|
|
77
|
+
}
|
|
78
|
+
if (block.type === 'tool_use') {
|
|
79
|
+
const toolId = block.id || `tool_${toolCalls.length + 1}`;
|
|
80
|
+
const toolName = block.name || 'tool';
|
|
81
|
+
const input = (_a = block.input) !== null && _a !== void 0 ? _a : {};
|
|
82
|
+
toolCalls.push({
|
|
83
|
+
id: toolId,
|
|
84
|
+
type: 'function',
|
|
85
|
+
function: {
|
|
86
|
+
name: toolName,
|
|
87
|
+
arguments: JSON.stringify(input),
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
if (block.type === 'tool_result') {
|
|
92
|
+
const toolCallId = block.tool_use_id || block.id;
|
|
93
|
+
const toolContent = block.content;
|
|
94
|
+
toolResultMessages.push({
|
|
95
|
+
role: 'tool',
|
|
96
|
+
tool_call_id: toolCallId,
|
|
97
|
+
content: typeof toolContent === 'string' ? toolContent : JSON.stringify(toolContent !== null && toolContent !== void 0 ? toolContent : {}),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const content = textParts.length > 0 ? textParts.join('') : null;
|
|
103
|
+
const openaiMessage = {
|
|
104
|
+
role: message.role,
|
|
105
|
+
content,
|
|
106
|
+
};
|
|
107
|
+
if (toolCalls.length > 0) {
|
|
108
|
+
openaiMessage.tool_calls = toolCalls;
|
|
109
|
+
}
|
|
110
|
+
messages.push(openaiMessage);
|
|
111
|
+
toolResultMessages.forEach((toolMessage) => messages.push(toolMessage));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const openaiBody = {
|
|
116
|
+
model: targetModel || body.model,
|
|
117
|
+
messages,
|
|
118
|
+
};
|
|
119
|
+
if (typeof body.temperature === 'number')
|
|
120
|
+
openaiBody.temperature = body.temperature;
|
|
121
|
+
if (typeof body.top_p === 'number')
|
|
122
|
+
openaiBody.top_p = body.top_p;
|
|
123
|
+
if (typeof body.max_tokens === 'number')
|
|
124
|
+
openaiBody.max_tokens = body.max_tokens;
|
|
125
|
+
if (Array.isArray(body.stop_sequences))
|
|
126
|
+
openaiBody.stop = body.stop_sequences;
|
|
127
|
+
if (body.tools) {
|
|
128
|
+
openaiBody.tools = body.tools.map((tool) => ({
|
|
129
|
+
type: 'function',
|
|
130
|
+
function: {
|
|
131
|
+
name: tool.name,
|
|
132
|
+
description: tool.description,
|
|
133
|
+
parameters: tool.input_schema,
|
|
134
|
+
},
|
|
135
|
+
}));
|
|
136
|
+
}
|
|
137
|
+
if (body.tool_choice) {
|
|
138
|
+
openaiBody.tool_choice = mapClaudeToolChoiceToOpenAI(body.tool_choice);
|
|
139
|
+
}
|
|
140
|
+
if (body.stream === true) {
|
|
141
|
+
openaiBody.stream = true;
|
|
142
|
+
openaiBody.stream_options = { include_usage: true };
|
|
143
|
+
}
|
|
144
|
+
return openaiBody;
|
|
145
|
+
};
|
|
146
|
+
exports.transformClaudeRequestToOpenAIChat = transformClaudeRequestToOpenAIChat;
|
|
147
|
+
const extractOpenAIText = (content) => {
|
|
148
|
+
if (typeof content === 'string')
|
|
149
|
+
return content;
|
|
150
|
+
if (!Array.isArray(content))
|
|
151
|
+
return null;
|
|
152
|
+
const parts = [];
|
|
153
|
+
for (const item of content) {
|
|
154
|
+
if (item && typeof item === 'object' && typeof item.text === 'string') {
|
|
155
|
+
parts.push(item.text);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return parts.length > 0 ? parts.join('') : null;
|
|
159
|
+
};
|
|
160
|
+
const transformOpenAIChatResponseToClaude = (body) => {
|
|
161
|
+
var _a, _b;
|
|
162
|
+
const choice = Array.isArray(body === null || body === void 0 ? void 0 : body.choices) ? body.choices[0] : null;
|
|
163
|
+
const message = (choice === null || choice === void 0 ? void 0 : choice.message) || {};
|
|
164
|
+
const contentBlocks = [];
|
|
165
|
+
const contentText = extractOpenAIText(message.content);
|
|
166
|
+
if (contentText) {
|
|
167
|
+
contentBlocks.push({ type: 'text', text: contentText });
|
|
168
|
+
}
|
|
169
|
+
if (Array.isArray(message.tool_calls)) {
|
|
170
|
+
for (const toolCall of message.tool_calls) {
|
|
171
|
+
const toolName = ((_a = toolCall === null || toolCall === void 0 ? void 0 : toolCall.function) === null || _a === void 0 ? void 0 : _a.name) || 'tool';
|
|
172
|
+
let input = {};
|
|
173
|
+
if ((_b = toolCall === null || toolCall === void 0 ? void 0 : toolCall.function) === null || _b === void 0 ? void 0 : _b.arguments) {
|
|
174
|
+
try {
|
|
175
|
+
input = JSON.parse(toolCall.function.arguments);
|
|
176
|
+
}
|
|
177
|
+
catch (_c) {
|
|
178
|
+
input = toolCall.function.arguments;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
contentBlocks.push({
|
|
182
|
+
type: 'tool_use',
|
|
183
|
+
id: toolCall.id,
|
|
184
|
+
name: toolName,
|
|
185
|
+
input,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const usage = (body === null || body === void 0 ? void 0 : body.usage) ? (0, exports.convertOpenAIUsageToClaude)(body.usage) : null;
|
|
190
|
+
return {
|
|
191
|
+
id: body === null || body === void 0 ? void 0 : body.id,
|
|
192
|
+
type: 'message',
|
|
193
|
+
role: 'assistant',
|
|
194
|
+
model: body === null || body === void 0 ? void 0 : body.model,
|
|
195
|
+
content: contentBlocks,
|
|
196
|
+
stop_reason: (0, exports.mapStopReason)(choice === null || choice === void 0 ? void 0 : choice.finish_reason),
|
|
197
|
+
stop_sequence: null,
|
|
198
|
+
usage: usage || {
|
|
199
|
+
input_tokens: 0,
|
|
200
|
+
output_tokens: 0,
|
|
201
|
+
cache_read_input_tokens: 0,
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
};
|
|
205
|
+
exports.transformOpenAIChatResponseToClaude = transformOpenAIChatResponseToClaude;
|
|
206
|
+
const extractTokenUsageFromOpenAIUsage = (usage) => {
|
|
207
|
+
if (!usage)
|
|
208
|
+
return undefined;
|
|
209
|
+
const converted = (0, exports.convertOpenAIUsageToClaude)(usage);
|
|
210
|
+
return {
|
|
211
|
+
inputTokens: converted.input_tokens,
|
|
212
|
+
outputTokens: converted.output_tokens,
|
|
213
|
+
totalTokens: usage.total_tokens,
|
|
214
|
+
cacheReadInputTokens: converted.cache_read_input_tokens,
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
exports.extractTokenUsageFromOpenAIUsage = extractTokenUsageFromOpenAIUsage;
|
|
218
|
+
const extractTokenUsageFromClaudeUsage = (usage) => {
|
|
219
|
+
var _a, _b;
|
|
220
|
+
if (!usage)
|
|
221
|
+
return undefined;
|
|
222
|
+
return {
|
|
223
|
+
inputTokens: (_a = usage.input_tokens) !== null && _a !== void 0 ? _a : 0,
|
|
224
|
+
outputTokens: (_b = usage.output_tokens) !== null && _b !== void 0 ? _b : 0,
|
|
225
|
+
totalTokens: usage.input_tokens !== undefined && usage.output_tokens !== undefined
|
|
226
|
+
? usage.input_tokens + usage.output_tokens
|
|
227
|
+
: undefined,
|
|
228
|
+
cacheReadInputTokens: usage.cache_read_input_tokens,
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
exports.extractTokenUsageFromClaudeUsage = extractTokenUsageFromClaudeUsage;
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractTokenUsageFromOpenAIResponsesUsage = exports.transformClaudeResponseToOpenAIResponses = exports.transformOpenAIResponsesToClaude = exports.transformClaudeRequestToOpenAIResponses = exports.transformOpenAIResponsesRequestToOpenAIChat = exports.transformOpenAIResponsesRequestToClaude = void 0;
|
|
4
|
+
const decodeDataUrl = (dataUrl) => {
|
|
5
|
+
const match = dataUrl.match(/^data:(.*?);base64,(.*)$/);
|
|
6
|
+
if (!match)
|
|
7
|
+
return null;
|
|
8
|
+
return { mediaType: match[1], data: match[2] };
|
|
9
|
+
};
|
|
10
|
+
const buildClaudeContentFromOpenAIContent = (content) => {
|
|
11
|
+
var _a;
|
|
12
|
+
if (typeof content === 'string') {
|
|
13
|
+
return content;
|
|
14
|
+
}
|
|
15
|
+
if (!Array.isArray(content))
|
|
16
|
+
return null;
|
|
17
|
+
const blocks = [];
|
|
18
|
+
for (const item of content) {
|
|
19
|
+
const itemType = item === null || item === void 0 ? void 0 : item.type;
|
|
20
|
+
if (itemType === 'input_text' || itemType === 'output_text' || itemType === 'text') {
|
|
21
|
+
if (typeof item.text === 'string') {
|
|
22
|
+
blocks.push({ type: 'text', text: item.text });
|
|
23
|
+
}
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (itemType === 'input_image' || itemType === 'image_url' || itemType === 'image') {
|
|
27
|
+
const url = typeof item.image_url === 'string' ? item.image_url : (_a = item.image_url) === null || _a === void 0 ? void 0 : _a.url;
|
|
28
|
+
if (url && url.startsWith('data:')) {
|
|
29
|
+
const decoded = decodeDataUrl(url);
|
|
30
|
+
if (decoded) {
|
|
31
|
+
blocks.push({
|
|
32
|
+
type: 'image',
|
|
33
|
+
source: { type: 'base64', media_type: decoded.mediaType, data: decoded.data },
|
|
34
|
+
});
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (url) {
|
|
39
|
+
blocks.push({ type: 'image', source: { type: 'url', url } });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (blocks.length === 0)
|
|
44
|
+
return null;
|
|
45
|
+
return blocks;
|
|
46
|
+
};
|
|
47
|
+
const extractTextFromOpenAIContent = (content) => {
|
|
48
|
+
if (typeof content === 'string')
|
|
49
|
+
return content;
|
|
50
|
+
if (!Array.isArray(content))
|
|
51
|
+
return '';
|
|
52
|
+
const parts = [];
|
|
53
|
+
for (const item of content) {
|
|
54
|
+
if (((item === null || item === void 0 ? void 0 : item.type) === 'input_text' || (item === null || item === void 0 ? void 0 : item.type) === 'output_text' || (item === null || item === void 0 ? void 0 : item.type) === 'text') && typeof item.text === 'string') {
|
|
55
|
+
parts.push(item.text);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return parts.join('');
|
|
59
|
+
};
|
|
60
|
+
const normalizeOpenAIInputMessages = (input) => {
|
|
61
|
+
if (!input)
|
|
62
|
+
return [];
|
|
63
|
+
if (typeof input === 'string') {
|
|
64
|
+
return [{ role: 'user', content: input }];
|
|
65
|
+
}
|
|
66
|
+
if (Array.isArray(input)) {
|
|
67
|
+
return input;
|
|
68
|
+
}
|
|
69
|
+
if (typeof input === 'object' && input.role) {
|
|
70
|
+
return [input];
|
|
71
|
+
}
|
|
72
|
+
return [];
|
|
73
|
+
};
|
|
74
|
+
const mapOpenAIToolChoiceToClaude = (toolChoice) => {
|
|
75
|
+
var _a;
|
|
76
|
+
if (toolChoice === 'auto' || toolChoice === 'none' || toolChoice === 'required') {
|
|
77
|
+
return toolChoice;
|
|
78
|
+
}
|
|
79
|
+
if (toolChoice && typeof toolChoice === 'object') {
|
|
80
|
+
const functionName = ((_a = toolChoice.function) === null || _a === void 0 ? void 0 : _a.name) || toolChoice.name;
|
|
81
|
+
if (functionName) {
|
|
82
|
+
return { type: 'tool', name: functionName };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return toolChoice;
|
|
86
|
+
};
|
|
87
|
+
const mapClaudeToolChoiceToOpenAI = (toolChoice) => {
|
|
88
|
+
if (toolChoice === 'auto' || toolChoice === 'none' || toolChoice === 'required') {
|
|
89
|
+
return toolChoice;
|
|
90
|
+
}
|
|
91
|
+
if (toolChoice && typeof toolChoice === 'object') {
|
|
92
|
+
const name = toolChoice.name;
|
|
93
|
+
if (name) {
|
|
94
|
+
return { type: 'function', function: { name } };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return toolChoice;
|
|
98
|
+
};
|
|
99
|
+
const mapClaudeContentToOpenAIInput = (content) => {
|
|
100
|
+
if (typeof content === 'string' || content === null) {
|
|
101
|
+
return content;
|
|
102
|
+
}
|
|
103
|
+
if (!Array.isArray(content))
|
|
104
|
+
return null;
|
|
105
|
+
const parts = [];
|
|
106
|
+
const textParts = [];
|
|
107
|
+
for (const block of content) {
|
|
108
|
+
if (!block || typeof block !== 'object')
|
|
109
|
+
continue;
|
|
110
|
+
if (block.type === 'text' && typeof block.text === 'string') {
|
|
111
|
+
textParts.push(block.text);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (block.type === 'image' && block.source) {
|
|
115
|
+
const source = block.source;
|
|
116
|
+
if (source.type === 'url' && source.url) {
|
|
117
|
+
parts.push({ type: 'input_image', image_url: source.url });
|
|
118
|
+
}
|
|
119
|
+
if (source.type === 'base64' && source.data) {
|
|
120
|
+
const mediaType = source.media_type || 'application/octet-stream';
|
|
121
|
+
parts.push({ type: 'input_image', image_url: `data:${mediaType};base64,${source.data}` });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (block.type === 'tool_result') {
|
|
125
|
+
const toolContent = block.content;
|
|
126
|
+
if (toolContent !== undefined) {
|
|
127
|
+
textParts.push(typeof toolContent === 'string' ? toolContent : JSON.stringify(toolContent));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (parts.length === 0) {
|
|
132
|
+
return textParts.join('') || null;
|
|
133
|
+
}
|
|
134
|
+
if (textParts.length > 0) {
|
|
135
|
+
parts.unshift({ type: 'input_text', text: textParts.join('') });
|
|
136
|
+
}
|
|
137
|
+
return parts;
|
|
138
|
+
};
|
|
139
|
+
const extractTextFromClaudeContent = (content) => {
|
|
140
|
+
if (typeof content === 'string')
|
|
141
|
+
return content;
|
|
142
|
+
if (!Array.isArray(content))
|
|
143
|
+
return undefined;
|
|
144
|
+
const parts = [];
|
|
145
|
+
for (const block of content) {
|
|
146
|
+
if (block && typeof block === 'object' && block.type === 'text' && typeof block.text === 'string') {
|
|
147
|
+
parts.push(block.text);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return parts.join('');
|
|
151
|
+
};
|
|
152
|
+
const transformOpenAIResponsesRequestToClaude = (body, targetModel) => {
|
|
153
|
+
var _a;
|
|
154
|
+
const inputMessages = normalizeOpenAIInputMessages(body === null || body === void 0 ? void 0 : body.input);
|
|
155
|
+
const messages = inputMessages.map((message) => {
|
|
156
|
+
var _a;
|
|
157
|
+
const role = message.role === 'assistant'
|
|
158
|
+
? 'assistant'
|
|
159
|
+
: message.role === 'system' || message.role === 'developer'
|
|
160
|
+
? 'system'
|
|
161
|
+
: message.role === 'tool'
|
|
162
|
+
? 'tool'
|
|
163
|
+
: 'user';
|
|
164
|
+
const contentBlocks = buildClaudeContentFromOpenAIContent(message.content);
|
|
165
|
+
return {
|
|
166
|
+
role,
|
|
167
|
+
content: (_a = contentBlocks !== null && contentBlocks !== void 0 ? contentBlocks : extractTextFromOpenAIContent(message.content)) !== null && _a !== void 0 ? _a : null,
|
|
168
|
+
};
|
|
169
|
+
});
|
|
170
|
+
const tools = Array.isArray(body === null || body === void 0 ? void 0 : body.tools)
|
|
171
|
+
? body.tools
|
|
172
|
+
.map((tool) => (tool === null || tool === void 0 ? void 0 : tool.function) ? ({
|
|
173
|
+
name: tool.function.name,
|
|
174
|
+
description: tool.function.description,
|
|
175
|
+
input_schema: tool.function.parameters,
|
|
176
|
+
}) : null)
|
|
177
|
+
.filter(Boolean)
|
|
178
|
+
: undefined;
|
|
179
|
+
return {
|
|
180
|
+
model: targetModel || (body === null || body === void 0 ? void 0 : body.model),
|
|
181
|
+
messages,
|
|
182
|
+
system: body === null || body === void 0 ? void 0 : body.instructions,
|
|
183
|
+
max_tokens: (_a = body === null || body === void 0 ? void 0 : body.max_output_tokens) !== null && _a !== void 0 ? _a : body === null || body === void 0 ? void 0 : body.max_tokens,
|
|
184
|
+
temperature: body === null || body === void 0 ? void 0 : body.temperature,
|
|
185
|
+
top_p: body === null || body === void 0 ? void 0 : body.top_p,
|
|
186
|
+
stream: body === null || body === void 0 ? void 0 : body.stream,
|
|
187
|
+
tools,
|
|
188
|
+
tool_choice: (body === null || body === void 0 ? void 0 : body.tool_choice) ? mapOpenAIToolChoiceToClaude(body.tool_choice) : undefined,
|
|
189
|
+
stop_sequences: body === null || body === void 0 ? void 0 : body.stop,
|
|
190
|
+
};
|
|
191
|
+
};
|
|
192
|
+
exports.transformOpenAIResponsesRequestToClaude = transformOpenAIResponsesRequestToClaude;
|
|
193
|
+
const transformOpenAIResponsesRequestToOpenAIChat = (body, targetModel) => {
|
|
194
|
+
const inputMessages = normalizeOpenAIInputMessages(body === null || body === void 0 ? void 0 : body.input);
|
|
195
|
+
const messages = inputMessages.map((message) => ({
|
|
196
|
+
role: message.role || 'user',
|
|
197
|
+
content: extractTextFromOpenAIContent(message.content),
|
|
198
|
+
}));
|
|
199
|
+
if (typeof (body === null || body === void 0 ? void 0 : body.instructions) === 'string' && body.instructions.trim().length > 0) {
|
|
200
|
+
messages.unshift({ role: 'system', content: body.instructions });
|
|
201
|
+
}
|
|
202
|
+
const openaiBody = {
|
|
203
|
+
model: targetModel || (body === null || body === void 0 ? void 0 : body.model),
|
|
204
|
+
messages,
|
|
205
|
+
};
|
|
206
|
+
if (typeof (body === null || body === void 0 ? void 0 : body.temperature) === 'number')
|
|
207
|
+
openaiBody.temperature = body.temperature;
|
|
208
|
+
if (typeof (body === null || body === void 0 ? void 0 : body.top_p) === 'number')
|
|
209
|
+
openaiBody.top_p = body.top_p;
|
|
210
|
+
if (typeof (body === null || body === void 0 ? void 0 : body.max_output_tokens) === 'number')
|
|
211
|
+
openaiBody.max_tokens = body.max_output_tokens;
|
|
212
|
+
if (typeof (body === null || body === void 0 ? void 0 : body.max_tokens) === 'number' && openaiBody.max_tokens === undefined)
|
|
213
|
+
openaiBody.max_tokens = body.max_tokens;
|
|
214
|
+
if (Array.isArray(body === null || body === void 0 ? void 0 : body.stop))
|
|
215
|
+
openaiBody.stop = body.stop;
|
|
216
|
+
if (body === null || body === void 0 ? void 0 : body.tools) {
|
|
217
|
+
openaiBody.tools = body.tools;
|
|
218
|
+
}
|
|
219
|
+
if (body === null || body === void 0 ? void 0 : body.tool_choice) {
|
|
220
|
+
openaiBody.tool_choice = body.tool_choice;
|
|
221
|
+
}
|
|
222
|
+
if ((body === null || body === void 0 ? void 0 : body.stream) === true) {
|
|
223
|
+
openaiBody.stream = true;
|
|
224
|
+
openaiBody.stream_options = { include_usage: true };
|
|
225
|
+
}
|
|
226
|
+
return openaiBody;
|
|
227
|
+
};
|
|
228
|
+
exports.transformOpenAIResponsesRequestToOpenAIChat = transformOpenAIResponsesRequestToOpenAIChat;
|
|
229
|
+
const transformClaudeRequestToOpenAIResponses = (body, targetModel) => {
|
|
230
|
+
const messages = Array.isArray(body.messages) ? body.messages : [];
|
|
231
|
+
const input = messages.map((message) => ({
|
|
232
|
+
role: message.role,
|
|
233
|
+
content: mapClaudeContentToOpenAIInput(message.content),
|
|
234
|
+
}));
|
|
235
|
+
const tools = Array.isArray(body.tools)
|
|
236
|
+
? body.tools.map((tool) => ({
|
|
237
|
+
type: 'function',
|
|
238
|
+
function: {
|
|
239
|
+
name: tool.name,
|
|
240
|
+
description: tool.description,
|
|
241
|
+
parameters: tool.input_schema,
|
|
242
|
+
},
|
|
243
|
+
}))
|
|
244
|
+
: undefined;
|
|
245
|
+
const openaiBody = {
|
|
246
|
+
model: targetModel || body.model,
|
|
247
|
+
input,
|
|
248
|
+
instructions: extractTextFromClaudeContent(body.system),
|
|
249
|
+
stream: body.stream,
|
|
250
|
+
tools,
|
|
251
|
+
tool_choice: body.tool_choice ? mapClaudeToolChoiceToOpenAI(body.tool_choice) : undefined,
|
|
252
|
+
temperature: body.temperature,
|
|
253
|
+
top_p: body.top_p,
|
|
254
|
+
max_output_tokens: body.max_tokens,
|
|
255
|
+
};
|
|
256
|
+
if (Array.isArray(body.stop_sequences)) {
|
|
257
|
+
openaiBody.stop = body.stop_sequences;
|
|
258
|
+
}
|
|
259
|
+
return openaiBody;
|
|
260
|
+
};
|
|
261
|
+
exports.transformClaudeRequestToOpenAIResponses = transformClaudeRequestToOpenAIResponses;
|
|
262
|
+
const extractOutputItems = (body) => {
|
|
263
|
+
var _a, _b;
|
|
264
|
+
const outputItems = Array.isArray(body === null || body === void 0 ? void 0 : body.output) ? body.output : [];
|
|
265
|
+
const contentBlocks = [];
|
|
266
|
+
for (const item of outputItems) {
|
|
267
|
+
if (!item || typeof item !== 'object')
|
|
268
|
+
continue;
|
|
269
|
+
if (item.type === 'message') {
|
|
270
|
+
const content = Array.isArray(item.content) ? item.content : [];
|
|
271
|
+
for (const part of content) {
|
|
272
|
+
if ((part === null || part === void 0 ? void 0 : part.type) === 'output_text' && typeof part.text === 'string') {
|
|
273
|
+
contentBlocks.push({ type: 'text', text: part.text });
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (item.type === 'output_text' && typeof item.text === 'string') {
|
|
278
|
+
contentBlocks.push({ type: 'text', text: item.text });
|
|
279
|
+
}
|
|
280
|
+
if (item.type === 'tool_call' || item.type === 'function_call' || (item === null || item === void 0 ? void 0 : item.name)) {
|
|
281
|
+
let parsedArgs = (_a = item.arguments) !== null && _a !== void 0 ? _a : item.input;
|
|
282
|
+
if (typeof parsedArgs === 'string') {
|
|
283
|
+
try {
|
|
284
|
+
parsedArgs = JSON.parse(parsedArgs);
|
|
285
|
+
}
|
|
286
|
+
catch (_c) {
|
|
287
|
+
// keep string
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
contentBlocks.push({
|
|
291
|
+
type: 'tool_use',
|
|
292
|
+
id: item.id || item.tool_call_id,
|
|
293
|
+
name: item.name || ((_b = item.function) === null || _b === void 0 ? void 0 : _b.name) || 'tool',
|
|
294
|
+
input: parsedArgs,
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return contentBlocks;
|
|
299
|
+
};
|
|
300
|
+
const transformOpenAIResponsesToClaude = (body) => {
|
|
301
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
302
|
+
const responseBody = (_a = body === null || body === void 0 ? void 0 : body.response) !== null && _a !== void 0 ? _a : body;
|
|
303
|
+
const contentBlocks = extractOutputItems(responseBody);
|
|
304
|
+
const usage = responseBody === null || responseBody === void 0 ? void 0 : responseBody.usage;
|
|
305
|
+
const inputTokens = (_c = (_b = usage === null || usage === void 0 ? void 0 : usage.input_tokens) !== null && _b !== void 0 ? _b : usage === null || usage === void 0 ? void 0 : usage.prompt_tokens) !== null && _c !== void 0 ? _c : 0;
|
|
306
|
+
const outputTokens = (_e = (_d = usage === null || usage === void 0 ? void 0 : usage.output_tokens) !== null && _d !== void 0 ? _d : usage === null || usage === void 0 ? void 0 : usage.completion_tokens) !== null && _e !== void 0 ? _e : 0;
|
|
307
|
+
const cacheRead = (_h = (_f = usage === null || usage === void 0 ? void 0 : usage.cache_read_input_tokens) !== null && _f !== void 0 ? _f : (_g = usage === null || usage === void 0 ? void 0 : usage.prompt_tokens_details) === null || _g === void 0 ? void 0 : _g.cached_tokens) !== null && _h !== void 0 ? _h : 0;
|
|
308
|
+
return {
|
|
309
|
+
id: responseBody === null || responseBody === void 0 ? void 0 : responseBody.id,
|
|
310
|
+
type: 'message',
|
|
311
|
+
role: 'assistant',
|
|
312
|
+
model: responseBody === null || responseBody === void 0 ? void 0 : responseBody.model,
|
|
313
|
+
content: contentBlocks,
|
|
314
|
+
stop_reason: 'end_turn',
|
|
315
|
+
stop_sequence: null,
|
|
316
|
+
usage: {
|
|
317
|
+
input_tokens: inputTokens,
|
|
318
|
+
output_tokens: outputTokens,
|
|
319
|
+
cache_read_input_tokens: cacheRead,
|
|
320
|
+
},
|
|
321
|
+
};
|
|
322
|
+
};
|
|
323
|
+
exports.transformOpenAIResponsesToClaude = transformOpenAIResponsesToClaude;
|
|
324
|
+
const transformClaudeResponseToOpenAIResponses = (body) => {
|
|
325
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
326
|
+
const contentBlocks = Array.isArray(body === null || body === void 0 ? void 0 : body.content) ? body.content : [];
|
|
327
|
+
const outputTextParts = [];
|
|
328
|
+
const toolCalls = [];
|
|
329
|
+
for (const block of contentBlocks) {
|
|
330
|
+
if (!block || typeof block !== 'object')
|
|
331
|
+
continue;
|
|
332
|
+
if (block.type === 'text' && typeof block.text === 'string') {
|
|
333
|
+
outputTextParts.push(block.text);
|
|
334
|
+
}
|
|
335
|
+
if (block.type === 'tool_use') {
|
|
336
|
+
const args = (_a = block.input) !== null && _a !== void 0 ? _a : {};
|
|
337
|
+
toolCalls.push({
|
|
338
|
+
id: block.id || `tool_${toolCalls.length + 1}`,
|
|
339
|
+
name: block.name || 'tool',
|
|
340
|
+
arguments: typeof args === 'string' ? args : JSON.stringify(args),
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
const outputText = outputTextParts.join('');
|
|
345
|
+
const outputItems = [];
|
|
346
|
+
if (outputText) {
|
|
347
|
+
outputItems.push({
|
|
348
|
+
type: 'message',
|
|
349
|
+
role: 'assistant',
|
|
350
|
+
content: [{ type: 'output_text', text: outputText }],
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
for (const toolCall of toolCalls) {
|
|
354
|
+
outputItems.push({
|
|
355
|
+
type: 'tool_call',
|
|
356
|
+
id: toolCall.id,
|
|
357
|
+
name: toolCall.name,
|
|
358
|
+
arguments: toolCall.arguments,
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
const inputTokens = (_c = (_b = body === null || body === void 0 ? void 0 : body.usage) === null || _b === void 0 ? void 0 : _b.input_tokens) !== null && _c !== void 0 ? _c : 0;
|
|
362
|
+
const cacheRead = (_e = (_d = body === null || body === void 0 ? void 0 : body.usage) === null || _d === void 0 ? void 0 : _d.cache_read_input_tokens) !== null && _e !== void 0 ? _e : 0;
|
|
363
|
+
const outputTokens = (_g = (_f = body === null || body === void 0 ? void 0 : body.usage) === null || _f === void 0 ? void 0 : _f.output_tokens) !== null && _g !== void 0 ? _g : 0;
|
|
364
|
+
const usage = {
|
|
365
|
+
input_tokens: inputTokens + cacheRead,
|
|
366
|
+
output_tokens: outputTokens,
|
|
367
|
+
total_tokens: inputTokens + cacheRead + outputTokens,
|
|
368
|
+
};
|
|
369
|
+
return {
|
|
370
|
+
id: body === null || body === void 0 ? void 0 : body.id,
|
|
371
|
+
object: 'response',
|
|
372
|
+
model: body === null || body === void 0 ? void 0 : body.model,
|
|
373
|
+
output: outputItems,
|
|
374
|
+
output_text: outputText,
|
|
375
|
+
status: 'completed',
|
|
376
|
+
usage,
|
|
377
|
+
};
|
|
378
|
+
};
|
|
379
|
+
exports.transformClaudeResponseToOpenAIResponses = transformClaudeResponseToOpenAIResponses;
|
|
380
|
+
const extractTokenUsageFromOpenAIResponsesUsage = (usage) => {
|
|
381
|
+
var _a, _b, _c, _d, _e;
|
|
382
|
+
if (!usage)
|
|
383
|
+
return undefined;
|
|
384
|
+
const inputTokens = (_b = (_a = usage.input_tokens) !== null && _a !== void 0 ? _a : usage.prompt_tokens) !== null && _b !== void 0 ? _b : 0;
|
|
385
|
+
const outputTokens = (_d = (_c = usage.output_tokens) !== null && _c !== void 0 ? _c : usage.completion_tokens) !== null && _d !== void 0 ? _d : 0;
|
|
386
|
+
return {
|
|
387
|
+
inputTokens,
|
|
388
|
+
outputTokens,
|
|
389
|
+
totalTokens: (_e = usage.total_tokens) !== null && _e !== void 0 ? _e : inputTokens + outputTokens,
|
|
390
|
+
};
|
|
391
|
+
};
|
|
392
|
+
exports.extractTokenUsageFromOpenAIResponsesUsage = extractTokenUsageFromOpenAIResponsesUsage;
|