



























@@ -1400,6 +1400,26 @@ describe("runEmbeddedAgent incomplete-turn safety", () => {
14001400lastAssistant: { stopReason: "end_turn" },
14011401}),
14021402).toBe(false);
1403+expect(
1404+isIncompleteTerminalAssistantTurn({
1405+hasAssistantVisibleText: true,
1406+lastAssistant: { stopReason: "length" },
1407+}),
1408+).toBe(true);
1409+expect(
1410+isIncompleteTerminalAssistantTurn({
1411+hasAssistantVisibleText: true,
1412+hasTerminalOutput: true,
1413+lastAssistant: { stopReason: "length" },
1414+}),
1415+).toBe(false);
1416+expect(
1417+isIncompleteTerminalAssistantTurn({
1418+hasAssistantVisibleText: true,
1419+hasTerminalOutput: true,
1420+lastAssistant: { stopReason: "toolUse" },
1421+}),
1422+).toBe(true);
14031423});
1404142414051425it("surfaces no-visible-answer recovery for app-server interrupted tool-only output", () => {
@@ -2567,6 +2587,109 @@ describe("runEmbeddedAgent incomplete-turn safety", () => {
25672587expect(incompleteTurnText).toContain("couldn't generate a response");
25682588});
256925892590+it("surfaces incomplete-turn text for token-limited partial answers", () => {
2591+const incompleteTurnText = resolveIncompleteTurnPayloadText({
2592+payloadCount: 1,
2593+aborted: false,
2594+timedOut: false,
2595+attempt: makeAttemptResult({
2596+assistantTexts: ["Partial answer"],
2597+lastAssistant: {
2598+role: "assistant",
2599+stopReason: "length",
2600+provider: "ollama",
2601+model: "qwen3.5",
2602+content: [{ type: "text", text: "Partial answer" }],
2603+} as unknown as EmbeddedRunAttemptResult["lastAssistant"],
2604+}),
2605+});
2606+2607+expect(incompleteTurnText).toContain("couldn't generate a response");
2608+});
2609+2610+it("keeps complete visible stop turns successful", () => {
2611+const incompleteTurnText = resolveIncompleteTurnPayloadText({
2612+payloadCount: 1,
2613+aborted: false,
2614+timedOut: false,
2615+attempt: makeAttemptResult({
2616+assistantTexts: ["Complete answer"],
2617+lastAssistant: {
2618+role: "assistant",
2619+stopReason: "stop",
2620+provider: "ollama",
2621+model: "qwen3.5",
2622+content: [{ type: "text", text: "Complete answer" }],
2623+} as unknown as EmbeddedRunAttemptResult["lastAssistant"],
2624+}),
2625+});
2626+2627+expect(incompleteTurnText).toBeNull();
2628+});
2629+2630+it("preserves terminal tool media on token-limited turns", () => {
2631+const incompleteTurnText = resolveIncompleteTurnPayloadText({
2632+payloadCount: 1,
2633+aborted: false,
2634+timedOut: false,
2635+attempt: makeAttemptResult({
2636+assistantTexts: ["Partial answer"],
2637+toolMediaUrls: ["file:///tmp/render.png"],
2638+lastAssistant: {
2639+role: "assistant",
2640+stopReason: "length",
2641+provider: "ollama",
2642+model: "qwen3.5",
2643+content: [{ type: "text", text: "Partial answer" }],
2644+} as unknown as EmbeddedRunAttemptResult["lastAssistant"],
2645+}),
2646+});
2647+2648+expect(incompleteTurnText).toBeNull();
2649+});
2650+2651+it("preserves tool media already delivered through block replies", () => {
2652+const incompleteTurnText = resolveIncompleteTurnPayloadText({
2653+payloadCount: 1,
2654+aborted: false,
2655+timedOut: false,
2656+attempt: makeAttemptResult({
2657+assistantTexts: ["Partial answer"],
2658+hasToolMediaBlockReply: true,
2659+lastAssistant: {
2660+role: "assistant",
2661+stopReason: "length",
2662+provider: "ollama",
2663+model: "qwen3.5",
2664+content: [{ type: "text", text: "Partial answer" }],
2665+} as unknown as EmbeddedRunAttemptResult["lastAssistant"],
2666+}),
2667+});
2668+2669+expect(incompleteTurnText).toBeNull();
2670+});
2671+2672+it("preserves successful cron progress on token-limited turns", () => {
2673+const incompleteTurnText = resolveIncompleteTurnPayloadText({
2674+payloadCount: 1,
2675+aborted: false,
2676+timedOut: false,
2677+attempt: makeAttemptResult({
2678+assistantTexts: ["Partial answer"],
2679+successfulCronAdds: 1,
2680+lastAssistant: {
2681+role: "assistant",
2682+stopReason: "length",
2683+provider: "ollama",
2684+model: "qwen3.5",
2685+content: [{ type: "text", text: "Partial answer" }],
2686+} as unknown as EmbeddedRunAttemptResult["lastAssistant"],
2687+}),
2688+});
2689+2690+expect(incompleteTurnText).toBeNull();
2691+});
2692+25702693it.each([
25712694[
25722695"heartbeat responses",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。