fix(agents): preserve prefixed Teams peer ids

This commit is contained in:
Gustavo Madeira Santana
2026-04-17 20:00:21 -04:00
parent 860689c685
commit 9c5d8e3025
3 changed files with 85 additions and 5 deletions

View File

@@ -703,11 +703,11 @@ describe("openclaw-tools: subagents (sessions_spawn lifecycle)", () => {
).toBe("bot-alpha-dm");
});
it("sessions_spawn strips conversation: prefix for Teams-style targets", async () => {
const rawConversationId = "19:example-conversation@thread.v2";
// Teams inbound context sets OriginatingTo to `conversation:<id>`. With the
// generic prefix peeler in extractRequesterPeer, the bound-account lookup
// should still find the binding keyed on the raw conversation id.
it("sessions_spawn strips only the Teams conversation: wrapper", async () => {
const rawConversationId = "a:1:example-conversation@thread.v2";
// Teams inbound context sets OriginatingTo to `conversation:<id>`. The
// Teams id itself may start with another token-colon segment, so extraction
// must stop after the known wrapper instead of peeling arbitrary prefixes.
expect(
await executeBoundAccountSpawn({
callId: "call-teams-conversation",

View File

@@ -39,4 +39,74 @@ describe("resolveRequesterOriginForChild", () => {
to,
});
});
it("preserves canonical peer ids that start with token-colon after a known wrapper", () => {
const to = "conversation:a:1:team-thread";
const cfg = {
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "msteams",
peer: {
kind: "channel",
id: "a:1:team-thread",
},
accountId: "bot-alpha-teams",
},
},
],
} as OpenClawConfig;
expect(
resolveRequesterOriginForChild({
cfg,
targetAgentId: "bot-alpha",
requesterAgentId: "main",
requesterChannel: "msteams",
requesterAccountId: "bot-beta",
requesterTo: to,
}),
).toMatchObject({
channel: "msteams",
accountId: "bot-alpha-teams",
to,
});
});
it("still peels channel id plus kind wrappers before peer lookup", () => {
const to = "line:group:U123example";
const cfg = {
bindings: [
{
type: "route",
agentId: "bot-alpha",
match: {
channel: "line",
peer: {
kind: "group",
id: "U123example",
},
accountId: "bot-alpha-line",
},
},
],
} as OpenClawConfig;
expect(
resolveRequesterOriginForChild({
cfg,
targetAgentId: "bot-alpha",
requesterAgentId: "main",
requesterChannel: "line",
requesterAccountId: "bot-beta",
requesterTo: to,
}),
).toMatchObject({
channel: "line",
accountId: "bot-alpha-line",
to,
});
});
});

View File

@@ -26,6 +26,13 @@ const KIND_PREFIX_TO_CHAT_TYPE: Readonly<Record<string, ChatType>> = {
// Matches one leading `<alpha-token>:` wrapper at a time.
const GENERIC_PREFIX_PATTERN = /^[a-z][a-z0-9_-]*:/i;
function shouldPeelRequesterPrefix(prefix: string, channelId: string | undefined): boolean {
if (prefix in KIND_PREFIX_TO_CHAT_TYPE) {
return true;
}
return Boolean(channelId && prefix === `${channelId.trim().toLowerCase()}:`);
}
export function extractRequesterPeer(
channelId: string | undefined,
requesterTo: string | undefined,
@@ -49,6 +56,9 @@ export function extractRequesterPeer(
break;
}
const prefix = match[0].toLowerCase();
if (!shouldPeelRequesterPrefix(prefix, channelId)) {
break;
}
if (prefix in KIND_PREFIX_TO_CHAT_TYPE) {
inferredKind ??= KIND_PREFIX_TO_CHAT_TYPE[prefix];
}