fix: imessage dm replies and error details (#935)
This commit is contained in:
@@ -53,4 +53,38 @@ describe("buildThreadingToolContext", () => {
|
||||
|
||||
expect(result.currentChannelId).toBe("chat:99");
|
||||
});
|
||||
|
||||
it("uses the sender handle for iMessage direct chats", () => {
|
||||
const sessionCtx = {
|
||||
Provider: "imessage",
|
||||
ChatType: "direct",
|
||||
From: "imessage:+15550001",
|
||||
To: "chat_id:12",
|
||||
} as TemplateContext;
|
||||
|
||||
const result = buildThreadingToolContext({
|
||||
sessionCtx,
|
||||
config: cfg,
|
||||
hasRepliedRef: undefined,
|
||||
});
|
||||
|
||||
expect(result.currentChannelId).toBe("imessage:+15550001");
|
||||
});
|
||||
|
||||
it("uses chat_id for iMessage groups", () => {
|
||||
const sessionCtx = {
|
||||
Provider: "imessage",
|
||||
ChatType: "group",
|
||||
From: "group:7",
|
||||
To: "chat_id:7",
|
||||
} as TemplateContext;
|
||||
|
||||
const result = buildThreadingToolContext({
|
||||
sessionCtx,
|
||||
config: cfg,
|
||||
hasRepliedRef: undefined,
|
||||
});
|
||||
|
||||
expect(result.currentChannelId).toBe("chat_id:7");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,7 +26,12 @@ export function buildThreadingToolContext(params: {
|
||||
const dock = getChannelDock(provider);
|
||||
if (!dock?.threading?.buildToolContext) return {};
|
||||
// WhatsApp context isolation keys off conversation id, not the bot's own number.
|
||||
const threadingTo = provider === "whatsapp" ? (sessionCtx.From ?? sessionCtx.To) : sessionCtx.To;
|
||||
const threadingTo =
|
||||
provider === "whatsapp"
|
||||
? (sessionCtx.From ?? sessionCtx.To)
|
||||
: provider === "imessage" && sessionCtx.ChatType === "direct"
|
||||
? (sessionCtx.From ?? sessionCtx.To)
|
||||
: sessionCtx.To;
|
||||
return (
|
||||
dock.threading.buildToolContext({
|
||||
cfg: config,
|
||||
|
||||
@@ -180,7 +180,17 @@ export class IMessageRpcClient {
|
||||
this.pending.delete(key);
|
||||
|
||||
if (parsed.error) {
|
||||
const msg = parsed.error.message ?? "imsg rpc error";
|
||||
const baseMessage = parsed.error.message ?? "imsg rpc error";
|
||||
const details = parsed.error.data;
|
||||
const code = parsed.error.code;
|
||||
const suffixes = [] as string[];
|
||||
if (typeof code === "number") suffixes.push(`code=${code}`);
|
||||
if (details !== undefined) {
|
||||
const detailText =
|
||||
typeof details === "string" ? details : JSON.stringify(details, null, 2);
|
||||
if (detailText) suffixes.push(detailText);
|
||||
}
|
||||
const msg = suffixes.length > 0 ? `${baseMessage}: ${suffixes.join(" ")}` : baseMessage;
|
||||
pending.reject(new Error(msg));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ beforeEach(() => {
|
||||
});
|
||||
|
||||
describe("monitorIMessageProvider", () => {
|
||||
it("updates last route with chat_id for direct messages", async () => {
|
||||
it("updates last route with sender handle for direct messages", async () => {
|
||||
replyMock.mockResolvedValueOnce({ text: "ok" });
|
||||
const run = monitorIMessageProvider();
|
||||
await waitForSubscribe();
|
||||
@@ -118,7 +118,7 @@ describe("monitorIMessageProvider", () => {
|
||||
expect(updateLastRouteMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
channel: "imessage",
|
||||
to: "chat_id:7",
|
||||
to: "+15550004444",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -296,7 +296,7 @@ export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): P
|
||||
});
|
||||
}
|
||||
|
||||
const imessageTo = chatTarget || `imessage:${sender}`;
|
||||
const imessageTo = (isGroup ? chatTarget : undefined) || `imessage:${sender}`;
|
||||
const ctxPayload = {
|
||||
Body: combinedBody,
|
||||
RawBody: bodyText,
|
||||
@@ -329,7 +329,7 @@ export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): P
|
||||
const storePath = resolveStorePath(sessionCfg?.store, {
|
||||
agentId: route.agentId,
|
||||
});
|
||||
const to = chatTarget || sender;
|
||||
const to = (isGroup ? chatTarget : undefined) || sender;
|
||||
if (to) {
|
||||
await updateLastRoute({
|
||||
storePath,
|
||||
|
||||
@@ -100,4 +100,36 @@ describe("runMessageAction context isolation", () => {
|
||||
}),
|
||||
).rejects.toThrow(/Cross-context messaging denied/);
|
||||
});
|
||||
|
||||
it("allows iMessage send when target matches current handle", async () => {
|
||||
const result = await runMessageAction({
|
||||
cfg: whatsappConfig,
|
||||
action: "send",
|
||||
params: {
|
||||
channel: "imessage",
|
||||
to: "imessage:+15551234567",
|
||||
message: "hi",
|
||||
},
|
||||
toolContext: { currentChannelId: "imessage:+15551234567" },
|
||||
dryRun: true,
|
||||
});
|
||||
|
||||
expect(result.kind).toBe("send");
|
||||
});
|
||||
|
||||
it("blocks iMessage send when target differs from current handle", async () => {
|
||||
await expect(
|
||||
runMessageAction({
|
||||
cfg: whatsappConfig,
|
||||
action: "send",
|
||||
params: {
|
||||
channel: "imessage",
|
||||
to: "imessage:+15551230000",
|
||||
message: "hi",
|
||||
},
|
||||
toolContext: { currentChannelId: "imessage:+15551234567" },
|
||||
dryRun: true,
|
||||
}),
|
||||
).rejects.toThrow(/Cross-context messaging denied/);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user