























@@ -901,6 +901,29 @@ describe("loadChatHistory filtering", () => {
901901expect(state.chatMessages).toEqual([messages[0], messages[2]]);
902902});
903903904+it("keeps image-only user messages that carry transcript media paths", async () => {
905+const messages = [
906+{ role: "user", content: "", MediaPath: "/tmp/openclaw/user-upload.png" },
907+{
908+role: "user",
909+content: "",
910+MediaPaths: ["/tmp/openclaw/first.png", "/tmp/openclaw/second.jpg"],
911+},
912+{ role: "user", content: "" },
913+];
914+const mockClient = {
915+request: vi.fn().mockResolvedValue({ messages }),
916+};
917+const state = createState({
918+client: mockClient as unknown as ChatState["client"],
919+connected: true,
920+});
921+922+await loadChatHistory(state);
923+924+expect(state.chatMessages).toEqual([messages[0], messages[1]]);
925+});
926+904927it("keeps a user message even if it matches the synthetic repair text", async () => {
905928const messages = [
906929{
@@ -1075,6 +1098,76 @@ describe("sendChatMessage", () => {
10751098]);
10761099});
107711001101+it("sends inline image payloads without copying data URLs into optimistic chat state", async () => {
1102+const request = vi.fn().mockResolvedValue({ runId: "run-1", status: "started" });
1103+const state = createState({
1104+connected: true,
1105+client: { request } as unknown as ChatState["client"],
1106+});
1107+const imageBase64 = "A".repeat(1024 * 1024);
1108+const imageDataUrl = `data:image/png;base64,${imageBase64}`;
1109+1110+const result = await sendChatMessage(state, "", [
1111+{
1112+id: "att-image",
1113+dataUrl: imageDataUrl,
1114+mimeType: "image/png",
1115+fileName: "photo.png",
1116+},
1117+]);
1118+1119+expect(result).toMatch(UUID_V4_RE);
1120+expect(request).toHaveBeenCalledTimes(1);
1121+const [requestMethod, requestParams] = requireFirstRequestCall(request);
1122+expect(requestMethod).toBe("chat.send");
1123+const sendParams = requireRecord(requestParams);
1124+expect(sendParams.message).toBe("");
1125+expect(sendParams.attachments).toEqual([
1126+{
1127+type: "image",
1128+mimeType: "image/png",
1129+fileName: "photo.png",
1130+content: imageBase64,
1131+},
1132+]);
1133+expect(state.chatMessages).toStrictEqual([
1134+{
1135+role: "user",
1136+content: [{ type: "text", text: "Attached image: photo.png" }],
1137+timestamp: expect.any(Number),
1138+},
1139+]);
1140+expect(JSON.stringify(state.chatMessages)).not.toContain("data:image/png;base64");
1141+1142+const captionedRequest = vi.fn().mockResolvedValue({ runId: "run-2", status: "started" });
1143+const captionedState = createState({
1144+connected: true,
1145+client: { request: captionedRequest } as unknown as ChatState["client"],
1146+});
1147+1148+await expect(
1149+sendChatMessage(captionedState, "describe", [
1150+{
1151+id: "att-captioned-image",
1152+dataUrl: imageDataUrl,
1153+mimeType: "image/png",
1154+fileName: "photo.png",
1155+},
1156+]),
1157+).resolves.toMatch(UUID_V4_RE);
1158+expect(captionedState.chatMessages).toStrictEqual([
1159+{
1160+role: "user",
1161+content: [
1162+{ type: "text", text: "describe" },
1163+{ type: "text", text: "Attached image: photo.png" },
1164+],
1165+timestamp: expect.any(Number),
1166+},
1167+]);
1168+expect(JSON.stringify(captionedState.chatMessages)).not.toContain("data:image/png;base64");
1169+});
1170+10781171it("formats structured non-auth connect failures for chat send", async () => {
10791172const request = vi.fn().mockRejectedValue(
10801173new GatewayRequestError({
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。