fix(cron): tighten session mirror classification

This commit is contained in:
Cavit Erginsoy
2026-05-11 22:26:28 +01:00
committed by Peter Steinberger
parent 7de413499f
commit f3403708a3
4 changed files with 60 additions and 18 deletions
@@ -1026,6 +1026,8 @@ export async function dispatchCronDelivery(
sessionKey: deliverySessionKey,
agentId: params.agentId,
text: mirrorText,
// Keep cron delivery mirrors text-first: non-audio attachment names
// are folded into mirrorText so media does not replace delivered text.
mediaUrls: undefined,
storePath: resolveStorePath(params.cfgWithAgentDefaults.session?.store, {
agentId: resolveAgentIdFromSessionKey(deliverySessionKey),
@@ -585,6 +585,8 @@ export function setMinimalOutboundSessionPluginRegistryForTests(): void {
capabilities: { chatTypes: ["direct", "group", "channel"] },
}),
messaging: {
parseExplicitTarget: ({ raw }) =>
raw.startsWith("spaces/") ? { to: raw, chatType: "group" } : null,
targetPrefixes: ["fallbackchat"],
},
},
+13 -1
View File
@@ -363,7 +363,7 @@ describe("resolveOutboundSessionRoute", () => {
},
},
{
name: "FallbackChat space-style target",
name: "FallbackChat plugin parser classifies space-style target",
cfg: baseConfig,
channel: "fallbackchat",
target: "spaces/AAA",
@@ -386,6 +386,18 @@ describe("resolveOutboundSessionRoute", () => {
chatType: "direct",
},
},
{
name: "FallbackChat explicit thread prefix",
cfg: baseConfig,
channel: "fallbackchat",
target: "thread:abc",
expected: {
sessionKey: "agent:main:fallbackchat:channel:abc",
from: "fallbackchat:channel:abc",
to: "channel:abc",
chatType: "channel",
},
},
] satisfies NamedRouteCase[])("$name", async ({ name: _name, ...params }) => {
await expectResolvedRoute(params);
});
+43 -17
View File
@@ -50,7 +50,44 @@ function stripProviderPrefix(raw: string, channel: string): string {
}
function stripKindPrefix(raw: string): string {
return raw.replace(/^(user|channel|group|conversation|room|dm):/i, "").trim();
return raw.replace(/^(user|channel|group|conversation|room|dm|thread):/i, "").trim();
}
const FALLBACK_TARGET_KIND_PREFIXES: Array<{ kind: ChatType; pattern: RegExp }> = [
{ kind: "direct", pattern: /^(user:|dm:)/i },
{ kind: "channel", pattern: /^(channel:|conversation:|thread:)/i },
{ kind: "group", pattern: /^(group:|room:)/i },
];
function normalizeInferredPeerKind(value: ChatType | undefined): ChatType | undefined {
return value === "direct" || value === "group" || value === "channel" ? value : undefined;
}
function inferPeerKindFromPlugin(params: {
plugin: ReturnType<typeof resolveOutboundChannelPlugin>;
targets: readonly string[];
}): ChatType | undefined {
for (const target of params.targets) {
const inferred = normalizeInferredPeerKind(
params.plugin?.messaging?.parseExplicitTarget?.({ raw: target })?.chatType ??
params.plugin?.messaging?.inferTargetChatType?.({ to: target }),
);
if (inferred) {
return inferred;
}
}
return undefined;
}
function inferPeerKindFromFallbackPrefixes(targets: readonly string[]): ChatType | undefined {
for (const target of targets) {
for (const fallback of FALLBACK_TARGET_KIND_PREFIXES) {
if (fallback.pattern.test(target)) {
return fallback.kind;
}
}
}
return undefined;
}
function inferPeerKind(params: {
@@ -81,22 +118,11 @@ function inferPeerKind(params: {
(target, index, values): target is string =>
Boolean(target) && values.indexOf(target) === index,
);
for (const target of targets) {
const inferred = plugin?.messaging?.inferTargetChatType?.({ to: target });
if (inferred === "direct" || inferred === "group" || inferred === "channel") {
return inferred;
}
}
if (targets.some((target) => /^(@|<@!?|user:|dm:|c2c:|users\/)/i.test(target))) {
return "direct";
}
if (targets.some((target) => /^(channel:|conversation:|thread:|channels\/)/i.test(target))) {
return "channel";
}
if (targets.some((target) => /^(#|group:|room:|spaces\/|groups\/|rooms\/)/i.test(target))) {
return "group";
}
return "direct";
return (
inferPeerKindFromPlugin({ plugin, targets }) ??
inferPeerKindFromFallbackPrefixes(targets) ??
"direct"
);
}
function resolveFallbackSession(