(text: string, hasTools: boolean)
| 547 | * 2. 已恢复出的工具调用明显属于大参数写入类,需要继续补全内容 |
| 548 | */ |
| 549 | export function shouldAutoContinueTruncatedToolResponse(text: string, hasTools: boolean): boolean { |
| 550 | if (!hasTools) return false; |
| 551 | |
| 552 | if (!isTruncated(text)) { |
| 553 | if (!hasToolCalls(text)) return false; |
| 554 | |
| 555 | const { toolCalls } = parseToolCalls(text); |
| 556 | if (toolCalls.length === 0) return false; |
| 557 | |
| 558 | return toolCalls.some(toolCallLooksSemanticallyIncomplete); |
| 559 | } |
| 560 | |
| 561 | // ★ json action 块未闭合是最精确的截断信号,不受长度限制影响 |
| 562 | // isTruncated 在有 json action 块时 early return:全闭合→false,未闭合→true |
| 563 | // 所以此处 isTruncated=true 且有开标签,必然意味着 action 块未闭合,无需重复计数 |
| 564 | const hasUnclosedActionBlock = (text.match(/```json\s+action/g) || []).length > 0; |
| 565 | // 响应过短(< 200 chars)时不触发续写:上下文不足会导致模型拒绝或错误续写 |
| 566 | // 例外:json action 块明确未闭合时跳过此检查(thinking 剥离后正文可能很短) |
| 567 | if (!hasUnclosedActionBlock && text.trim().length < 200) return false; |
| 568 | if (!hasToolCalls(text)) return true; |
| 569 | |
| 570 | const { toolCalls } = parseToolCalls(text); |
| 571 | if (toolCalls.length === 0) return true; |
| 572 | |
| 573 | return toolCalls.some(toolCallNeedsMoreContinuation); |
| 574 | } |
| 575 | |
| 576 | // ==================== 续写辅助 ==================== |
| 577 |
no test coverage detected