@mmmbuto/zai-codex-bridge 0.4.5 → 0.4.6
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/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/src/server.js +55 -28
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.4.6] - 2026-01-16
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- Avoid empty output_text items in tool-only streaming responses
|
|
12
|
+
- Only emit output_text.done/content_part.done when output text exists
|
|
13
|
+
|
|
8
14
|
## [0.4.5] - 2026-01-16
|
|
9
15
|
|
|
10
16
|
### Fixed
|
package/package.json
CHANGED
package/src/server.js
CHANGED
|
@@ -359,7 +359,9 @@ function translateChatToResponses(chatResponse, responsesRequest, ids, allowTool
|
|
|
359
359
|
if (reasoningText) {
|
|
360
360
|
content.push({ type: 'reasoning_text', text: reasoningText, annotations: [] });
|
|
361
361
|
}
|
|
362
|
-
|
|
362
|
+
if (outputText) {
|
|
363
|
+
content.push({ type: 'output_text', text: outputText, annotations: [] });
|
|
364
|
+
}
|
|
363
365
|
|
|
364
366
|
const msgItem = {
|
|
365
367
|
id: msgId,
|
|
@@ -369,11 +371,16 @@ function translateChatToResponses(chatResponse, responsesRequest, ids, allowTool
|
|
|
369
371
|
content,
|
|
370
372
|
};
|
|
371
373
|
|
|
372
|
-
// Build output array: message item + any function_call items
|
|
373
|
-
const finalOutput = [
|
|
374
|
+
// Build output array: message item (if any) + any function_call items
|
|
375
|
+
const finalOutput = [];
|
|
376
|
+
|
|
377
|
+
const hasToolCalls = allowTools && msg.tool_calls && Array.isArray(msg.tool_calls);
|
|
378
|
+
if (content.length > 0 || !hasToolCalls) {
|
|
379
|
+
finalOutput.push(msgItem);
|
|
380
|
+
}
|
|
374
381
|
|
|
375
382
|
// Handle tool_calls (only if allowTools)
|
|
376
|
-
if (
|
|
383
|
+
if (hasToolCalls) {
|
|
377
384
|
for (const tc of msg.tool_calls) {
|
|
378
385
|
const callId = tc.id || `call_${randomUUID().replace(/-/g, '')}`;
|
|
379
386
|
const name = tc.function?.name || '';
|
|
@@ -517,13 +524,8 @@ async function streamChatToResponses(upstreamBody, res, responsesRequest, ids, a
|
|
|
517
524
|
item: msgItemInProgress,
|
|
518
525
|
});
|
|
519
526
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
item_id: msgId,
|
|
523
|
-
output_index: OUTPUT_INDEX,
|
|
524
|
-
content_index: CONTENT_INDEX,
|
|
525
|
-
part: { type: 'output_text', text: '', annotations: [] },
|
|
526
|
-
});
|
|
527
|
+
// content_part.added emitted only if we receive output_text
|
|
528
|
+
let contentPartAdded = false;
|
|
527
529
|
|
|
528
530
|
let out = '';
|
|
529
531
|
let reasoning = '';
|
|
@@ -688,6 +690,16 @@ async function streamChatToResponses(upstreamBody, res, responsesRequest, ids, a
|
|
|
688
690
|
}
|
|
689
691
|
|
|
690
692
|
if (typeof delta.content === 'string' && delta.content.length) {
|
|
693
|
+
if (!contentPartAdded) {
|
|
694
|
+
sse({
|
|
695
|
+
type: 'response.content_part.added',
|
|
696
|
+
item_id: msgId,
|
|
697
|
+
output_index: OUTPUT_INDEX,
|
|
698
|
+
content_index: CONTENT_INDEX,
|
|
699
|
+
part: { type: 'output_text', text: '', annotations: [] },
|
|
700
|
+
});
|
|
701
|
+
contentPartAdded = true;
|
|
702
|
+
}
|
|
691
703
|
out += delta.content;
|
|
692
704
|
sse({
|
|
693
705
|
type: 'response.output_text.delta',
|
|
@@ -712,28 +724,40 @@ async function streamChatToResponses(upstreamBody, res, responsesRequest, ids, a
|
|
|
712
724
|
});
|
|
713
725
|
}
|
|
714
726
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
727
|
+
if (out.length) {
|
|
728
|
+
sse({
|
|
729
|
+
type: 'response.output_text.done',
|
|
730
|
+
item_id: msgId,
|
|
731
|
+
output_index: OUTPUT_INDEX,
|
|
732
|
+
content_index: CONTENT_INDEX,
|
|
733
|
+
text: out,
|
|
734
|
+
});
|
|
722
735
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
736
|
+
if (contentPartAdded) {
|
|
737
|
+
sse({
|
|
738
|
+
type: 'response.content_part.done',
|
|
739
|
+
item_id: msgId,
|
|
740
|
+
output_index: OUTPUT_INDEX,
|
|
741
|
+
content_index: CONTENT_INDEX,
|
|
742
|
+
part: { type: 'output_text', text: out, annotations: [] },
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
const msgContent = [];
|
|
748
|
+
if (reasoning.length) {
|
|
749
|
+
msgContent.push({ type: 'reasoning_text', text: reasoning, annotations: [] });
|
|
750
|
+
}
|
|
751
|
+
if (out.length) {
|
|
752
|
+
msgContent.push({ type: 'output_text', text: out, annotations: [] });
|
|
753
|
+
}
|
|
730
754
|
|
|
731
755
|
const msgItemDone = {
|
|
732
756
|
id: msgId,
|
|
733
757
|
type: 'message',
|
|
734
758
|
status: 'completed',
|
|
735
759
|
role: 'assistant',
|
|
736
|
-
content:
|
|
760
|
+
content: msgContent,
|
|
737
761
|
};
|
|
738
762
|
|
|
739
763
|
sse({
|
|
@@ -742,8 +766,11 @@ async function streamChatToResponses(upstreamBody, res, responsesRequest, ids, a
|
|
|
742
766
|
item: msgItemDone,
|
|
743
767
|
});
|
|
744
768
|
|
|
745
|
-
// Build final output array: message item + any function_call items
|
|
746
|
-
const finalOutput = [
|
|
769
|
+
// Build final output array: message item (if any) + any function_call items
|
|
770
|
+
const finalOutput = [];
|
|
771
|
+
if (msgContent.length > 0 || toolCallsMap.size === 0) {
|
|
772
|
+
finalOutput.push(msgItemDone);
|
|
773
|
+
}
|
|
747
774
|
if (allowTools && toolCallsMap.size > 0) {
|
|
748
775
|
const ordered = Array.from(toolCallsMap.entries()).sort((a, b) => a[0] - b[0]);
|
|
749
776
|
for (const [, tcData] of ordered) {
|