





















@@ -28,6 +28,9 @@ type MockOpenClawToolsOptions = {
2828sandboxRoot?: string;
2929sandboxFsBridge?: SandboxFsBridge;
3030fsPolicy?: NonNullable<Parameters<typeof createImageTool>[0]>["fsPolicy"];
31+agentChannel?: string | null;
32+agentAccountId?: string | null;
33+currentChannelId?: string | null;
3134modelHasVision?: boolean;
3235};
3336@@ -167,6 +170,9 @@ vi.mock("../openclaw-tools.js", async () => {
167170}
168171 : undefined,
169172fsPolicy: options?.fsPolicy,
173+agentChannel: options?.agentChannel,
174+agentAccountId: options?.agentAccountId,
175+currentChannelId: options?.currentChannelId,
170176modelHasVision: options?.modelHasVision,
171177});
172178return imageTool ? [imageTool] : [];
@@ -1640,6 +1646,85 @@ describe("image tool implicit imageModel config", () => {
16401646});
16411647});
164216481649+it("allows image paths from the current iMessage account attachment roots", async () => {
1650+const fetch = stubMinimaxOkFetch();
1651+await withTempAgentDir(async (agentDir) => {
1652+const attachmentRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-imessage-root-"));
1653+const imagePath = path.join(attachmentRoot, "photo.png");
1654+await fs.writeFile(imagePath, Buffer.from(ONE_PIXEL_PNG_B64, "base64"));
1655+try {
1656+const cfg: OpenClawConfig = {
1657+ ...createMinimaxImageConfig(),
1658+channels: {
1659+imessage: {
1660+accounts: {
1661+work: {
1662+attachmentRoots: [attachmentRoot],
1663+},
1664+},
1665+},
1666+},
1667+};
1668+1669+const withoutChannel = createRequiredImageTool({ config: cfg, agentDir });
1670+await expect(
1671+withoutChannel.execute("t1", { prompt: "Describe.", image: imagePath }),
1672+).rejects.toThrow(/not under an allowed directory/i);
1673+1674+const withImessage = createRequiredImageTool({
1675+config: cfg,
1676+ agentDir,
1677+agentChannel: "imessage",
1678+agentAccountId: "work",
1679+});
1680+1681+await expectImageToolExecOk(withImessage, imagePath);
1682+expect(fetch).toHaveBeenCalledTimes(1);
1683+} finally {
1684+await fs.rm(attachmentRoot, { recursive: true, force: true });
1685+}
1686+});
1687+});
1688+1689+it("allows image paths from current iMessage wildcard attachment roots", async () => {
1690+const fetch = stubMinimaxOkFetch();
1691+await withTempAgentDir(async (agentDir) => {
1692+const attachmentRootParent = await fs.mkdtemp(
1693+path.join(os.tmpdir(), "openclaw-imessage-wildcard-root-"),
1694+);
1695+const attachmentRoot = path.join(attachmentRootParent, "work", "Attachments");
1696+const imagePath = path.join(attachmentRoot, "photo.png");
1697+await fs.mkdir(attachmentRoot, { recursive: true });
1698+await fs.writeFile(imagePath, Buffer.from(ONE_PIXEL_PNG_B64, "base64"));
1699+try {
1700+const cfg: OpenClawConfig = {
1701+ ...createMinimaxImageConfig(),
1702+channels: {
1703+imessage: {
1704+accounts: {
1705+work: {
1706+attachmentRoots: [path.join(attachmentRootParent, "*", "Attachments")],
1707+},
1708+},
1709+},
1710+},
1711+};
1712+1713+const withImessage = createRequiredImageTool({
1714+config: cfg,
1715+ agentDir,
1716+agentChannel: "imessage",
1717+agentAccountId: "work",
1718+});
1719+1720+await expectImageToolExecOk(withImessage, imagePath);
1721+expect(fetch).toHaveBeenCalledTimes(1);
1722+} finally {
1723+await fs.rm(attachmentRootParent, { recursive: true, force: true });
1724+}
1725+});
1726+});
1727+16431728it("allows workspace images via createOpenClawCodingTools when workspace root is explicit", async () => {
16441729await withTempWorkspacePng(async ({ workspaceDir, imagePath }) => {
16451730const fetch = stubMinimaxOkFetch();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。