imessage: isolate group-ish threads by chat_id

This commit is contained in:
Miles
2026-01-08 16:24:28 -06:00
parent 95c2ccbd7b
commit 27952bb94d
3 changed files with 139 additions and 31 deletions

View File

@@ -216,6 +216,46 @@ describe("monitorIMessageProvider", () => {
expect(sendMock).not.toHaveBeenCalled();
});
it("treats configured chat_id as a group session even when is_group is false", async () => {
config = {
...config,
imessage: {
dmPolicy: "open",
allowFrom: ["*"],
groups: { "2": { requireMention: false } },
},
};
const run = monitorIMessageProvider();
await waitForSubscribe();
notificationHandler?.({
method: "message",
params: {
message: {
id: 14,
chat_id: 2,
sender: "+15550001111",
is_from_me: false,
text: "hello",
is_group: false,
},
},
});
await flush();
closeResolve?.();
await run;
expect(replyMock).toHaveBeenCalled();
const ctx = replyMock.mock.calls[0]?.[0] as {
ChatType?: string;
SessionKey?: string;
};
expect(ctx.ChatType).toBe("group");
expect(ctx.SessionKey).toBe("agent:main:imessage:group:2");
});
it("prefixes tool and final replies with responsePrefix", async () => {
config = {
...config,

View File

@@ -168,10 +168,36 @@ export async function monitorIMessageProvider(
const chatId = message.chat_id ?? undefined;
const chatGuid = message.chat_guid ?? undefined;
const chatIdentifier = message.chat_identifier ?? undefined;
const isGroup = Boolean(message.is_group);
const groupIdCandidate = chatId !== undefined ? String(chatId) : undefined;
const groupListPolicy = groupIdCandidate
? resolveProviderGroupPolicy({
cfg,
provider: "imessage",
accountId: accountInfo.accountId,
groupId: groupIdCandidate,
})
: {
allowlistEnabled: false,
allowed: true,
groupConfig: undefined,
defaultConfig: undefined,
};
// Some iMessage threads can have multiple participants but still report
// is_group=false depending on how Messages stores the identifier.
// If the owner explicitly configures a chat_id under imessage.groups, treat
// that thread as a "group" for permission gating and session isolation.
const treatAsGroupByConfig = Boolean(
groupIdCandidate &&
groupListPolicy.allowlistEnabled &&
groupListPolicy.groupConfig,
);
const isGroup = Boolean(message.is_group) || treatAsGroupByConfig;
if (isGroup && !chatId) return;
const groupId = isGroup ? String(chatId) : undefined;
const groupId = isGroup ? groupIdCandidate : undefined;
const storeAllowFrom = await readProviderAllowFromStore("imessage").catch(
() => [],
);
@@ -212,12 +238,6 @@ export async function monitorIMessageProvider(
return;
}
}
const groupListPolicy = resolveProviderGroupPolicy({
cfg,
provider: "imessage",
accountId: accountInfo.accountId,
groupId,
});
if (groupListPolicy.allowlistEnabled && !groupListPolicy.allowed) {
logVerbose(
`imessage: skipping group message (${groupId ?? "unknown"}) not in allowlist`,