@mmmbuto/zai-codex-bridge 0.3.0 → 0.3.1
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 +108 -92
package/package.json
CHANGED
package/src/server.js
CHANGED
|
@@ -458,105 +458,121 @@ async function streamChatToResponses(stream, res, responseId, messageItemId) {
|
|
|
458
458
|
for await (const chunk of stream) {
|
|
459
459
|
buffer += chunk.toString('utf8');
|
|
460
460
|
|
|
461
|
-
// Z.ai stream: SSE lines "data: {...}\n
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
let json;
|
|
474
|
-
try { json = JSON.parse(payload); } catch { continue; }
|
|
475
|
-
|
|
476
|
-
const choice = json?.choices?.[0];
|
|
477
|
-
const delta = choice?.delta ?? {};
|
|
478
|
-
|
|
479
|
-
// 1) reasoning
|
|
480
|
-
if (typeof delta.reasoning_content === 'string' && delta.reasoning_content.length) {
|
|
481
|
-
reasoningText += delta.reasoning_content;
|
|
482
|
-
send({
|
|
483
|
-
type: 'response.reasoning_text.delta',
|
|
484
|
-
sequence_number: seq++,
|
|
485
|
-
item_id: messageItemId,
|
|
486
|
-
output_index: 0,
|
|
487
|
-
content_index: 0,
|
|
488
|
-
delta: delta.reasoning_content,
|
|
489
|
-
});
|
|
490
|
-
log('debug', `Reasoning delta: ${delta.reasoning_content.substring(0, 30)}...`);
|
|
461
|
+
// Z.ai stream: SSE lines "data: {...}\n"
|
|
462
|
+
// Split by newline and process each complete line
|
|
463
|
+
const lines = buffer.split('\n');
|
|
464
|
+
// Keep the last line if it's incomplete (doesn't end with data pattern)
|
|
465
|
+
buffer = lines.pop() || '';
|
|
466
|
+
|
|
467
|
+
for (const line of lines) {
|
|
468
|
+
if (!line.trim() || !line.startsWith('data:')) {
|
|
469
|
+
// Skip empty lines and comments (starting with :)
|
|
470
|
+
if (line.trim() && !line.startsWith(':')) {
|
|
471
|
+
log('debug', 'Non-data line:', line.substring(0, 50));
|
|
491
472
|
}
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
492
475
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
476
|
+
const payload = line.slice(5).trim();
|
|
477
|
+
if (payload === '[DONE]') {
|
|
478
|
+
log('info', 'Stream received [DONE]');
|
|
479
|
+
await finalizeAndClose();
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (!payload) continue;
|
|
484
|
+
|
|
485
|
+
let json;
|
|
486
|
+
try {
|
|
487
|
+
json = JSON.parse(payload);
|
|
488
|
+
} catch (e) {
|
|
489
|
+
log('warn', 'Failed to parse SSE payload:', e.message, 'payload:', payload.substring(0, 100));
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
506
492
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
493
|
+
const choice = json?.choices?.[0];
|
|
494
|
+
const delta = choice?.delta ?? {};
|
|
495
|
+
|
|
496
|
+
// 1) reasoning
|
|
497
|
+
if (typeof delta.reasoning_content === 'string' && delta.reasoning_content.length) {
|
|
498
|
+
reasoningText += delta.reasoning_content;
|
|
499
|
+
send({
|
|
500
|
+
type: 'response.reasoning_text.delta',
|
|
501
|
+
sequence_number: seq++,
|
|
502
|
+
item_id: messageItemId,
|
|
503
|
+
output_index: 0,
|
|
504
|
+
content_index: 0,
|
|
505
|
+
delta: delta.reasoning_content,
|
|
506
|
+
});
|
|
507
|
+
log('debug', `Reasoning delta: ${delta.reasoning_content.substring(0, 30)}...`);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// 2) normal output
|
|
511
|
+
if (typeof delta.content === 'string' && delta.content.length) {
|
|
512
|
+
outputText += delta.content;
|
|
513
|
+
send({
|
|
514
|
+
type: 'response.output_text.delta',
|
|
515
|
+
sequence_number: seq++,
|
|
516
|
+
item_id: messageItemId,
|
|
517
|
+
output_index: 0,
|
|
518
|
+
content_index: reasoningText ? 1 : 0,
|
|
519
|
+
delta: delta.content,
|
|
520
|
+
});
|
|
521
|
+
log('debug', `Output delta: ${delta.content.substring(0, 30)}...`);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// 3) tool calls (OpenAI-style in chat.completions delta.tool_calls)
|
|
525
|
+
if (Array.isArray(delta.tool_calls)) {
|
|
526
|
+
for (const tc of delta.tool_calls) {
|
|
527
|
+
// tc: {id, type:"function", function:{name, arguments}}
|
|
528
|
+
const callId = tc.id || `call_${tc.index ?? 0}`;
|
|
529
|
+
const name = tc.function?.name || 'unknown';
|
|
530
|
+
const argsDelta = tc.function?.arguments || '';
|
|
531
|
+
|
|
532
|
+
let st = toolCalls.get(callId);
|
|
533
|
+
if (!st) {
|
|
534
|
+
st = {
|
|
535
|
+
itemId: `fc_${crypto.randomUUID().replace(/-/g, '')}`,
|
|
536
|
+
outputIndex: nextOutputIndex++,
|
|
537
|
+
name,
|
|
538
|
+
args: '',
|
|
539
|
+
};
|
|
540
|
+
toolCalls.set(callId, st);
|
|
541
|
+
|
|
542
|
+
send({
|
|
543
|
+
type: 'response.output_item.added',
|
|
544
|
+
sequence_number: seq++,
|
|
545
|
+
output_index: st.outputIndex,
|
|
546
|
+
item: {
|
|
547
|
+
type: 'function_call',
|
|
548
|
+
id: st.itemId,
|
|
549
|
+
call_id: callId,
|
|
550
|
+
name: st.name,
|
|
551
|
+
arguments: '',
|
|
552
|
+
},
|
|
553
|
+
});
|
|
554
|
+
log('debug', `Tool call added: ${name} (${callId})`);
|
|
550
555
|
}
|
|
551
|
-
}
|
|
552
556
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
557
|
+
if (argsDelta) {
|
|
558
|
+
st.args += argsDelta;
|
|
559
|
+
send({
|
|
560
|
+
type: 'response.function_call_arguments.delta',
|
|
561
|
+
sequence_number: seq++,
|
|
562
|
+
item_id: st.itemId,
|
|
563
|
+
output_index: st.outputIndex,
|
|
564
|
+
delta: argsDelta,
|
|
565
|
+
});
|
|
566
|
+
}
|
|
558
567
|
}
|
|
559
568
|
}
|
|
569
|
+
|
|
570
|
+
// 4) finish
|
|
571
|
+
if (choice?.finish_reason) {
|
|
572
|
+
log('info', `Stream finish_reason: ${choice.finish_reason}`);
|
|
573
|
+
await finalizeAndClose();
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
560
576
|
}
|
|
561
577
|
}
|
|
562
578
|
} catch (e) {
|