

























@@ -17,6 +17,7 @@ import {
1717DEFAULT_REASONING_ONLY_RETRY_LIMIT,
1818EMPTY_RESPONSE_RETRY_INSTRUCTION,
1919extractPlanningOnlyPlanDetails,
20+hasCommittedUserVisibleToolDelivery,
2021isLikelyExecutionAckPrompt,
2122PLANNING_ONLY_RETRY_INSTRUCTION,
2223REASONING_ONLY_RETRY_INSTRUCTION,
@@ -919,6 +920,73 @@ describe("runEmbeddedPiAgent incomplete-turn safety", () => {
919920expect(incompleteTurnText).toContain("verify before retrying");
920921});
921922923+it("does not treat empty committed messaging arrays as user-visible delivery", () => {
924+expect(
925+hasCommittedUserVisibleToolDelivery({
926+messagingToolSentTexts: [" "],
927+messagingToolSentMediaUrls: [],
928+}),
929+).toBe(false);
930+});
931+932+it("treats committed messaging media as user-visible delivery", () => {
933+expect(
934+hasCommittedUserVisibleToolDelivery({
935+messagingToolSentTexts: [],
936+messagingToolSentMediaUrls: ["file:///tmp/render.png"],
937+}),
938+).toBe(true);
939+});
940+941+it("treats committed messaging text as replay-invalid side effect metadata", () => {
942+expect(
943+buildAttemptReplayMetadata({
944+toolMetas: [],
945+didSendViaMessagingTool: false,
946+messagingToolSentTexts: ["Delivered through the message tool."],
947+messagingToolSentMediaUrls: [],
948+}),
949+).toEqual({ hadPotentialSideEffects: true, replaySafe: false });
950+});
951+952+it("treats committed messaging media as replay-invalid side effect metadata", () => {
953+expect(
954+buildAttemptReplayMetadata({
955+toolMetas: [],
956+didSendViaMessagingTool: false,
957+messagingToolSentTexts: [],
958+messagingToolSentMediaUrls: ["file:///tmp/render.png"],
959+}),
960+).toEqual({ hadPotentialSideEffects: true, replaySafe: false });
961+});
962+963+it("leaves committed delivery plus tool errors to the tool-error payload path", () => {
964+const incompleteTurnText = resolveIncompleteTurnPayloadText({
965+payloadCount: 0,
966+aborted: false,
967+timedOut: false,
968+attempt: makeAttemptResult({
969+assistantTexts: [],
970+didSendViaMessagingTool: true,
971+messagingToolSentTexts: ["Delivered through the message tool."],
972+lastToolError: {
973+toolName: "message",
974+meta: "send",
975+error: "delivery failed for second target",
976+},
977+lastAssistant: {
978+role: "assistant",
979+stopReason: "error",
980+provider: "openai",
981+model: "gpt-5.4",
982+content: [],
983+} as unknown as EmbeddedRunAttemptResult["lastAssistant"],
984+}),
985+});
986+987+expect(incompleteTurnText).toBeNull();
988+});
989+922990it("does not retry reasoning-only GPT turns after side effects", () => {
923991const retryInstruction = resolveReasoningOnlyRetryInstruction({
924992provider: "openai",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。