()
| 272 | // 预算 / 轮数用尽时的「收尾轮」:禁用工具,逼模型基于已读内容出【ANSWER】, |
| 273 | // 而不是停在「半截工具调用、没有答案」(budget_exceeded 旧行为)。只跑一次。 |
| 274 | async function* finalizeWithoutTools(): AsyncGenerator<AgentEvent> { |
| 275 | const finMsgs: ChatMessage[] = [ |
| 276 | ...messages, |
| 277 | { role: "user", text: BUDGET_FINALIZE_PROMPT }, |
| 278 | ]; |
| 279 | let finText = ""; |
| 280 | let finEnd: AgentEvent | null = null; |
| 281 | for await (const evt of provider.runTurn({ |
| 282 | model, |
| 283 | system, |
| 284 | messages: finMsgs, |
| 285 | disable_tools: true, |
| 286 | signal: input.signal, |
| 287 | })) { |
| 288 | if (evt.kind === "text-delta") { |
| 289 | finText += evt.text; |
| 290 | totalAssistantText += evt.text; |
| 291 | yield evt; |
| 292 | } else if (evt.kind === "turn-end") { |
| 293 | finEnd = evt; |
| 294 | } else if (evt.kind === "tool-call") { |
| 295 | // 工具已禁用,正常不会触发;防御性忽略,避免悬空 tool_call |
| 296 | } else { |
| 297 | yield evt; |
| 298 | } |
| 299 | } |
| 300 | if (finText) { |
| 301 | messages = [...finMsgs, { role: "assistant", text: finText }]; |
| 302 | } |
| 303 | const allText = gatherAssistantText(messages); |
| 304 | if (allText) yield* validateAnswerRefs(allText); |
| 305 | yield finEnd ?? { kind: "turn-end", reason: "stop" }; |
| 306 | } |
| 307 | |
| 308 | while (turnIdx < MAX_TURNS) { |
| 309 | if (input.signal?.aborted) { |
no test coverage detected