fix: harden mcp channel bridge smoke

This commit is contained in:
Peter Steinberger
2026-03-28 04:10:00 +00:00
parent 9b405f88d4
commit ec5877346c
11 changed files with 970 additions and 29 deletions

View File

@@ -136,6 +136,24 @@ describe("openclaw channel mcp server", () => {
timestamp: Date.now(),
},
},
{
id: "msg-attachment",
message: {
role: "assistant",
content: [
{ type: "text", text: "attached image" },
{
type: "image",
source: {
type: "base64",
media_type: "image/png",
data: "abc",
},
},
],
timestamp: Date.now() + 1,
},
},
],
});
@@ -175,6 +193,27 @@ describe("openclaw channel mcp server", () => {
role: "assistant",
content: [{ type: "text", text: "hello from transcript" }],
});
expect(read.structuredContent?.messages?.[1]).toMatchObject({
__openclaw: {
id: "msg-attachment",
},
});
const attachments = (await mcp.client.callTool({
name: "attachments_fetch",
arguments: { session_key: sessionKey, message_id: "msg-attachment" },
})) as {
structuredContent?: { attachments?: Array<Record<string, unknown>> };
isError?: boolean;
};
expect(attachments.isError).not.toBe(true);
expect(attachments.structuredContent?.attachments).toEqual(
expect.arrayContaining([
expect.objectContaining({
type: "image",
}),
]),
);
const waitPromise = mcp.client.callTool({
name: "events_wait",
@@ -454,6 +493,28 @@ describe("openclaw channel mcp server", () => {
request_id: "abcde",
behavior: "allow",
});
emitSessionTranscriptUpdate({
sessionFile: path.join(path.dirname(storePath), "sess-claude.jsonl"),
sessionKey,
messageId: "msg-user-3",
message: {
role: "user",
content: "plain string user turn",
timestamp: Date.now(),
},
});
await vi.waitFor(() => {
expect(channelNotifications).toHaveLength(2);
});
expect(channelNotifications[1]).toMatchObject({
content: "plain string user turn",
meta: expect.objectContaining({
session_key: sessionKey,
message_id: "msg-user-3",
}),
});
} finally {
await mcp?.close();
await harness.close();

View File

@@ -166,6 +166,15 @@ function toText(value: unknown): string | undefined {
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
}
function resolveMessageId(entry: Record<string, unknown>): string | undefined {
return (
toText(entry.id) ??
(entry.__openclaw && typeof entry.__openclaw === "object"
? toText((entry.__openclaw as { id?: unknown }).id)
: undefined)
);
}
function summarizeResult(
label: string,
count: number,
@@ -832,7 +841,7 @@ export async function createOpenClawChannelMcpServer(opts: OpenClawMcpServeOptio
},
async ({ session_key, message_id, limit }) => {
const messages = await bridge.readMessages(session_key, limit ?? 100);
const message = messages.find((entry) => toText(entry.id) === message_id);
const message = messages.find((entry) => resolveMessageId(entry) === message_id);
if (!message) {
return {
content: [{ type: "text", text: `message not found: ${message_id}` }],