

























@@ -642,6 +642,62 @@ describe("runEmbeddedPiAgent incomplete-turn safety", () => {
642642expect(mockedLog.warn).toHaveBeenCalledWith(expect.stringContaining("empty response detected"));
643643});
644644645+it("retries empty openai-compatible stop turns even when the backend reports output tokens", async () => {
646+mockedClassifyFailoverReason.mockReturnValue(null);
647+mockedRunEmbeddedAttempt.mockResolvedValueOnce(
648+makeAttemptResult({
649+assistantTexts: [],
650+lastAssistant: {
651+role: "assistant",
652+api: "openai-completions",
653+stopReason: "stop",
654+provider: "llamacpp",
655+model: "qwen3.6-27b",
656+content: [],
657+usage: {
658+input: 512,
659+output: 103,
660+cacheRead: 0,
661+cacheWrite: 0,
662+totalTokens: 615,
663+},
664+} as unknown as EmbeddedRunAttemptResult["lastAssistant"],
665+}),
666+);
667+mockedRunEmbeddedAttempt.mockResolvedValueOnce(
668+makeAttemptResult({
669+assistantTexts: ["Visible local answer."],
670+lastAssistant: {
671+role: "assistant",
672+api: "openai-completions",
673+stopReason: "stop",
674+provider: "llamacpp",
675+model: "qwen3.6-27b",
676+content: [{ type: "text", text: "Visible local answer." }],
677+usage: {
678+input: 640,
679+output: 5,
680+cacheRead: 0,
681+cacheWrite: 0,
682+totalTokens: 645,
683+},
684+} as unknown as EmbeddedRunAttemptResult["lastAssistant"],
685+}),
686+);
687+688+await runEmbeddedPiAgent({
689+ ...overflowBaseRunParams,
690+provider: "llamacpp",
691+model: "qwen3.6-27b",
692+runId: "run-empty-openai-compatible-stop-continuation",
693+});
694+695+expect(mockedRunEmbeddedAttempt).toHaveBeenCalledTimes(2);
696+const secondCall = mockedRunEmbeddedAttempt.mock.calls[1]?.[0] as { prompt?: string };
697+expect(secondCall.prompt).toContain(EMPTY_RESPONSE_RETRY_INSTRUCTION);
698+expect(mockedLog.warn).toHaveBeenCalledWith(expect.stringContaining("empty response detected"));
699+});
700+645701it("surfaces an error after exhausting empty-response retries", async () => {
646702mockedClassifyFailoverReason.mockReturnValue(null);
647703mockedRunEmbeddedAttempt.mockResolvedValue(
@@ -1426,6 +1482,30 @@ describe("runEmbeddedPiAgent incomplete-turn safety", () => {
14261482expect(retryInstruction).toBeNull();
14271483});
142814841485+it("detects empty openai-compatible stop turns with non-zero output usage", () => {
1486+const retryInstruction = resolveEmptyResponseRetryInstruction({
1487+provider: "llamacpp",
1488+modelId: "qwen3.6-27b",
1489+modelApi: "openai-completions",
1490+payloadCount: 0,
1491+aborted: false,
1492+timedOut: false,
1493+attempt: makeAttemptResult({
1494+assistantTexts: [],
1495+lastAssistant: {
1496+role: "assistant",
1497+stopReason: "stop",
1498+provider: "llamacpp",
1499+model: "qwen3.6-27b",
1500+content: [],
1501+usage: { input: 512, output: 103, totalTokens: 615 },
1502+} as unknown as EmbeddedRunAttemptResult["lastAssistant"],
1503+}),
1504+});
1505+1506+expect(retryInstruction).toBe(EMPTY_RESPONSE_RETRY_INSTRUCTION);
1507+});
1508+14291509it("detects generic empty GPT turns without visible text", () => {
14301510const retryInstruction = resolveEmptyResponseRetryInstruction({
14311511provider: "openai",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。