Skip to content

Commit 3ce4a87

Browse files
vincentkocpashpashpash
authored andcommitted
fix(agents): preserve rich internal source replies
1 parent 411458d commit 3ce4a87

2 files changed

Lines changed: 62 additions & 3 deletions

File tree

src/agents/pi-embedded-runner/run/payloads.test.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { AssistantMessage } from "@earendil-works/pi-ai";
22
import { describe, expect, it } from "vitest";
33
import { getReplyPayloadMetadata } from "../../../auto-reply/reply-payload.js";
4+
import type { InteractiveReply, MessagePresentation } from "../../../interactive/payload.js";
45
import {
56
buildPayloads,
67
expectSinglePayloadText,
@@ -172,6 +173,64 @@ describe("buildEmbeddedRunPayloads tool-error warnings", () => {
172173
});
173174
});
174175

176+
it("preserves rich-only internal message-tool source replies", () => {
177+
const presentation = {
178+
blocks: [
179+
{
180+
type: "buttons",
181+
buttons: [{ label: "Approve", value: "approve" }],
182+
},
183+
],
184+
} satisfies MessagePresentation;
185+
const interactive = {
186+
blocks: [
187+
{
188+
type: "buttons",
189+
buttons: [{ label: "Open", value: "open" }],
190+
},
191+
],
192+
} satisfies InteractiveReply;
193+
194+
const payloads = buildPayloads({
195+
assistantTexts: ["ordinary final should stay private"],
196+
didSendViaMessagingTool: true,
197+
messagingToolSourceReplyPayloads: [
198+
{
199+
presentation,
200+
},
201+
{
202+
interactive,
203+
},
204+
],
205+
sourceReplyDeliveryMode: "message_tool_only",
206+
sessionKey: "agent:main",
207+
agentId: "main",
208+
runId: "run-1",
209+
});
210+
211+
expect(payloads).toHaveLength(2);
212+
expect(payloads[0]).toMatchObject({ presentation });
213+
expect(payloads[0]?.text).toBeUndefined();
214+
expect(payloads[1]).toMatchObject({ interactive });
215+
expect(payloads[1]?.text).toBeUndefined();
216+
expect(getReplyPayloadMetadata(payloads[0] as object)).toMatchObject({
217+
deliverDespiteSourceReplySuppression: true,
218+
sourceReplyTranscriptMirror: {
219+
sessionKey: "agent:main",
220+
agentId: "main",
221+
idempotencyKey: "run-1:internal-source-reply:0",
222+
},
223+
});
224+
expect(getReplyPayloadMetadata(payloads[1] as object)).toMatchObject({
225+
deliverDespiteSourceReplySuppression: true,
226+
sourceReplyTranscriptMirror: {
227+
sessionKey: "agent:main",
228+
agentId: "main",
229+
idempotencyKey: "run-1:internal-source-reply:1",
230+
},
231+
});
232+
});
233+
175234
it("ignores accumulated internal/status text after the final answer", () => {
176235
const payloads = buildPayloads({
177236
assistantTexts: [

src/agents/pi-embedded-runner/run/payloads.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { AssistantMessage } from "@earendil-works/pi-ai";
2-
import { hasOutboundReplyContent } from "openclaw/plugin-sdk/reply-payload";
32
import type { SourceReplyDeliveryMode } from "../../../auto-reply/get-reply-options.types.js";
43
import {
54
createHeartbeatToolResponsePayload,
@@ -16,6 +15,7 @@ import type { ReasoningLevel, ThinkLevel, VerboseLevel } from "../../../auto-rep
1615
import { isSilentReplyPayloadText, SILENT_REPLY_TOKEN } from "../../../auto-reply/tokens.js";
1716
import { formatToolAggregate } from "../../../auto-reply/tool-meta.js";
1817
import type { OpenClawConfig } from "../../../config/types.openclaw.js";
18+
import { hasReplyPayloadContent } from "../../../interactive/payload.js";
1919
import { isCronSessionKey } from "../../../routing/session-key.js";
2020
import { extractAssistantTextForPhase } from "../../../shared/chat-message-content.js";
2121
import {
@@ -568,15 +568,15 @@ export function buildEmbeddedRunPayloads(params: {
568568
if (payload.text && isSilentReplyPayloadText(payload.text, SILENT_REPLY_TOKEN)) {
569569
const silentText = payload.text;
570570
payload.text = undefined;
571-
if (hasOutboundReplyContent(payload)) {
571+
if (hasReplyPayloadContent(payload)) {
572572
return payload;
573573
}
574574
payload.text = silentText;
575575
}
576576
return payload;
577577
})
578578
.filter((p) => {
579-
if (!hasOutboundReplyContent(p)) {
579+
if (!hasReplyPayloadContent(p)) {
580580
return false;
581581
}
582582
if (p.text && isSilentReplyPayloadText(p.text, SILENT_REPLY_TOKEN)) {

0 commit comments

Comments
 (0)