@@ -715,6 +715,48 @@ describe("chat directive tag stripping for non-streaming final payloads", () =>
|
715 | 715 | ); |
716 | 716 | }); |
717 | 717 | |
| 718 | +it("does not persist agent media supplements when no playable media resolves", async () => { |
| 719 | +const transcriptDir = createTranscriptFixture("openclaw-chat-send-agent-stale-tts-"); |
| 720 | +const staleAudioPath = path.join(transcriptDir, "stale.mp3"); |
| 721 | +mockState.config = { |
| 722 | +agents: { |
| 723 | +defaults: { |
| 724 | +workspace: transcriptDir, |
| 725 | +}, |
| 726 | +}, |
| 727 | +}; |
| 728 | +mockState.triggerAgentRunStart = true; |
| 729 | +mockState.dispatchedReplies = [ |
| 730 | +{ |
| 731 | +kind: "final", |
| 732 | +payload: { |
| 733 | +text: "Text-only test: one clean reply, no TTS, no media, no tool narration.", |
| 734 | +mediaUrl: staleAudioPath, |
| 735 | +mediaUrls: [staleAudioPath], |
| 736 | +trustedLocalMedia: true, |
| 737 | +}, |
| 738 | +}, |
| 739 | +]; |
| 740 | +const respond = vi.fn(); |
| 741 | +const context = createChatContext(); |
| 742 | + |
| 743 | +await runNonStreamingChatSend({ |
| 744 | + context, |
| 745 | + respond, |
| 746 | +idempotencyKey: "idem-stale-agent-media", |
| 747 | +expectBroadcast: false, |
| 748 | +waitFor: "dedupe", |
| 749 | +}); |
| 750 | + |
| 751 | +const assistantUpdates = mockState.emittedTranscriptUpdates.filter( |
| 752 | +(update) => |
| 753 | +typeof update.message === "object" && |
| 754 | +update.message !== null && |
| 755 | +(update.message as { role?: unknown }).role === "assistant", |
| 756 | +); |
| 757 | +expect(assistantUpdates).toEqual([]); |
| 758 | +}); |
| 759 | + |
718 | 760 | it("keeps visible text on non-agent TTS final media because no model transcript exists", async () => { |
719 | 761 | const transcriptDir = createTranscriptFixture("openclaw-chat-send-command-tts-final-"); |
720 | 762 | const audioPath = path.join(transcriptDir, "tts.mp3"); |
|