fix: normalize session keys and outbound mirroring

This commit is contained in:
Peter Steinberger
2026-01-24 11:57:04 +00:00
parent eaeb52f70a
commit 4b6cdd1d3c
33 changed files with 1357 additions and 145 deletions

View File

@@ -8,7 +8,6 @@ import { createMessageTool } from "./message-tool.js";
const mocks = vi.hoisted(() => ({
runMessageAction: vi.fn(),
appendAssistantMessageToSessionTranscript: vi.fn(async () => ({ ok: true, sessionFile: "x" })),
}));
vi.mock("../../infra/outbound/message-action-runner.js", async () => {
@@ -21,47 +20,9 @@ vi.mock("../../infra/outbound/message-action-runner.js", async () => {
};
});
vi.mock("../../config/sessions.js", async () => {
const actual = await vi.importActual<typeof import("../../config/sessions.js")>(
"../../config/sessions.js",
);
return {
...actual,
appendAssistantMessageToSessionTranscript: mocks.appendAssistantMessageToSessionTranscript,
};
});
describe("message tool mirroring", () => {
it("mirrors media filename for plugin-handled sends", async () => {
mocks.appendAssistantMessageToSessionTranscript.mockClear();
mocks.runMessageAction.mockResolvedValue({
kind: "send",
action: "send",
channel: "telegram",
handledBy: "plugin",
payload: {},
dryRun: false,
} satisfies MessageActionRunResult);
const tool = createMessageTool({
agentSessionKey: "agent:main:main",
config: {} as never,
});
await tool.execute("1", {
action: "send",
target: "telegram:123",
message: "",
media: "https://example.com/files/report.pdf?sig=1",
});
expect(mocks.appendAssistantMessageToSessionTranscript).toHaveBeenCalledWith(
expect.objectContaining({ text: "report.pdf" }),
);
});
it("does not mirror on dry-run", async () => {
mocks.appendAssistantMessageToSessionTranscript.mockClear();
describe("message tool agent routing", () => {
it("derives agentId from the session key", async () => {
mocks.runMessageAction.mockClear();
mocks.runMessageAction.mockResolvedValue({
kind: "send",
action: "send",
@@ -72,7 +33,7 @@ describe("message tool mirroring", () => {
} satisfies MessageActionRunResult);
const tool = createMessageTool({
agentSessionKey: "agent:main:main",
agentSessionKey: "agent:alpha:main",
config: {} as never,
});
@@ -82,7 +43,9 @@ describe("message tool mirroring", () => {
message: "hi",
});
expect(mocks.appendAssistantMessageToSessionTranscript).not.toHaveBeenCalled();
const call = mocks.runMessageAction.mock.calls[0]?.[0];
expect(call?.agentId).toBe("alpha");
expect(call?.sessionKey).toBeUndefined();
});
});

View File

@@ -11,10 +11,6 @@ import {
import { BLUEBUBBLES_GROUP_ACTIONS } from "../../channels/plugins/bluebubbles-actions.js";
import type { ClawdbotConfig } from "../../config/config.js";
import { loadConfig } from "../../config/config.js";
import {
appendAssistantMessageToSessionTranscript,
resolveMirroredTranscriptText,
} from "../../config/sessions.js";
import { GATEWAY_CLIENT_IDS, GATEWAY_CLIENT_MODES } from "../../gateway/protocol/client-info.js";
import { normalizeTargetForProvider } from "../../infra/outbound/target-normalization.js";
import { getToolResult, runMessageAction } from "../../infra/outbound/message-action-runner.js";
@@ -377,36 +373,11 @@ export function createMessageTool(options?: MessageToolOptions): AnyAgentTool {
defaultAccountId: accountId ?? undefined,
gateway,
toolContext,
sessionKey: options?.agentSessionKey,
agentId: options?.agentSessionKey
? resolveSessionAgentId({ sessionKey: options.agentSessionKey, config: cfg })
: undefined,
});
if (
action === "send" &&
options?.agentSessionKey &&
!result.dryRun &&
result.handledBy === "plugin"
) {
const mediaUrl = typeof params.media === "string" ? params.media : undefined;
const mirrorText = resolveMirroredTranscriptText({
text: typeof params.message === "string" ? params.message : undefined,
mediaUrls: mediaUrl ? [mediaUrl] : undefined,
});
if (mirrorText) {
const agentId = resolveSessionAgentId({
sessionKey: options.agentSessionKey,
config: cfg,
});
await appendAssistantMessageToSessionTranscript({
agentId,
sessionKey: options.agentSessionKey,
text: mirrorText,
});
}
}
const toolResult = getToolResult(result);
if (toolResult) return toolResult;
return jsonResult(result.payload);