From 8456f64615b893afdebd49c142af3e81fed7319d Mon Sep 17 00:00:00 2001 From: hex2077 Date: Wed, 4 Mar 2026 15:26:53 +0800 Subject: [PATCH] =?UTF-8?q?fix(CodexConverter):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=B5=81=E5=BC=8F=E5=93=8D=E5=BA=94=E4=B8=AD=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E4=B8=8E=E7=8A=B6=E6=80=81=E4=B8=8D=E5=8C=B9=E9=85=8D=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 当 Codex 增量事件缺少 response.id 时,现在会智能选择最近活跃的流状态进行归并,避免使用固定 "default" key 导致状态污染。同时为流状态添加最后更新时间戳,并维护最近响应ID的引用,确保流式转换的准确性和稳定性。 --- VERSION | 2 +- src/converters/strategies/CodexConverter.js | 33 +++++++++++++++++++-- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/VERSION b/VERSION index 7fcd83f..1f6fb3d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.10.5.2 +2.10.5.3 diff --git a/src/converters/strategies/CodexConverter.js b/src/converters/strategies/CodexConverter.js index 23e49c0..5d341e3 100644 --- a/src/converters/strategies/CodexConverter.js +++ b/src/converters/strategies/CodexConverter.js @@ -1126,8 +1126,29 @@ export class CodexConverter extends BaseConverter { */ toClaudeStreamChunk(chunk, model) { const type = chunk.type; - const resId = chunk.response?.id || 'default'; - + + // Codex 的多数增量事件不带 response.id,需要将其归并到最近活跃的流状态。 + let resId = chunk.response?.id; + if (!resId) { + if (this.lastClaudeStreamResponseId && this.streamParams.has(this.lastClaudeStreamResponseId)) { + resId = this.lastClaudeStreamResponseId; + } else if (this.streamParams.size === 1) { + resId = this.streamParams.keys().next().value; + } else { + // 兜底:选择最近更新的流,避免落到固定 "default" key 导致串流状态污染。 + let latestKey = null; + let latestUpdatedAt = -1; + for (const [key, streamState] of this.streamParams.entries()) { + const updatedAt = streamState?.lastUpdatedAt || 0; + if (updatedAt > latestUpdatedAt) { + latestUpdatedAt = updatedAt; + latestKey = key; + } + } + resId = latestKey || 'default'; + } + } + if (!this.streamParams.has(resId)) { this.streamParams.set(resId, { model: model, @@ -1135,13 +1156,16 @@ export class CodexConverter extends BaseConverter { responseID: resId, blockIndex: 0, blockStarted: false, // track whether content_block_start has been sent for current block - currentBlockType: null // 'thinking' or 'text' + currentBlockType: null, // 'thinking' or 'text' + lastUpdatedAt: Date.now() }); } const state = this.streamParams.get(resId); + state.lastUpdatedAt = Date.now(); if (type === 'response.created') { state.responseID = chunk.response.id; + this.lastClaudeStreamResponseId = state.responseID; return { type: "message_start", message: { @@ -1262,6 +1286,9 @@ export class CodexConverter extends BaseConverter { { type: "message_stop" } ); this.streamParams.delete(resId); + if (this.lastClaudeStreamResponseId === resId) { + this.lastClaudeStreamResponseId = null; + } return events; }