fix(grok): 修正流式响应中Claude协议转换逻辑并提取为独立方法

重构GrokConverter中的Claude流式转换逻辑,将原先内联的复杂分支提取为独立的toClaudeStreamChunk方法,提高代码可维护性。同时调整grok-core.js中usage payload的附加时机,确保在响应存在时才附加估算数据。
This commit is contained in:
hex2077 2026-04-11 19:50:40 +08:00
parent 0818e608cf
commit 0654d9330b
3 changed files with 55 additions and 51 deletions

View file

@ -1 +1 @@
2.13.5.1
2.13.6

View file

@ -467,48 +467,8 @@ export class GrokConverter extends BaseConverter {
return this.toOpenAIResponsesStreamChunk(chunk, model);
case MODEL_PROTOCOL_PREFIX.CODEX:
return this.toCodexStreamChunk(chunk, model);
case MODEL_PROTOCOL_PREFIX.CLAUDE: {
const openaiPieces = this.toOpenAIStreamChunk(chunk, model);
if (!openaiPieces) return null;
const key = requestId || '_';
const openaiConverter = ConverterFactory.getConverter(MODEL_PROTOCOL_PREFIX.OPENAI);
const pieces = Array.isArray(openaiPieces) ? openaiPieces : [openaiPieces];
const out = [];
for (const p of pieces) {
const events = openaiConverter.toClaudeStreamChunk(p, model);
if (!events) continue;
const arr = Array.isArray(events) ? events : [events];
for (const ev of arr) {
if (!this._claudeMsgStartSent.get(key)) {
this._claudeMsgStartSent.set(key, true);
const msgId = `msg_${String(p.id || uuidv4()).replace(/^chatcmpl-/, '')}`;
out.push({
type: 'message_start',
message: {
id: msgId,
type: 'message',
role: 'assistant',
content: [],
model: model || p.model || 'unknown',
stop_reason: null,
stop_sequence: null,
usage: {
input_tokens: 0,
output_tokens: 0,
cache_creation_input_tokens: 0,
cache_read_input_tokens: 0
}
}
});
}
out.push(ev);
}
}
if (chunk?.result?.response?.isDone) {
this._claudeMsgStartSent.delete(key);
}
return out.length === 0 ? null : (out.length === 1 ? out[0] : out);
}
case MODEL_PROTOCOL_PREFIX.CLAUDE:
return this.toClaudeStreamChunk(chunk, model, requestId);
default:
return chunk;
}
@ -1424,6 +1384,54 @@ export class GrokConverter extends BaseConverter {
return codexChunks.length > 0 ? codexChunks : null;
}
toClaudeStreamChunk(chunk, model, requestId) {
const openaiPieces = this.toOpenAIStreamChunk(chunk, model);
if (!openaiPieces) return null;
const key = requestId || '_';
const openaiConverter = ConverterFactory.getConverter(MODEL_PROTOCOL_PREFIX.OPENAI);
const pieces = Array.isArray(openaiPieces) ? openaiPieces : [openaiPieces];
const out = [];
for (const p of pieces) {
const events = openaiConverter.toClaudeStreamChunk(p, model);
if (!events) continue;
const arr = Array.isArray(events) ? events : [events];
for (const ev of arr) {
if (!this._claudeMsgStartSent.get(key)) {
this._claudeMsgStartSent.set(key, true);
const msgId = `msg_${String(p.id || uuidv4()).replace(/^chatcmpl-/, '')}`;
out.push({
type: 'message_start',
message: {
id: msgId,
type: 'message',
role: 'assistant',
content: [],
model: model || p.model || 'unknown',
stop_reason: null,
stop_sequence: null,
usage: {
input_tokens: 0,
output_tokens: 0,
cache_creation_input_tokens: 0,
cache_read_input_tokens: 0
}
}
});
}
out.push(ev);
}
}
if (chunk?.result?.response?.isDone) {
this._claudeMsgStartSent.delete(key);
}
return out.length === 0 ? null : (out.length === 1 ? out[0] : out);
}
/**
* Grok模型列表 -> OpenAI模型列表
*/

View file

@ -1348,15 +1348,11 @@ export class GrokApiService {
if (dataStr === '[DONE]') break;
try {
const json = JSON.parse(dataStr);
if (json.result && requestBody && !grokStreamUsagePayloadAttached) {
json.result._grokUsageEstimatePayload = {
promptText: requestBody.message || "",
toolsJson: requestBody.tools && Array.isArray(requestBody.tools) && requestBody.tools.length
? JSON.stringify(requestBody.tools) : ""
};
grokStreamUsagePayloadAttached = true;
}
if (json.result?.response) {
if (requestBody && !grokStreamUsagePayloadAttached) {
attachGrokUsageEstimatePayload(json.result, requestBody);
grokStreamUsagePayloadAttached = true;
}
const resp = json.result.response;
resp._requestBaseUrl = reqBaseUrl;
resp._uuid = this.uuid;