fix(grok): 修正流式响应中Claude协议转换逻辑并提取为独立方法
重构GrokConverter中的Claude流式转换逻辑,将原先内联的复杂分支提取为独立的toClaudeStreamChunk方法,提高代码可维护性。同时调整grok-core.js中usage payload的附加时机,确保在响应存在时才附加估算数据。
This commit is contained in:
parent
0818e608cf
commit
0654d9330b
3 changed files with 55 additions and 51 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
2.13.5.1
|
2.13.6
|
||||||
|
|
|
||||||
|
|
@ -467,48 +467,8 @@ export class GrokConverter extends BaseConverter {
|
||||||
return this.toOpenAIResponsesStreamChunk(chunk, model);
|
return this.toOpenAIResponsesStreamChunk(chunk, model);
|
||||||
case MODEL_PROTOCOL_PREFIX.CODEX:
|
case MODEL_PROTOCOL_PREFIX.CODEX:
|
||||||
return this.toCodexStreamChunk(chunk, model);
|
return this.toCodexStreamChunk(chunk, model);
|
||||||
case MODEL_PROTOCOL_PREFIX.CLAUDE: {
|
case MODEL_PROTOCOL_PREFIX.CLAUDE:
|
||||||
const openaiPieces = this.toOpenAIStreamChunk(chunk, model);
|
return this.toClaudeStreamChunk(chunk, model, requestId);
|
||||||
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);
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
@ -1424,6 +1384,54 @@ export class GrokConverter extends BaseConverter {
|
||||||
return codexChunks.length > 0 ? codexChunks : null;
|
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模型列表
|
* Grok模型列表 -> OpenAI模型列表
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1348,15 +1348,11 @@ export class GrokApiService {
|
||||||
if (dataStr === '[DONE]') break;
|
if (dataStr === '[DONE]') break;
|
||||||
try {
|
try {
|
||||||
const json = JSON.parse(dataStr);
|
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 (json.result?.response) {
|
||||||
|
if (requestBody && !grokStreamUsagePayloadAttached) {
|
||||||
|
attachGrokUsageEstimatePayload(json.result, requestBody);
|
||||||
|
grokStreamUsagePayloadAttached = true;
|
||||||
|
}
|
||||||
const resp = json.result.response;
|
const resp = json.result.response;
|
||||||
resp._requestBaseUrl = reqBaseUrl;
|
resp._requestBaseUrl = reqBaseUrl;
|
||||||
resp._uuid = this.uuid;
|
resp._uuid = this.uuid;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue