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.
@@ -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, 'max_tokens')) {
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: { ...item, id: itemId }
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: { ...item, id: itemId },
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: { ...payload, stream: true },
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: { ...payload, stream: false }
2245
+ body: normalizeResponsesPayloadForUpstream(payload, false)
2035
2246
  });
2036
2247
 
2037
2248
  // 优先走上游 /responses(如果支持)。若上游报错且不是“端点不支持”,则直接透传错误。
@@ -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
- status: 'completed',
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: { ...item, id: itemId }
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: { ...item, id: itemId },
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 toUpstreamNonStreamingResponsesPayload(payload) {
1151
+ function normalizeResponsesPayloadForUpstream(payload, stream) {
1087
1152
  const body = payload && typeof payload === 'object' ? payload : {};
1088
- const normalized = { ...body, stream: false };
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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codexmate",
3
- "version": "0.0.53",
3
+ "version": "0.0.54",
4
4
  "description": "Codex/Claude Code/OpenClaw 配置、会话与任务编排 CLI + Web 工具",
5
5
  "main": "cli.js",
6
6
  "bin": {