@mmmbuto/zai-codex-bridge 0.1.7 → 0.1.9
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/package.json +1 -1
- package/src/server.js +54 -8
package/package.json
CHANGED
package/src/server.js
CHANGED
|
@@ -80,10 +80,24 @@ function translateResponsesToChat(request) {
|
|
|
80
80
|
content: request.input
|
|
81
81
|
});
|
|
82
82
|
} else if (Array.isArray(request.input)) {
|
|
83
|
-
// Array of
|
|
83
|
+
// Array of ResponseItem objects - filter only Message items with role
|
|
84
84
|
for (const item of request.input) {
|
|
85
|
+
// Only process items with a 'role' field (Message items)
|
|
86
|
+
// Skip Reasoning, FunctionCall, LocalShellCall, etc.
|
|
87
|
+
if (!item.role) continue;
|
|
88
|
+
|
|
89
|
+
// Map non-standard roles to Z.AI-compatible roles
|
|
90
|
+
// Z.AI accepts: system, user, assistant
|
|
91
|
+
let role = item.role;
|
|
92
|
+
if (role === 'developer') {
|
|
93
|
+
role = 'user'; // Map developer to user
|
|
94
|
+
} else if (role !== 'system' && role !== 'user' && role !== 'assistant') {
|
|
95
|
+
// Skip any other non-standard roles
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
|
|
85
99
|
const msg = {
|
|
86
|
-
role:
|
|
100
|
+
role: role,
|
|
87
101
|
content: flattenContent(item.content)
|
|
88
102
|
};
|
|
89
103
|
|
|
@@ -127,7 +141,21 @@ function translateResponsesToChat(request) {
|
|
|
127
141
|
}
|
|
128
142
|
|
|
129
143
|
if (request.tools && Array.isArray(request.tools)) {
|
|
130
|
-
|
|
144
|
+
// Filter out tools with null or empty function
|
|
145
|
+
chatRequest.tools = request.tools.filter(tool => {
|
|
146
|
+
if (tool.type === 'function') {
|
|
147
|
+
// Check if function has required fields
|
|
148
|
+
return tool.function && typeof tool.function === 'object' &&
|
|
149
|
+
tool.function.name && tool.function.name.length > 0 &&
|
|
150
|
+
tool.function.parameters !== undefined && tool.function.parameters !== null;
|
|
151
|
+
}
|
|
152
|
+
// Keep non-function tools (if any)
|
|
153
|
+
return true;
|
|
154
|
+
});
|
|
155
|
+
// Only add tools array if there are valid tools
|
|
156
|
+
if (chatRequest.tools.length === 0) {
|
|
157
|
+
delete chatRequest.tools;
|
|
158
|
+
}
|
|
131
159
|
}
|
|
132
160
|
|
|
133
161
|
if (request.tool_choice) {
|
|
@@ -210,7 +238,9 @@ async function makeUpstreamRequest(path, body, headers) {
|
|
|
210
238
|
base: ZAI_BASE_URL,
|
|
211
239
|
hasAuth: !!upstreamHeaders.Authorization,
|
|
212
240
|
bodyKeys: Object.keys(body),
|
|
213
|
-
bodyPreview: JSON.stringify(body).substring(0,
|
|
241
|
+
bodyPreview: JSON.stringify(body).substring(0, 800),
|
|
242
|
+
messagesCount: body.messages?.length || 0,
|
|
243
|
+
allRoles: body.messages?.map(m => m.role) || []
|
|
214
244
|
});
|
|
215
245
|
|
|
216
246
|
const response = await fetch(url, {
|
|
@@ -229,6 +259,8 @@ async function streamChatToResponses(stream, res) {
|
|
|
229
259
|
const decoder = new TextDecoder();
|
|
230
260
|
let buffer = '';
|
|
231
261
|
let chunkCount = 0;
|
|
262
|
+
let deltaCount = 0;
|
|
263
|
+
let lastParsed = null; // Keep track of last parsed SSE for ID extraction
|
|
232
264
|
|
|
233
265
|
log('debug', 'Starting to process stream');
|
|
234
266
|
|
|
@@ -252,14 +284,27 @@ async function streamChatToResponses(stream, res) {
|
|
|
252
284
|
|
|
253
285
|
// Check for stream end
|
|
254
286
|
if (data === '[DONE]') {
|
|
255
|
-
log('
|
|
256
|
-
|
|
257
|
-
|
|
287
|
+
log('info', `Stream end received - wrote ${deltaCount} deltas total`);
|
|
288
|
+
|
|
289
|
+
// Send response.completed event (required by Codex Responses API)
|
|
290
|
+
const completedEvent = {
|
|
291
|
+
id: lastParsed?.id || 'msg_' + Date.now(),
|
|
292
|
+
usage: lastParsed?.usage || {
|
|
293
|
+
input_tokens: 0,
|
|
294
|
+
output_tokens: 0,
|
|
295
|
+
total_tokens: 0
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
res.write(`event: response.completed\n`);
|
|
300
|
+
res.write(`data: ${JSON.stringify(completedEvent)}\n\n`);
|
|
301
|
+
log('info', 'Sent response.completed event');
|
|
258
302
|
return;
|
|
259
303
|
}
|
|
260
304
|
|
|
261
305
|
try {
|
|
262
306
|
const parsed = JSON.parse(data);
|
|
307
|
+
lastParsed = parsed; // Save for later use in completed event
|
|
263
308
|
log('debug', 'Parsed SSE:', JSON.stringify(parsed).substring(0, 150));
|
|
264
309
|
|
|
265
310
|
const delta = parsed.choices?.[0]?.delta;
|
|
@@ -268,6 +313,7 @@ async function streamChatToResponses(stream, res) {
|
|
|
268
313
|
const content = delta?.content || delta?.reasoning_content || '';
|
|
269
314
|
|
|
270
315
|
if (content) {
|
|
316
|
+
deltaCount++;
|
|
271
317
|
log('debug', 'Writing delta:', content.substring(0, 30));
|
|
272
318
|
res.write(`event: output.text.delta\n`);
|
|
273
319
|
res.write(`data: ${JSON.stringify({ value: content })}\n\n`);
|
|
@@ -283,7 +329,7 @@ async function streamChatToResponses(stream, res) {
|
|
|
283
329
|
}
|
|
284
330
|
}
|
|
285
331
|
|
|
286
|
-
log('
|
|
332
|
+
log('info', `Stream ended naturally - wrote ${deltaCount} deltas`);
|
|
287
333
|
}
|
|
288
334
|
|
|
289
335
|
/**
|