fix: honor send path/filePath inputs (#1444) (thanks @hopyky)

This commit is contained in:
Peter Steinberger
2026-01-23 02:10:05 +00:00
parent 59a8eecd7e
commit 837749dced
4 changed files with 60 additions and 10 deletions

View File

@@ -26,6 +26,7 @@ Docs: https://docs.clawd.bot
### Fixes
- BlueBubbles: stop typing indicator on idle/no-reply. (#1439) Thanks @Nicell.
- Message tool: keep path/filePath as-is for send; hydrate buffers only for sendAttachment. (#1444) Thanks @hopyky.
- Auto-reply: only report a model switch when session state is available. (#1465) Thanks @robbyczgw-cla.
- Control UI: resolve local avatar URLs with basePath across injection + identity RPC. (#1457) Thanks @dlauer.
- Agents: surface concrete API error details instead of generic AI service errors.

View File

@@ -86,6 +86,64 @@ describe("message tool mirroring", () => {
});
});
describe("message tool path passthrough", () => {
it("does not convert path to media for send", async () => {
mocks.runMessageAction.mockClear();
mocks.runMessageAction.mockResolvedValue({
kind: "send",
action: "send",
channel: "telegram",
to: "telegram:123",
handledBy: "plugin",
payload: {},
dryRun: true,
} satisfies MessageActionRunResult);
const tool = createMessageTool({
config: {} as never,
});
await tool.execute("1", {
action: "send",
target: "telegram:123",
path: "~/Downloads/voice.ogg",
message: "",
});
const call = mocks.runMessageAction.mock.calls[0]?.[0];
expect(call?.params?.path).toBe("~/Downloads/voice.ogg");
expect(call?.params?.media).toBeUndefined();
});
it("does not convert filePath to media for send", async () => {
mocks.runMessageAction.mockClear();
mocks.runMessageAction.mockResolvedValue({
kind: "send",
action: "send",
channel: "telegram",
to: "telegram:123",
handledBy: "plugin",
payload: {},
dryRun: true,
} satisfies MessageActionRunResult);
const tool = createMessageTool({
config: {} as never,
});
await tool.execute("1", {
action: "send",
target: "telegram:123",
filePath: "./tmp/note.m4a",
message: "",
});
const call = mocks.runMessageAction.mock.calls[0]?.[0];
expect(call?.params?.filePath).toBe("./tmp/note.m4a");
expect(call?.params?.media).toBeUndefined();
});
});
describe("message tool description", () => {
const bluebubblesPlugin: ChannelPlugin = {
id: "bluebubbles",

View File

@@ -341,15 +341,6 @@ export function createMessageTool(options?: MessageToolOptions): AnyAgentTool {
required: true,
}) as ChannelMessageActionName;
// Handle path and filePath parameters: convert to media with file:// URL
if (action === "send" && !params.media) {
const filePath =
(params.path as string | undefined) || (params.filePath as string | undefined);
if (filePath) {
params.media = filePath.startsWith("file://") ? filePath : `file://${filePath}`;
}
}
const accountId = readStringParam(params, "accountId") ?? agentAccountId;
const gateway = {

View File

@@ -343,7 +343,7 @@ async function hydrateSendAttachmentParams(params: {
action: ChannelMessageActionName;
dryRun?: boolean;
}): Promise<void> {
if (params.action !== "sendAttachment" && params.action !== "send") return;
if (params.action !== "sendAttachment") return;
const mediaHint = readStringParam(params.args, "media", { trim: false });
const fileHint =