@@ -204,22 +204,24 @@ export class QwenApi implements LLMApi {
204204 return { isThinking : false , content : "[解析响应错误]" } ;
205205 }
206206
207- // --- 加入这个关键的检查 ---
208- // 检查 json 对象是否存在,以及它是否包含 output 和 output .choices
209- if ( ! json || typeof json . output !== 'object' || ! Array . isArray ( json . output . choices ) ) {
210- // 如果没有 output .choices,就打印一个警告(方便调试,看看是啥样的块)
211- console . warn ( "收到的SSE块没有预期的 output. choices 结构:" , json ) ;
207+ // --- 修改这里的检查逻辑 ---
208+ // 现在我们直接检查 json.choices 是否是一个数组
209+ if ( ! json || ! Array . isArray ( json . choices ) ) {
210+ // 如果没有 json .choices,打印日志并检查是否是错误或结束块
211+ console . warn ( "收到的SSE块没有预期的 choices 结构 (直接在顶层) :" , json ) ;
212212
213- // 这里可以进一步判断:
214- // 1. 是否是包含错误信息的块?
215213 if ( json . code && json . message ) {
216214 console . error ( "DashScope API 流式传输错误:" , json ) ;
217- return { isThinking : false , content : `[API错误: ${ json . message } ]` } ; // 可以显示错误信息
215+ return { isThinking : false , content : `[API错误: ${ json . message } ]` } ;
216+ }
217+ // 你可以检查是否有 usage 字段来判断是否是结束块
218+ if ( json . usage ) {
219+ console . log ( "收到包含 usage 的结束块:" , json ) ;
220+ // 这里通常可以安全返回空,表示内容流结束
221+ return { isThinking : false , content : "" } ;
218222 }
219- // 2. 是否是包含使用量(usage)的结束块?(如果需要处理usage可以在这里加逻辑)
220- // if (json.usage) { ... }
221223
222- // 如果都不是,就认为它是一个非内容块(比如结束信号),安全地返回空内容
224+ // 其他未知结构,也返回空
223225 return { isThinking : false , content : "" } ;
224226 }
225227 // --- 检查结束 ---
@@ -228,12 +230,20 @@ export class QwenApi implements LLMApi {
228230
229231
230232
231- const choices = json . output . choices as Array < {
233+ //const choices = json.output.choices as Array<{
234+ const choices = json . choices as Array < {
232235 message : {
233236 content : string | null | MultimodalContentForAlibaba [ ] ;
234237 tool_calls : ChatMessageTool [ ] ;
235238 reasoning_content : string | null ;
236239 } ;
240+ delta ?: { // 兼容 delta 结构
241+ content ?: string | null ;
242+ tool_calls ?: ChatMessageTool [ ] ;
243+ reasoning_content ?: string | null ;
244+
245+ } ;
246+ finish_reason ?: string ; // 结束原因
237247 } > ;
238248
239249
@@ -246,11 +256,40 @@ export class QwenApi implements LLMApi {
246256
247257
248258
249- if ( ! choices ?. length ) return { isThinking : false , content : "" } ;
259+ if ( ! choices ?. length ) return {
260+ console. log ( "收到的SSE块 choices 数组为空:" , json ) ;
261+ isThinking: false , content : "" };
262+
263+
264+
265+ // --- 从 choices[0] 中提取信息 ---
266+ // 需要同时考虑 message 和 delta 两种可能的结构
267+ const firstChoice = choices [ 0 ] ;
268+ const message = firstChoice . message ;
269+ const delta = firstChoice . delta ;
270+
271+ // 优先从 delta 获取,其次从 message 获取(流式响应通常用 delta)
272+ const tool_calls = delta ?. tool_calls ?? message ?. tool_calls ;
273+ const reasoning = delta ?. reasoning_content ?? message ?. reasoning_content ;
274+ let content = delta ?. content ?? message ?. content ; // content 可能是字符串或数组
275+
276+
277+
278+
279+
250280
251- const tool_calls = choices [ 0 ] ?. message ?. tool_calls ;
281+
282+ //const tool_calls = choices[0]?.message?.tool_calls;
252283 if ( tool_calls ?. length > 0 ) {
253- const index = tool_calls [ 0 ] ?. index ;
284+ //const index = tool_calls[0]?.index;
285+
286+
287+ const toolCall = tool_calls [ 0 ] ; // 假设每次只处理一个 tool call chunk
288+ const index = ( toolCall as any ) . index ; // DashScope 可能有 index
289+
290+
291+
292+
254293 const id = tool_calls [ 0 ] ?. id ;
255294 const args = tool_calls [ 0 ] ?. function ?. arguments ;
256295 if ( id ) {
@@ -283,6 +322,14 @@ export class QwenApi implements LLMApi {
283322 } ;
284323 }
285324
325+ // 检查 finish_reason,如果是 'tool_calls',说明是工具调用结束,可能没有 content
326+ if ( firstChoice . finish_reason === "tool_calls" ) {
327+ console . log ( "收到 tool_calls 结束标记" ) ;
328+ return { isThinking : false , content : "" } ;
329+ }
330+
331+
332+
286333 if ( reasoning && reasoning . length > 0 ) {
287334 return {
288335 isThinking : true ,
0 commit comments