Skip to content

Commit cf4000b

Browse files
committed
fix(gateway): preserve slash command media replies
1 parent 85ebbec commit cf4000b

3 files changed

Lines changed: 1238 additions & 146 deletions

File tree

src/gateway/gateway-trajectory-export.live.test.ts

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { afterEach, describe, expect, it } from "vitest";
66
import type { EventFrame } from "../../packages/gateway-protocol/src/index.js";
77
import { isLiveTestEnabled } from "../agents/live-test-helpers.js";
88
import type { OpenClawConfig } from "../config/config.js";
9-
import { extractFirstTextBlock } from "../shared/chat-message-content.js";
109
import { GatewayClient } from "./client.js";
1110
import {
1211
connectTestGatewayClient,
@@ -215,10 +214,34 @@ function extractChatFinalText(event: EventFrame, runId: string): string | undefi
215214
if (!message || typeof message !== "object") {
216215
return undefined;
217216
}
218-
const messageRecord = message as { text?: unknown };
219-
return typeof messageRecord.text === "string"
220-
? messageRecord.text
221-
: extractFirstTextBlock(message);
217+
return extractVisibleMessageText(message);
218+
}
219+
220+
function extractVisibleMessageText(message: unknown): string | undefined {
221+
if (!message || typeof message !== "object") {
222+
return undefined;
223+
}
224+
const record = message as { text?: unknown; content?: unknown };
225+
if (typeof record.text === "string" && record.text.trim()) {
226+
return record.text;
227+
}
228+
if (typeof record.content === "string" && record.content.trim()) {
229+
return record.content;
230+
}
231+
if (!Array.isArray(record.content)) {
232+
return undefined;
233+
}
234+
const text = record.content
235+
.map((block) => {
236+
if (!block || typeof block !== "object") {
237+
return "";
238+
}
239+
const entry = block as { type?: unknown; text?: unknown };
240+
return entry.type === "text" && typeof entry.text === "string" ? entry.text : "";
241+
})
242+
.filter((value) => value.trim())
243+
.join("\n");
244+
return text || undefined;
222245
}
223246

224247
async function approveTrajectoryExport(client: GatewayClient): Promise<string> {
@@ -231,7 +254,7 @@ async function approveTrajectoryExport(client: GatewayClient): Promise<string> {
231254
};
232255
}
233256
| undefined;
234-
let lastApprovalCommands: string[] = [];
257+
let lastApprovalSummaries: Array<{ id?: string; hasTrajectoryExportCommand: boolean }> = [];
235258
while (Date.now() - startedAt < 60_000) {
236259
const approvals = (await client.request(
237260
"exec.approval.list",
@@ -243,9 +266,12 @@ async function approveTrajectoryExport(client: GatewayClient): Promise<string> {
243266
command?: string;
244267
};
245268
}>;
246-
lastApprovalCommands = approvals
247-
.map((entry) => entry.request?.command)
248-
.filter((command): command is string => typeof command === "string");
269+
lastApprovalSummaries = approvals.map((entry) => ({
270+
...(entry.id ? { id: entry.id } : {}),
271+
hasTrajectoryExportCommand: Boolean(
272+
entry.request?.command?.includes("sessions export-trajectory"),
273+
),
274+
}));
249275
approval = approvals.find((entry) =>
250276
entry.request?.command?.includes("sessions export-trajectory"),
251277
);
@@ -258,7 +284,7 @@ async function approveTrajectoryExport(client: GatewayClient): Promise<string> {
258284
}
259285
if (!approval?.id) {
260286
throw new Error(
261-
`expected trajectory export approval id; approvals=${JSON.stringify(lastApprovalCommands)}`,
287+
`expected trajectory export approval id; approvals=${JSON.stringify(lastApprovalSummaries)}`,
262288
);
263289
}
264290
expect(approval.request?.command).toContain("sessions export-trajectory");
@@ -387,7 +413,7 @@ describeLive("gateway live trajectory export", () => {
387413
).toBe(true);
388414
const finalText =
389415
typeof exportResponse?.message === "object"
390-
? extractFirstTextBlock(exportResponse.message)
416+
? extractVisibleMessageText(exportResponse.message)
391417
: await waitForTrajectoryExportInstructionText({
392418
events: gatewayEvents,
393419
expectedText: "Trajectory exports can include",

0 commit comments

Comments
 (0)