codexmate 0.0.53 → 0.0.54
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/cli/builtin-proxy.js +222 -11
- package/cli/openai-bridge.js +238 -14
- package/package.json +1 -1
package/cli/builtin-proxy.js
CHANGED
|
@@ -940,7 +940,6 @@ function createBuiltinProxyRuntimeController(deps = {}) {
|
|
|
940
940
|
'n',
|
|
941
941
|
'modalities',
|
|
942
942
|
'audio',
|
|
943
|
-
'reasoning',
|
|
944
943
|
'reasoning_effort',
|
|
945
944
|
'service_tier'
|
|
946
945
|
];
|
|
@@ -964,10 +963,15 @@ function createBuiltinProxyRuntimeController(deps = {}) {
|
|
|
964
963
|
if (isRecord(source.text) && asTrimmedString(source.text.verbosity)) {
|
|
965
964
|
chatBody.verbosity = asTrimmedString(source.text.verbosity);
|
|
966
965
|
}
|
|
966
|
+
if (isRecord(source.reasoning) && asTrimmedString(source.reasoning.effort)) {
|
|
967
|
+
chatBody.reasoning_effort = asTrimmedString(source.reasoning.effort);
|
|
968
|
+
}
|
|
967
969
|
|
|
968
970
|
pruneInvalidChatToolChoice(chatBody);
|
|
969
971
|
|
|
970
|
-
if (Object.prototype.hasOwnProperty.call(source, '
|
|
972
|
+
if (Object.prototype.hasOwnProperty.call(source, 'max_completion_tokens')) {
|
|
973
|
+
chatBody.max_tokens = Math.max(128, Number(source.max_completion_tokens) || 0);
|
|
974
|
+
} else if (Object.prototype.hasOwnProperty.call(source, 'max_tokens')) {
|
|
971
975
|
chatBody.max_tokens = source.max_tokens;
|
|
972
976
|
} else if (source.max_output_tokens != null) {
|
|
973
977
|
chatBody.max_tokens = source.max_output_tokens;
|
|
@@ -976,6 +980,18 @@ function createBuiltinProxyRuntimeController(deps = {}) {
|
|
|
976
980
|
return chatBody;
|
|
977
981
|
}
|
|
978
982
|
|
|
983
|
+
function normalizeResponsesPayloadForUpstream(payload, stream) {
|
|
984
|
+
const source = isRecord(payload) ? payload : {};
|
|
985
|
+
const normalized = { ...source, stream };
|
|
986
|
+
if (isRecord(source.reasoning)) {
|
|
987
|
+
const include = Array.isArray(source.include) ? source.include.filter((item) => typeof item === 'string') : [];
|
|
988
|
+
if (!include.includes('reasoning.encrypted_content')) {
|
|
989
|
+
normalized.include = [...include, 'reasoning.encrypted_content'];
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
return normalized;
|
|
993
|
+
}
|
|
994
|
+
|
|
979
995
|
function ensureResponseMetadata(payload) {
|
|
980
996
|
const base = payload && typeof payload === 'object' && !Array.isArray(payload) ? payload : {};
|
|
981
997
|
const id = typeof base.id === 'string' && base.id.trim()
|
|
@@ -1001,6 +1017,112 @@ function createBuiltinProxyRuntimeController(deps = {}) {
|
|
|
1001
1017
|
res.write(`data: ${JSON.stringify(dataObj)}\n\n`);
|
|
1002
1018
|
}
|
|
1003
1019
|
|
|
1020
|
+
function buildResponsesSseItem(item, fallbackId) {
|
|
1021
|
+
const source = isRecord(item) ? item : {};
|
|
1022
|
+
const itemId = asTrimmedString(source.id || source.call_id) || fallbackId || `item_${crypto.randomBytes(8).toString('hex')}`;
|
|
1023
|
+
if (source.type === 'message') {
|
|
1024
|
+
return {
|
|
1025
|
+
...source,
|
|
1026
|
+
id: itemId,
|
|
1027
|
+
role: source.role || 'assistant',
|
|
1028
|
+
content: Array.isArray(source.content)
|
|
1029
|
+
? source.content.map((part) => {
|
|
1030
|
+
if (!isRecord(part)) return part;
|
|
1031
|
+
if (part.type !== 'output_text') return cloneJsonValue(part);
|
|
1032
|
+
return {
|
|
1033
|
+
...part,
|
|
1034
|
+
text: typeof part.text === 'string' ? part.text : '',
|
|
1035
|
+
annotations: Array.isArray(part.annotations) ? part.annotations : [],
|
|
1036
|
+
logprobs: Array.isArray(part.logprobs) ? part.logprobs : []
|
|
1037
|
+
};
|
|
1038
|
+
})
|
|
1039
|
+
: []
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1042
|
+
if (source.type === 'reasoning') {
|
|
1043
|
+
return {
|
|
1044
|
+
...source,
|
|
1045
|
+
id: itemId,
|
|
1046
|
+
summary: Array.isArray(source.summary) ? source.summary : []
|
|
1047
|
+
};
|
|
1048
|
+
}
|
|
1049
|
+
if (source.type === 'function_call') {
|
|
1050
|
+
return {
|
|
1051
|
+
...source,
|
|
1052
|
+
id: itemId,
|
|
1053
|
+
call_id: asTrimmedString(source.call_id) || itemId,
|
|
1054
|
+
name: asTrimmedString(source.name),
|
|
1055
|
+
arguments: typeof source.arguments === 'string' ? source.arguments : ''
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
if (source.type === 'custom_tool_call') {
|
|
1059
|
+
return {
|
|
1060
|
+
...source,
|
|
1061
|
+
id: itemId,
|
|
1062
|
+
call_id: asTrimmedString(source.call_id) || itemId,
|
|
1063
|
+
name: asTrimmedString(source.name),
|
|
1064
|
+
input: typeof source.input === 'string' ? source.input : ''
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
return { ...source, id: itemId };
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
function emitResponsesTextPartAdded(res, itemId, outputIndex, contentIndex, nextSeq) {
|
|
1071
|
+
writeSse(res, 'response.content_part.added', {
|
|
1072
|
+
type: 'response.content_part.added',
|
|
1073
|
+
item_id: itemId,
|
|
1074
|
+
output_index: outputIndex,
|
|
1075
|
+
content_index: contentIndex,
|
|
1076
|
+
part: { type: 'output_text', text: '', annotations: [], logprobs: [] },
|
|
1077
|
+
sequence_number: nextSeq()
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
function emitResponsesTextPartDone(res, itemId, outputIndex, contentIndex, text, nextSeq) {
|
|
1082
|
+
writeSse(res, 'response.content_part.done', {
|
|
1083
|
+
type: 'response.content_part.done',
|
|
1084
|
+
item_id: itemId,
|
|
1085
|
+
output_index: outputIndex,
|
|
1086
|
+
content_index: contentIndex,
|
|
1087
|
+
part: { type: 'output_text', text: typeof text === 'string' ? text : '', annotations: [], logprobs: [] },
|
|
1088
|
+
sequence_number: nextSeq()
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
function emitResponsesToolArgumentEvents(res, item, outputIndex, nextSeq) {
|
|
1093
|
+
const eventType = item.type === 'custom_tool_call'
|
|
1094
|
+
? 'response.custom_tool_call_input.delta'
|
|
1095
|
+
: 'response.function_call_arguments.delta';
|
|
1096
|
+
const doneType = item.type === 'custom_tool_call'
|
|
1097
|
+
? ''
|
|
1098
|
+
: 'response.function_call_arguments.done';
|
|
1099
|
+
const value = item.type === 'custom_tool_call'
|
|
1100
|
+
? (typeof item.input === 'string' ? item.input : '')
|
|
1101
|
+
: (typeof item.arguments === 'string' ? item.arguments : '');
|
|
1102
|
+
if (value) {
|
|
1103
|
+
writeSse(res, eventType, {
|
|
1104
|
+
type: eventType,
|
|
1105
|
+
item_id: item.id,
|
|
1106
|
+
output_index: outputIndex,
|
|
1107
|
+
call_id: item.call_id,
|
|
1108
|
+
name: item.name,
|
|
1109
|
+
delta: value,
|
|
1110
|
+
sequence_number: nextSeq()
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
if (doneType) {
|
|
1114
|
+
writeSse(res, doneType, {
|
|
1115
|
+
type: doneType,
|
|
1116
|
+
item_id: item.id,
|
|
1117
|
+
output_index: outputIndex,
|
|
1118
|
+
call_id: item.call_id,
|
|
1119
|
+
name: item.name,
|
|
1120
|
+
arguments: value,
|
|
1121
|
+
sequence_number: nextSeq()
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1004
1126
|
function sendResponsesSse(res, responsePayload) {
|
|
1005
1127
|
const response = ensureResponseMetadata(responsePayload);
|
|
1006
1128
|
const responseId = response.id;
|
|
@@ -1027,12 +1149,14 @@ function createBuiltinProxyRuntimeController(deps = {}) {
|
|
|
1027
1149
|
const itemType = typeof item.type === 'string' ? item.type : '';
|
|
1028
1150
|
const itemId = typeof item.id === 'string' && item.id.trim()
|
|
1029
1151
|
? item.id.trim()
|
|
1030
|
-
: `item_${crypto.randomBytes(8).toString('hex')}
|
|
1152
|
+
: (typeof item.call_id === 'string' && item.call_id.trim() ? item.call_id.trim() : `item_${crypto.randomBytes(8).toString('hex')}`);
|
|
1153
|
+
const wireItem = buildResponsesSseItem(item, itemId);
|
|
1031
1154
|
|
|
1032
1155
|
writeSse(res, 'response.output_item.added', {
|
|
1033
1156
|
type: 'response.output_item.added',
|
|
1034
1157
|
output_index: outputIndex,
|
|
1035
|
-
item:
|
|
1158
|
+
item: wireItem,
|
|
1159
|
+
sequence_number: nextSeq()
|
|
1036
1160
|
});
|
|
1037
1161
|
|
|
1038
1162
|
if (itemType === 'message') {
|
|
@@ -1042,6 +1166,7 @@ function createBuiltinProxyRuntimeController(deps = {}) {
|
|
|
1042
1166
|
if (!block || typeof block !== 'object') continue;
|
|
1043
1167
|
if (block.type !== 'output_text') continue;
|
|
1044
1168
|
const text = typeof block.text === 'string' ? block.text : '';
|
|
1169
|
+
emitResponsesTextPartAdded(res, itemId, outputIndex, contentIndex, nextSeq);
|
|
1045
1170
|
if (text) {
|
|
1046
1171
|
writeSse(res, 'response.output_text.delta', {
|
|
1047
1172
|
type: 'response.output_text.delta',
|
|
@@ -1060,13 +1185,40 @@ function createBuiltinProxyRuntimeController(deps = {}) {
|
|
|
1060
1185
|
text,
|
|
1061
1186
|
sequence_number: nextSeq()
|
|
1062
1187
|
});
|
|
1188
|
+
emitResponsesTextPartDone(res, itemId, outputIndex, contentIndex, text, nextSeq);
|
|
1189
|
+
}
|
|
1190
|
+
} else if (itemType === 'function_call' || itemType === 'custom_tool_call') {
|
|
1191
|
+
emitResponsesToolArgumentEvents(res, wireItem, outputIndex, nextSeq);
|
|
1192
|
+
} else if (itemType === 'reasoning') {
|
|
1193
|
+
const summary = Array.isArray(item.summary) ? item.summary : [];
|
|
1194
|
+
for (let summaryIndex = 0; summaryIndex < summary.length; summaryIndex += 1) {
|
|
1195
|
+
const block = summary[summaryIndex];
|
|
1196
|
+
const text = block && typeof block.text === 'string' ? block.text : '';
|
|
1197
|
+
if (text) {
|
|
1198
|
+
writeSse(res, 'response.reasoning_summary_text.delta', {
|
|
1199
|
+
type: 'response.reasoning_summary_text.delta',
|
|
1200
|
+
item_id: itemId,
|
|
1201
|
+
output_index: outputIndex,
|
|
1202
|
+
summary_index: summaryIndex,
|
|
1203
|
+
delta: text,
|
|
1204
|
+
sequence_number: nextSeq()
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
writeSse(res, 'response.reasoning_summary_text.done', {
|
|
1208
|
+
type: 'response.reasoning_summary_text.done',
|
|
1209
|
+
item_id: itemId,
|
|
1210
|
+
output_index: outputIndex,
|
|
1211
|
+
summary_index: summaryIndex,
|
|
1212
|
+
text,
|
|
1213
|
+
sequence_number: nextSeq()
|
|
1214
|
+
});
|
|
1063
1215
|
}
|
|
1064
1216
|
}
|
|
1065
1217
|
|
|
1066
1218
|
writeSse(res, 'response.output_item.done', {
|
|
1067
1219
|
type: 'response.output_item.done',
|
|
1068
1220
|
output_index: outputIndex,
|
|
1069
|
-
item:
|
|
1221
|
+
item: wireItem,
|
|
1070
1222
|
sequence_number: nextSeq()
|
|
1071
1223
|
});
|
|
1072
1224
|
}
|
|
@@ -1105,6 +1257,40 @@ function createBuiltinProxyRuntimeController(deps = {}) {
|
|
|
1105
1257
|
const delta = choice && choice.delta && typeof choice.delta === 'object' ? choice.delta : null;
|
|
1106
1258
|
if (!delta) continue;
|
|
1107
1259
|
|
|
1260
|
+
const reasoningSegment = typeof delta.reasoning_content === 'string'
|
|
1261
|
+
? delta.reasoning_content
|
|
1262
|
+
: (typeof delta.reasoning === 'string'
|
|
1263
|
+
? delta.reasoning
|
|
1264
|
+
: (typeof delta.reasoning_text === 'string' ? delta.reasoning_text : ''));
|
|
1265
|
+
if (reasoningSegment) {
|
|
1266
|
+
if (!state.reasoningItem) {
|
|
1267
|
+
state.reasoningItem = {
|
|
1268
|
+
id: `rs_${crypto.randomBytes(8).toString('hex')}`,
|
|
1269
|
+
type: 'reasoning',
|
|
1270
|
+
summary: [{ type: 'summary_text', text: '' }]
|
|
1271
|
+
};
|
|
1272
|
+
state.output.push(state.reasoningItem);
|
|
1273
|
+
state.outputStarted = true;
|
|
1274
|
+
beginChatStreamResponsesSse(state);
|
|
1275
|
+
writeSse(state.res, 'response.output_item.added', {
|
|
1276
|
+
type: 'response.output_item.added',
|
|
1277
|
+
output_index: state.output.length - 1,
|
|
1278
|
+
item: buildResponsesSseItem(state.reasoningItem, state.reasoningItem.id),
|
|
1279
|
+
sequence_number: state.nextSeq()
|
|
1280
|
+
});
|
|
1281
|
+
}
|
|
1282
|
+
state.reasoningText += reasoningSegment;
|
|
1283
|
+
state.reasoningItem.summary[0].text = state.reasoningText;
|
|
1284
|
+
writeSse(state.res, 'response.reasoning_summary_text.delta', {
|
|
1285
|
+
type: 'response.reasoning_summary_text.delta',
|
|
1286
|
+
item_id: state.reasoningItem.id,
|
|
1287
|
+
output_index: state.output.indexOf(state.reasoningItem),
|
|
1288
|
+
summary_index: 0,
|
|
1289
|
+
delta: reasoningSegment,
|
|
1290
|
+
sequence_number: state.nextSeq()
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1108
1294
|
if (typeof delta.content === 'string' && delta.content) {
|
|
1109
1295
|
if (!state.messageItem) {
|
|
1110
1296
|
state.messageItem = {
|
|
@@ -1119,8 +1305,10 @@ function createBuiltinProxyRuntimeController(deps = {}) {
|
|
|
1119
1305
|
writeSse(state.res, 'response.output_item.added', {
|
|
1120
1306
|
type: 'response.output_item.added',
|
|
1121
1307
|
output_index: state.output.length - 1,
|
|
1122
|
-
item: state.messageItem
|
|
1308
|
+
item: buildResponsesSseItem(state.messageItem, state.messageItem.id),
|
|
1309
|
+
sequence_number: state.nextSeq()
|
|
1123
1310
|
});
|
|
1311
|
+
emitResponsesTextPartAdded(state.res, state.messageItem.id, state.output.length - 1, 0, state.nextSeq);
|
|
1124
1312
|
}
|
|
1125
1313
|
state.messageText += delta.content;
|
|
1126
1314
|
state.messageItem.content[0].text = state.messageText;
|
|
@@ -1172,6 +1360,24 @@ function createBuiltinProxyRuntimeController(deps = {}) {
|
|
|
1172
1360
|
state.finished = true;
|
|
1173
1361
|
stopChatStreamHeartbeat(state);
|
|
1174
1362
|
|
|
1363
|
+
if (state.reasoningItem) {
|
|
1364
|
+
const outputIndex = state.output.indexOf(state.reasoningItem);
|
|
1365
|
+
writeSse(state.res, 'response.reasoning_summary_text.done', {
|
|
1366
|
+
type: 'response.reasoning_summary_text.done',
|
|
1367
|
+
item_id: state.reasoningItem.id,
|
|
1368
|
+
output_index: outputIndex,
|
|
1369
|
+
summary_index: 0,
|
|
1370
|
+
text: state.reasoningText,
|
|
1371
|
+
sequence_number: state.nextSeq()
|
|
1372
|
+
});
|
|
1373
|
+
writeSse(state.res, 'response.output_item.done', {
|
|
1374
|
+
type: 'response.output_item.done',
|
|
1375
|
+
output_index: outputIndex,
|
|
1376
|
+
item: buildResponsesSseItem(state.reasoningItem, state.reasoningItem.id),
|
|
1377
|
+
sequence_number: state.nextSeq()
|
|
1378
|
+
});
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1175
1381
|
if (state.messageItem) {
|
|
1176
1382
|
const outputIndex = state.output.indexOf(state.messageItem);
|
|
1177
1383
|
writeSse(state.res, 'response.output_text.done', {
|
|
@@ -1182,10 +1388,11 @@ function createBuiltinProxyRuntimeController(deps = {}) {
|
|
|
1182
1388
|
text: state.messageText,
|
|
1183
1389
|
sequence_number: state.nextSeq()
|
|
1184
1390
|
});
|
|
1391
|
+
emitResponsesTextPartDone(state.res, state.messageItem.id, outputIndex, 0, state.messageText, state.nextSeq);
|
|
1185
1392
|
writeSse(state.res, 'response.output_item.done', {
|
|
1186
1393
|
type: 'response.output_item.done',
|
|
1187
1394
|
output_index: outputIndex,
|
|
1188
|
-
item: state.messageItem,
|
|
1395
|
+
item: buildResponsesSseItem(state.messageItem, state.messageItem.id),
|
|
1189
1396
|
sequence_number: state.nextSeq()
|
|
1190
1397
|
});
|
|
1191
1398
|
}
|
|
@@ -1200,12 +1407,14 @@ function createBuiltinProxyRuntimeController(deps = {}) {
|
|
|
1200
1407
|
writeSse(state.res, 'response.output_item.added', {
|
|
1201
1408
|
type: 'response.output_item.added',
|
|
1202
1409
|
output_index: outputIndex,
|
|
1203
|
-
item
|
|
1410
|
+
item: buildResponsesSseItem(item, item.call_id),
|
|
1411
|
+
sequence_number: state.nextSeq()
|
|
1204
1412
|
});
|
|
1413
|
+
emitResponsesToolArgumentEvents(state.res, buildResponsesSseItem(item, item.call_id), outputIndex, state.nextSeq);
|
|
1205
1414
|
writeSse(state.res, 'response.output_item.done', {
|
|
1206
1415
|
type: 'response.output_item.done',
|
|
1207
1416
|
output_index: outputIndex,
|
|
1208
|
-
item,
|
|
1417
|
+
item: buildResponsesSseItem(item, item.call_id),
|
|
1209
1418
|
sequence_number: state.nextSeq()
|
|
1210
1419
|
});
|
|
1211
1420
|
}
|
|
@@ -1282,6 +1491,8 @@ function createBuiltinProxyRuntimeController(deps = {}) {
|
|
|
1282
1491
|
output: [],
|
|
1283
1492
|
messageItem: null,
|
|
1284
1493
|
messageText: '',
|
|
1494
|
+
reasoningItem: null,
|
|
1495
|
+
reasoningText: '',
|
|
1285
1496
|
toolCalls: [],
|
|
1286
1497
|
toolTypesByName: options.toolTypesByName || {},
|
|
1287
1498
|
finished: false,
|
|
@@ -1983,7 +2194,7 @@ function createBuiltinProxyRuntimeController(deps = {}) {
|
|
|
1983
2194
|
method: 'POST',
|
|
1984
2195
|
headers: commonHeaders,
|
|
1985
2196
|
timeoutMs,
|
|
1986
|
-
body:
|
|
2197
|
+
body: normalizeResponsesPayloadForUpstream(payload, true),
|
|
1987
2198
|
res,
|
|
1988
2199
|
model
|
|
1989
2200
|
});
|
|
@@ -2031,7 +2242,7 @@ function createBuiltinProxyRuntimeController(deps = {}) {
|
|
|
2031
2242
|
method: 'POST',
|
|
2032
2243
|
headers: commonHeaders,
|
|
2033
2244
|
timeoutMs,
|
|
2034
|
-
body:
|
|
2245
|
+
body: normalizeResponsesPayloadForUpstream(payload, false)
|
|
2035
2246
|
});
|
|
2036
2247
|
|
|
2037
2248
|
// 优先走上游 /responses(如果支持)。若上游报错且不是“端点不支持”,则直接透传错误。
|
package/cli/openai-bridge.js
CHANGED
|
@@ -300,9 +300,28 @@ function cloneJsonValue(value) {
|
|
|
300
300
|
}
|
|
301
301
|
|
|
302
302
|
function normalizeResponsesToolOutput(value) {
|
|
303
|
-
if (typeof value === 'string') return value;
|
|
304
|
-
if (value == null) return '';
|
|
305
|
-
return stringifyJsonValue(value, '');
|
|
303
|
+
if (typeof value === 'string') return value || '(empty)';
|
|
304
|
+
if (value == null) return '(empty)';
|
|
305
|
+
return stringifyJsonValue(value, '(empty)') || '(empty)';
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function chatContentToPlainText(content) {
|
|
309
|
+
if (typeof content === 'string') return content;
|
|
310
|
+
if (!Array.isArray(content)) return '';
|
|
311
|
+
return content
|
|
312
|
+
.map((item) => {
|
|
313
|
+
if (typeof item === 'string') return item;
|
|
314
|
+
if (!isRecord(item)) return '';
|
|
315
|
+
if (typeof item.text === 'string') return item.text;
|
|
316
|
+
if (typeof item.content === 'string') return item.content;
|
|
317
|
+
return '';
|
|
318
|
+
})
|
|
319
|
+
.join('');
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function wrapReasoningContentForChat(content) {
|
|
323
|
+
const text = chatContentToPlainText(content).trim();
|
|
324
|
+
return text ? `<thinking>${text}</thinking>` : '';
|
|
306
325
|
}
|
|
307
326
|
|
|
308
327
|
function normalizeOpenAiToolArguments(value) {
|
|
@@ -530,7 +549,7 @@ function normalizeResponsesInputToChatMessages(input) {
|
|
|
530
549
|
|
|
531
550
|
if (itemType === 'reasoning') {
|
|
532
551
|
flushPendingToolCalls();
|
|
533
|
-
const reasoningContent = toOpenAiMessageContent(item.summary != null ? item.summary : (item.content != null ? item.content : item));
|
|
552
|
+
const reasoningContent = wrapReasoningContentForChat(toOpenAiMessageContent(item.summary != null ? item.summary : (item.content != null ? item.content : item)));
|
|
534
553
|
const reasoningSignature = asTrimmedString(item.encrypted_content || item.reasoning_signature);
|
|
535
554
|
if (!hasOpenAiMessageContent(reasoningContent) && !reasoningSignature) return;
|
|
536
555
|
const message = { role: 'assistant', content: reasoningContent };
|
|
@@ -889,6 +908,12 @@ function convertResponsesRequestToChatCompletions(payload) {
|
|
|
889
908
|
top_p: Number.isFinite(body.top_p) ? Number(body.top_p) : undefined,
|
|
890
909
|
max_tokens: Number.isFinite(maxOutputTokens) && maxOutputTokens > 0 ? maxOutputTokens : undefined
|
|
891
910
|
};
|
|
911
|
+
if (isRecord(body.reasoning)) {
|
|
912
|
+
const effort = asTrimmedString(body.reasoning.effort);
|
|
913
|
+
if (effort) chat.reasoning_effort = effort;
|
|
914
|
+
} else if (asTrimmedString(body.reasoning_effort)) {
|
|
915
|
+
chat.reasoning_effort = asTrimmedString(body.reasoning_effort);
|
|
916
|
+
}
|
|
892
917
|
if (Array.isArray(body.stop) && body.stop.length) {
|
|
893
918
|
chat.stop = body.stop.filter((item) => typeof item === 'string' && item.trim());
|
|
894
919
|
}
|
|
@@ -940,12 +965,22 @@ function buildResponsesPayloadFromChatResult(model, text, toolCalls, upstreamPay
|
|
|
940
965
|
}
|
|
941
966
|
}
|
|
942
967
|
|
|
968
|
+
const choice = upstreamPayload && typeof upstreamPayload === 'object' && Array.isArray(upstreamPayload.choices)
|
|
969
|
+
? upstreamPayload.choices[0]
|
|
970
|
+
: null;
|
|
971
|
+
const finishReason = choice && typeof choice.finish_reason === 'string' ? choice.finish_reason : '';
|
|
972
|
+
const statusPatch = finishReason === 'length'
|
|
973
|
+
? { status: 'incomplete', incomplete_details: { reason: 'max_output_tokens' } }
|
|
974
|
+
: (finishReason === 'content_filter'
|
|
975
|
+
? { status: 'incomplete', incomplete_details: { reason: 'content_filter' } }
|
|
976
|
+
: { status: 'completed' });
|
|
977
|
+
|
|
943
978
|
const payload = {
|
|
944
979
|
id: responseId,
|
|
945
980
|
object: 'response',
|
|
946
981
|
model,
|
|
947
982
|
created_at: createdAt,
|
|
948
|
-
|
|
983
|
+
...statusPatch,
|
|
949
984
|
output,
|
|
950
985
|
output_text: trimmedText
|
|
951
986
|
};
|
|
@@ -1017,12 +1052,14 @@ function sendResponsesSse(res, responsePayload) {
|
|
|
1017
1052
|
const itemId = typeof item.id === 'string' && item.id.trim()
|
|
1018
1053
|
? item.id.trim()
|
|
1019
1054
|
: (typeof item.call_id === 'string' && item.call_id.trim() ? item.call_id.trim() : `item_${crypto.randomBytes(8).toString('hex')}`);
|
|
1055
|
+
const wireItem = buildResponsesSseItem(item, itemId);
|
|
1020
1056
|
|
|
1021
1057
|
// Emit item added so Codex can anchor subsequent deltas by output_index/content_index/item_id.
|
|
1022
1058
|
writeSse(res, 'response.output_item.added', {
|
|
1023
1059
|
type: 'response.output_item.added',
|
|
1024
1060
|
output_index: outputIndex,
|
|
1025
|
-
item:
|
|
1061
|
+
item: wireItem,
|
|
1062
|
+
sequence_number: nextSeq()
|
|
1026
1063
|
});
|
|
1027
1064
|
|
|
1028
1065
|
if (itemType === 'message') {
|
|
@@ -1032,6 +1069,7 @@ function sendResponsesSse(res, responsePayload) {
|
|
|
1032
1069
|
if (!block || typeof block !== 'object') continue;
|
|
1033
1070
|
if (block.type !== 'output_text') continue;
|
|
1034
1071
|
const text = typeof block.text === 'string' ? block.text : '';
|
|
1072
|
+
emitResponsesTextPartAdded(res, itemId, outputIndex, contentIndex, nextSeq);
|
|
1035
1073
|
if (text) {
|
|
1036
1074
|
writeSse(res, 'response.output_text.delta', {
|
|
1037
1075
|
type: 'response.output_text.delta',
|
|
@@ -1050,6 +1088,33 @@ function sendResponsesSse(res, responsePayload) {
|
|
|
1050
1088
|
text,
|
|
1051
1089
|
sequence_number: nextSeq()
|
|
1052
1090
|
});
|
|
1091
|
+
emitResponsesTextPartDone(res, itemId, outputIndex, contentIndex, text, nextSeq);
|
|
1092
|
+
}
|
|
1093
|
+
} else if (itemType === 'function_call' || itemType === 'custom_tool_call') {
|
|
1094
|
+
emitResponsesToolArgumentEvents(res, wireItem, outputIndex, nextSeq);
|
|
1095
|
+
} else if (itemType === 'reasoning') {
|
|
1096
|
+
const summary = Array.isArray(item.summary) ? item.summary : [];
|
|
1097
|
+
for (let summaryIndex = 0; summaryIndex < summary.length; summaryIndex += 1) {
|
|
1098
|
+
const block = summary[summaryIndex];
|
|
1099
|
+
const text = block && typeof block.text === 'string' ? block.text : '';
|
|
1100
|
+
if (text) {
|
|
1101
|
+
writeSse(res, 'response.reasoning_summary_text.delta', {
|
|
1102
|
+
type: 'response.reasoning_summary_text.delta',
|
|
1103
|
+
item_id: itemId,
|
|
1104
|
+
output_index: outputIndex,
|
|
1105
|
+
summary_index: summaryIndex,
|
|
1106
|
+
delta: text,
|
|
1107
|
+
sequence_number: nextSeq()
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
writeSse(res, 'response.reasoning_summary_text.done', {
|
|
1111
|
+
type: 'response.reasoning_summary_text.done',
|
|
1112
|
+
item_id: itemId,
|
|
1113
|
+
output_index: outputIndex,
|
|
1114
|
+
summary_index: summaryIndex,
|
|
1115
|
+
text,
|
|
1116
|
+
sequence_number: nextSeq()
|
|
1117
|
+
});
|
|
1053
1118
|
}
|
|
1054
1119
|
}
|
|
1055
1120
|
|
|
@@ -1057,7 +1122,7 @@ function sendResponsesSse(res, responsePayload) {
|
|
|
1057
1122
|
writeSse(res, 'response.output_item.done', {
|
|
1058
1123
|
type: 'response.output_item.done',
|
|
1059
1124
|
output_index: outputIndex,
|
|
1060
|
-
item:
|
|
1125
|
+
item: wireItem,
|
|
1061
1126
|
sequence_number: nextSeq()
|
|
1062
1127
|
});
|
|
1063
1128
|
}
|
|
@@ -1083,15 +1148,25 @@ function extractResponsesOutputText(payload) {
|
|
|
1083
1148
|
return '';
|
|
1084
1149
|
}
|
|
1085
1150
|
|
|
1086
|
-
function
|
|
1151
|
+
function normalizeResponsesPayloadForUpstream(payload, stream) {
|
|
1087
1152
|
const body = payload && typeof payload === 'object' ? payload : {};
|
|
1088
|
-
const normalized = { ...body, stream
|
|
1153
|
+
const normalized = { ...body, stream };
|
|
1089
1154
|
if (Array.isArray(body.tools)) {
|
|
1090
1155
|
normalized.tools = normalizeResponsesToolsForResponsesApi(body.tools);
|
|
1091
1156
|
}
|
|
1157
|
+
if (isRecord(body.reasoning)) {
|
|
1158
|
+
const include = Array.isArray(body.include) ? body.include.filter((item) => typeof item === 'string') : [];
|
|
1159
|
+
if (!include.includes('reasoning.encrypted_content')) {
|
|
1160
|
+
normalized.include = [...include, 'reasoning.encrypted_content'];
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1092
1163
|
return normalized;
|
|
1093
1164
|
}
|
|
1094
1165
|
|
|
1166
|
+
function toUpstreamNonStreamingResponsesPayload(payload) {
|
|
1167
|
+
return normalizeResponsesPayloadForUpstream(payload, false);
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1095
1170
|
function shouldFallbackFromUpstreamResponses(status, bodyText) {
|
|
1096
1171
|
if (!Number.isFinite(status)) return false;
|
|
1097
1172
|
// Common "unsupported" status codes for a route.
|
|
@@ -1202,6 +1277,101 @@ function writeSse(res, eventName, dataObj) {
|
|
|
1202
1277
|
res.write(`data: ${JSON.stringify(dataObj)}\n\n`);
|
|
1203
1278
|
}
|
|
1204
1279
|
|
|
1280
|
+
function buildResponsesSseItem(item, fallbackId) {
|
|
1281
|
+
const source = isRecord(item) ? item : {};
|
|
1282
|
+
const itemId = asTrimmedString(source.id || source.call_id) || fallbackId || `item_${crypto.randomBytes(8).toString('hex')}`;
|
|
1283
|
+
if (source.type === 'message') {
|
|
1284
|
+
return {
|
|
1285
|
+
...source,
|
|
1286
|
+
id: itemId,
|
|
1287
|
+
role: source.role || 'assistant',
|
|
1288
|
+
content: Array.isArray(source.content) ? source.content : []
|
|
1289
|
+
};
|
|
1290
|
+
}
|
|
1291
|
+
if (source.type === 'reasoning') {
|
|
1292
|
+
return {
|
|
1293
|
+
...source,
|
|
1294
|
+
id: itemId,
|
|
1295
|
+
summary: Array.isArray(source.summary) ? source.summary : []
|
|
1296
|
+
};
|
|
1297
|
+
}
|
|
1298
|
+
if (source.type === 'function_call') {
|
|
1299
|
+
return {
|
|
1300
|
+
...source,
|
|
1301
|
+
id: itemId,
|
|
1302
|
+
call_id: asTrimmedString(source.call_id) || itemId,
|
|
1303
|
+
name: asTrimmedString(source.name),
|
|
1304
|
+
arguments: typeof source.arguments === 'string' ? source.arguments : ''
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
if (source.type === 'custom_tool_call') {
|
|
1308
|
+
return {
|
|
1309
|
+
...source,
|
|
1310
|
+
id: itemId,
|
|
1311
|
+
call_id: asTrimmedString(source.call_id) || itemId,
|
|
1312
|
+
name: asTrimmedString(source.name),
|
|
1313
|
+
input: typeof source.input === 'string' ? source.input : ''
|
|
1314
|
+
};
|
|
1315
|
+
}
|
|
1316
|
+
return { ...source, id: itemId };
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
function emitResponsesTextPartAdded(res, itemId, outputIndex, contentIndex, nextSeq) {
|
|
1320
|
+
writeSse(res, 'response.content_part.added', {
|
|
1321
|
+
type: 'response.content_part.added',
|
|
1322
|
+
item_id: itemId,
|
|
1323
|
+
output_index: outputIndex,
|
|
1324
|
+
content_index: contentIndex,
|
|
1325
|
+
part: { type: 'output_text', text: '', annotations: [], logprobs: [] },
|
|
1326
|
+
sequence_number: nextSeq()
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
function emitResponsesTextPartDone(res, itemId, outputIndex, contentIndex, text, nextSeq) {
|
|
1331
|
+
writeSse(res, 'response.content_part.done', {
|
|
1332
|
+
type: 'response.content_part.done',
|
|
1333
|
+
item_id: itemId,
|
|
1334
|
+
output_index: outputIndex,
|
|
1335
|
+
content_index: contentIndex,
|
|
1336
|
+
part: { type: 'output_text', text: typeof text === 'string' ? text : '', annotations: [], logprobs: [] },
|
|
1337
|
+
sequence_number: nextSeq()
|
|
1338
|
+
});
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
function emitResponsesToolArgumentEvents(res, item, outputIndex, nextSeq) {
|
|
1342
|
+
const eventType = item.type === 'custom_tool_call'
|
|
1343
|
+
? 'response.custom_tool_call_input.delta'
|
|
1344
|
+
: 'response.function_call_arguments.delta';
|
|
1345
|
+
const doneType = item.type === 'custom_tool_call'
|
|
1346
|
+
? ''
|
|
1347
|
+
: 'response.function_call_arguments.done';
|
|
1348
|
+
const value = item.type === 'custom_tool_call'
|
|
1349
|
+
? (typeof item.input === 'string' ? item.input : '')
|
|
1350
|
+
: (typeof item.arguments === 'string' ? item.arguments : '');
|
|
1351
|
+
if (value) {
|
|
1352
|
+
writeSse(res, eventType, {
|
|
1353
|
+
type: eventType,
|
|
1354
|
+
item_id: item.id,
|
|
1355
|
+
output_index: outputIndex,
|
|
1356
|
+
call_id: item.call_id,
|
|
1357
|
+
name: item.name,
|
|
1358
|
+
delta: value,
|
|
1359
|
+
sequence_number: nextSeq()
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1362
|
+
if (doneType) {
|
|
1363
|
+
writeSse(res, doneType, {
|
|
1364
|
+
type: doneType,
|
|
1365
|
+
item_id: item.id,
|
|
1366
|
+
output_index: outputIndex,
|
|
1367
|
+
call_id: item.call_id,
|
|
1368
|
+
name: item.name,
|
|
1369
|
+
arguments: value,
|
|
1370
|
+
sequence_number: nextSeq()
|
|
1371
|
+
});
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1205
1375
|
function appendChatStreamToolCall(target, toolCall) {
|
|
1206
1376
|
if (!toolCall || typeof toolCall !== 'object') return;
|
|
1207
1377
|
const index = Number.isFinite(toolCall.index) ? toolCall.index : target.length;
|
|
@@ -1232,6 +1402,37 @@ function writeChatCompletionChunkAsResponsesSse(state, chunk) {
|
|
|
1232
1402
|
const delta = choice && choice.delta && typeof choice.delta === 'object' ? choice.delta : null;
|
|
1233
1403
|
if (!delta) continue;
|
|
1234
1404
|
|
|
1405
|
+
const reasoningSegment = typeof delta.reasoning_content === 'string'
|
|
1406
|
+
? delta.reasoning_content
|
|
1407
|
+
: (typeof delta.reasoning === 'string'
|
|
1408
|
+
? delta.reasoning
|
|
1409
|
+
: (typeof delta.reasoning_text === 'string' ? delta.reasoning_text : ''));
|
|
1410
|
+
if (reasoningSegment) {
|
|
1411
|
+
if (!state.reasoningItem) {
|
|
1412
|
+
state.reasoningItem = {
|
|
1413
|
+
id: `rs_${crypto.randomBytes(8).toString('hex')}`,
|
|
1414
|
+
type: 'reasoning',
|
|
1415
|
+
summary: [{ type: 'summary_text', text: '' }]
|
|
1416
|
+
};
|
|
1417
|
+
state.output.push(state.reasoningItem);
|
|
1418
|
+
writeSse(state.res, 'response.output_item.added', {
|
|
1419
|
+
type: 'response.output_item.added',
|
|
1420
|
+
output_index: state.output.length - 1,
|
|
1421
|
+
item: buildResponsesSseItem(state.reasoningItem, state.reasoningItem.id)
|
|
1422
|
+
});
|
|
1423
|
+
}
|
|
1424
|
+
state.reasoningText += reasoningSegment;
|
|
1425
|
+
state.reasoningItem.summary[0].text = state.reasoningText;
|
|
1426
|
+
writeSse(state.res, 'response.reasoning_summary_text.delta', {
|
|
1427
|
+
type: 'response.reasoning_summary_text.delta',
|
|
1428
|
+
item_id: state.reasoningItem.id,
|
|
1429
|
+
output_index: state.output.indexOf(state.reasoningItem),
|
|
1430
|
+
summary_index: 0,
|
|
1431
|
+
delta: reasoningSegment,
|
|
1432
|
+
sequence_number: state.nextSeq()
|
|
1433
|
+
});
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1235
1436
|
const segments = [];
|
|
1236
1437
|
// DeepSeek-style OpenAI-compatible streams may emit private reasoning in
|
|
1237
1438
|
// `reasoning_content` before the final answer. Responses `output_text`
|
|
@@ -1252,8 +1453,9 @@ function writeChatCompletionChunkAsResponsesSse(state, chunk) {
|
|
|
1252
1453
|
writeSse(state.res, 'response.output_item.added', {
|
|
1253
1454
|
type: 'response.output_item.added',
|
|
1254
1455
|
output_index: state.output.length - 1,
|
|
1255
|
-
item: state.messageItem
|
|
1456
|
+
item: buildResponsesSseItem(state.messageItem, state.messageItem.id)
|
|
1256
1457
|
});
|
|
1458
|
+
emitResponsesTextPartAdded(state.res, state.messageItem.id, state.output.length - 1, 0, state.nextSeq);
|
|
1257
1459
|
}
|
|
1258
1460
|
state.messageText += seg;
|
|
1259
1461
|
state.messageItem.content[0].text = state.messageText;
|
|
@@ -1283,6 +1485,24 @@ function finishChatStreamResponsesSse(state) {
|
|
|
1283
1485
|
if (!state || state.finished) return;
|
|
1284
1486
|
state.finished = true;
|
|
1285
1487
|
|
|
1488
|
+
if (state.reasoningItem) {
|
|
1489
|
+
const outputIndex = state.output.indexOf(state.reasoningItem);
|
|
1490
|
+
writeSse(state.res, 'response.reasoning_summary_text.done', {
|
|
1491
|
+
type: 'response.reasoning_summary_text.done',
|
|
1492
|
+
item_id: state.reasoningItem.id,
|
|
1493
|
+
output_index: outputIndex,
|
|
1494
|
+
summary_index: 0,
|
|
1495
|
+
text: state.reasoningText,
|
|
1496
|
+
sequence_number: state.nextSeq()
|
|
1497
|
+
});
|
|
1498
|
+
writeSse(state.res, 'response.output_item.done', {
|
|
1499
|
+
type: 'response.output_item.done',
|
|
1500
|
+
output_index: outputIndex,
|
|
1501
|
+
item: buildResponsesSseItem(state.reasoningItem, state.reasoningItem.id),
|
|
1502
|
+
sequence_number: state.nextSeq()
|
|
1503
|
+
});
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1286
1506
|
if (state.messageItem) {
|
|
1287
1507
|
const outputIndex = state.output.indexOf(state.messageItem);
|
|
1288
1508
|
writeSse(state.res, 'response.output_text.done', {
|
|
@@ -1293,10 +1513,11 @@ function finishChatStreamResponsesSse(state) {
|
|
|
1293
1513
|
text: state.messageText,
|
|
1294
1514
|
sequence_number: state.nextSeq()
|
|
1295
1515
|
});
|
|
1516
|
+
emitResponsesTextPartDone(state.res, state.messageItem.id, outputIndex, 0, state.messageText, state.nextSeq);
|
|
1296
1517
|
writeSse(state.res, 'response.output_item.done', {
|
|
1297
1518
|
type: 'response.output_item.done',
|
|
1298
1519
|
output_index: outputIndex,
|
|
1299
|
-
item: state.messageItem,
|
|
1520
|
+
item: buildResponsesSseItem(state.messageItem, state.messageItem.id),
|
|
1300
1521
|
sequence_number: state.nextSeq()
|
|
1301
1522
|
});
|
|
1302
1523
|
}
|
|
@@ -1310,12 +1531,13 @@ function finishChatStreamResponsesSse(state) {
|
|
|
1310
1531
|
writeSse(state.res, 'response.output_item.added', {
|
|
1311
1532
|
type: 'response.output_item.added',
|
|
1312
1533
|
output_index: outputIndex,
|
|
1313
|
-
item
|
|
1534
|
+
item: buildResponsesSseItem(item, item.call_id)
|
|
1314
1535
|
});
|
|
1536
|
+
emitResponsesToolArgumentEvents(state.res, buildResponsesSseItem(item, item.call_id), outputIndex, state.nextSeq);
|
|
1315
1537
|
writeSse(state.res, 'response.output_item.done', {
|
|
1316
1538
|
type: 'response.output_item.done',
|
|
1317
1539
|
output_index: outputIndex,
|
|
1318
|
-
item,
|
|
1540
|
+
item: buildResponsesSseItem(item, item.call_id),
|
|
1319
1541
|
sequence_number: state.nextSeq()
|
|
1320
1542
|
});
|
|
1321
1543
|
}
|
|
@@ -1485,6 +1707,8 @@ function streamChatCompletionsAsResponsesSse(targetUrl, options = {}) {
|
|
|
1485
1707
|
output: [],
|
|
1486
1708
|
messageItem: null,
|
|
1487
1709
|
messageText: '',
|
|
1710
|
+
reasoningItem: null,
|
|
1711
|
+
reasoningText: '',
|
|
1488
1712
|
toolCalls: [],
|
|
1489
1713
|
toolTypesByName: options.toolTypesByName || {},
|
|
1490
1714
|
finished: false,
|
|
@@ -2012,7 +2236,7 @@ function createOpenaiBridgeHttpHandler(options = {}) {
|
|
|
2012
2236
|
? { ok: false, status: 404, bodyText: '' }
|
|
2013
2237
|
: await retryTransientRequest(() => streamResponsesSse(upstreamResponsesUrl, {
|
|
2014
2238
|
method: 'POST',
|
|
2015
|
-
body: responsesRequest,
|
|
2239
|
+
body: normalizeResponsesPayloadForUpstream(responsesRequest, true),
|
|
2016
2240
|
headers: codexHeaders,
|
|
2017
2241
|
timeoutMs: streamTimeoutMs,
|
|
2018
2242
|
maxBytes: maxUpstreamBytes,
|