mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 17:44:45 +00:00
fix: track message attachment aliases
This commit is contained in:
@@ -320,6 +320,45 @@ describe("createCodexDynamicToolBridge", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("records message tool media attachment aliases as delivery evidence", async () => {
|
||||
const toolResult = {
|
||||
content: [{ type: "text", text: "Sent." }],
|
||||
details: { messageId: "message-1" },
|
||||
} satisfies AgentToolResult<unknown>;
|
||||
const tool = createTool({
|
||||
name: "message",
|
||||
execute: vi.fn(async () => toolResult),
|
||||
});
|
||||
const bridge = createCodexDynamicToolBridge({
|
||||
tools: [tool],
|
||||
signal: new AbortController().signal,
|
||||
});
|
||||
|
||||
const result = await handleMessageToolCall(bridge, {
|
||||
action: "send",
|
||||
text: "song attached",
|
||||
media: "/tmp/generated-song.mp3",
|
||||
attachments: [{ filePath: "/tmp/generated-cover.png" }],
|
||||
});
|
||||
|
||||
expect(result).toEqual(expectInputText("Sent."));
|
||||
expect(bridge.telemetry.didSendViaMessagingTool).toBe(true);
|
||||
expect(bridge.telemetry.messagingToolSentMediaUrls).toEqual([
|
||||
"/tmp/generated-song.mp3",
|
||||
"/tmp/generated-cover.png",
|
||||
]);
|
||||
expect(bridge.telemetry.messagingToolSentTargets).toEqual([
|
||||
{
|
||||
tool: "message",
|
||||
provider: "message",
|
||||
to: undefined,
|
||||
threadId: undefined,
|
||||
text: "song attached",
|
||||
mediaUrls: ["/tmp/generated-song.mp3", "/tmp/generated-cover.png"],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("records internal UI source replies separately from outbound messaging evidence", async () => {
|
||||
const toolResult = textToolResult("Sent to current chat.", {
|
||||
status: "ok",
|
||||
|
||||
@@ -417,11 +417,32 @@ function readFirstString(record: Record<string, unknown>, keys: string[]): strin
|
||||
|
||||
function collectMediaUrls(record: Record<string, unknown>): string[] {
|
||||
const urls: string[] = [];
|
||||
for (const key of ["mediaUrl", "media_url", "imageUrl", "image_url"]) {
|
||||
const value = record[key];
|
||||
const pushMediaUrl = (value: unknown) => {
|
||||
if (typeof value === "string" && value.trim()) {
|
||||
urls.push(value.trim());
|
||||
}
|
||||
};
|
||||
const pushAttachment = (value: unknown) => {
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
||||
return;
|
||||
}
|
||||
const attachment = value as Record<string, unknown>;
|
||||
for (const key of ["media", "mediaUrl", "path", "filePath", "fileUrl"]) {
|
||||
pushMediaUrl(attachment[key]);
|
||||
}
|
||||
};
|
||||
for (const key of [
|
||||
"media",
|
||||
"mediaUrl",
|
||||
"media_url",
|
||||
"path",
|
||||
"filePath",
|
||||
"fileUrl",
|
||||
"imageUrl",
|
||||
"image_url",
|
||||
]) {
|
||||
const value = record[key];
|
||||
pushMediaUrl(value);
|
||||
}
|
||||
for (const key of ["mediaUrls", "media_urls", "imageUrls", "image_urls"]) {
|
||||
const value = record[key];
|
||||
@@ -429,9 +450,13 @@ function collectMediaUrls(record: Record<string, unknown>): string[] {
|
||||
continue;
|
||||
}
|
||||
for (const entry of value) {
|
||||
if (typeof entry === "string" && entry.trim()) {
|
||||
urls.push(entry.trim());
|
||||
}
|
||||
pushMediaUrl(entry);
|
||||
}
|
||||
}
|
||||
const attachments = record.attachments;
|
||||
if (Array.isArray(attachments)) {
|
||||
for (const attachment of attachments) {
|
||||
pushAttachment(attachment);
|
||||
}
|
||||
}
|
||||
return urls;
|
||||
|
||||
@@ -1187,6 +1187,43 @@ describe("messaging tool media URL tracking", () => {
|
||||
expect(ctx.state.pendingMessagingMediaUrls.has("tool-upload-file")).toBe(false);
|
||||
});
|
||||
|
||||
it("commits message attachment aliases as delivery evidence", async () => {
|
||||
const { ctx } = createTestContext();
|
||||
|
||||
const startEvt: ToolExecutionStartEvent = {
|
||||
type: "tool_execution_start",
|
||||
toolName: "message",
|
||||
toolCallId: "tool-attachment-aliases",
|
||||
args: {
|
||||
action: "send",
|
||||
to: "channel:123",
|
||||
content: "track ready",
|
||||
media: "/tmp/generated-song.mp3",
|
||||
attachments: [{ filePath: "/tmp/generated-cover.png" }],
|
||||
},
|
||||
};
|
||||
await handleToolExecutionStart(ctx, startEvt);
|
||||
|
||||
const endEvt: ToolExecutionEndEvent = {
|
||||
type: "tool_execution_end",
|
||||
toolName: "message",
|
||||
toolCallId: "tool-attachment-aliases",
|
||||
isError: false,
|
||||
result: { ok: true },
|
||||
};
|
||||
await handleToolExecutionEnd(ctx, endEvt);
|
||||
|
||||
expect(ctx.state.messagingToolSentMediaUrls).toEqual([
|
||||
"/tmp/generated-song.mp3",
|
||||
"/tmp/generated-cover.png",
|
||||
]);
|
||||
expectRecordFields(requireSingleMessagingTarget(ctx), "messaging target", {
|
||||
to: "channel:123",
|
||||
text: "track ready",
|
||||
mediaUrls: ["/tmp/generated-song.mp3", "/tmp/generated-cover.png"],
|
||||
});
|
||||
});
|
||||
|
||||
it("commits sendAttachment args as message delivery evidence", async () => {
|
||||
const { ctx } = createTestContext();
|
||||
|
||||
|
||||
@@ -341,11 +341,23 @@ function pushUniqueMediaUrl(urls: string[], seen: Set<string>, value: unknown):
|
||||
function collectMessagingMediaUrlsFromRecord(record: Record<string, unknown>): string[] {
|
||||
const urls: string[] = [];
|
||||
const seen = new Set<string>();
|
||||
const pushAttachment = (value: unknown) => {
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
||||
return;
|
||||
}
|
||||
const attachment = value as Record<string, unknown>;
|
||||
pushUniqueMediaUrl(urls, seen, attachment.media);
|
||||
pushUniqueMediaUrl(urls, seen, attachment.mediaUrl);
|
||||
pushUniqueMediaUrl(urls, seen, attachment.path);
|
||||
pushUniqueMediaUrl(urls, seen, attachment.filePath);
|
||||
pushUniqueMediaUrl(urls, seen, attachment.fileUrl);
|
||||
};
|
||||
|
||||
pushUniqueMediaUrl(urls, seen, record.media);
|
||||
pushUniqueMediaUrl(urls, seen, record.mediaUrl);
|
||||
pushUniqueMediaUrl(urls, seen, record.path);
|
||||
pushUniqueMediaUrl(urls, seen, record.filePath);
|
||||
pushUniqueMediaUrl(urls, seen, record.fileUrl);
|
||||
|
||||
const mediaUrls = record.mediaUrls;
|
||||
if (Array.isArray(mediaUrls)) {
|
||||
@@ -353,6 +365,12 @@ function collectMessagingMediaUrlsFromRecord(record: Record<string, unknown>): s
|
||||
pushUniqueMediaUrl(urls, seen, mediaUrl);
|
||||
}
|
||||
}
|
||||
const attachments = record.attachments;
|
||||
if (Array.isArray(attachments)) {
|
||||
for (const attachment of attachments) {
|
||||
pushAttachment(attachment);
|
||||
}
|
||||
}
|
||||
|
||||
return urls;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user