Make @mentions visible to the agents they name
A DM addressed to one agent that @-mentions another was silently dropping the second agent out of the conversation: * `dispatchAgentMessage` added the mentioned agent to the wake set, so CEO's heartbeat fired — but * `listAgentInboxUnread` only surfaced messages where the current agent was `to_agent_id` or sat in a matching channel/project/ department. Mentions were invisible, so CEO's next turn saw nothing new and returned silently. From the operator's chair this looked exactly like "CEO ignored me; 张工程师 answered instead". * `findMentionedAgentIds` had a latent bug on top: its unique-alias filter used `ids.length === 1`, but a single agent whose name matched its role registered itself twice, tripped the filter, and every `@CEO` in a scaffold with role === name was a no-op. Once inbox visibility was fixed the bug became load-bearing. Root-cause fixes: * New migration v48 adds `agent_message_mentions(message_id, agent_id, company_id, created_at)` so mention fan-out is a first-class join. * `sendAgentMessage` now takes the resolved mention set and writes the row + mentions in a single transaction — a crash between the two writes can no longer leave a message visible to the recipient but invisible to the mentioned agent. * `dispatchAgentMessage` computes the mention set exactly once via `resolveMentionedAgentIds` and hands the same list to both the DB write and `resolveMessageWakeTargets`, so persistence and wake stay in lockstep. * `listAgentInboxUnread` and `listAgentMessages` gain an `id IN (select message_id from agent_message_mentions …)` clause so the mentioned agent's inbox actually contains the message that woke it. * `findMentionedAgentIds` now stores per-alias agent IDs in a `Set` and filters on `ids.size === 1`, dropping the self-duplication bug while preserving the "refuse ambiguous aliases" semantics. * Company teardown drops `agent_message_mentions` alongside the existing `agent_message_reads` cleanup so deletes stay clean. Tests pin the new behaviour: a DM with a `@CEO` mention reaches CEO's inbox and both agents get woken, while a DM whose recipient is `__board__` never attempts to wake the human sentinel.
This commit is contained in:
1 parent
e74dafcd36
commit
7833ded4a1
8 files changed
+231
-36
No files matched your search
@@ -295,12 +295,18 @@ export function buildAgentCrudMethods(
|
||||
if (agents.length === 0) return [];
|
||||
|
||||
const lowerText = text.toLowerCase();
|
||||
const aliasMap = new Map<string, string[]>();
|
||||
// Per-alias agent set. Storing a `Set` (not an array) means the
|
||||
// same agent contributing the same string via multiple fields
|
||||
// (e.g. name === role === "CEO") collapses to one entry. Before
|
||||
// this fix the duplicate push made the alias look non-unique, the
|
||||
// unique-alias filter dropped it, and every @mention in a scaffold
|
||||
// where role mirrored name silently missed.
|
||||
const aliasMap = new Map<string, Set<string>>();
|
||||
const registerAlias = (alias: string, agentId: string) => {
|
||||
const normalized = alias.trim().toLowerCase();
|
||||
if (!normalized) return;
|
||||
const existing = aliasMap.get(normalized) ?? [];
|
||||
existing.push(agentId);
|
||||
const existing = aliasMap.get(normalized) ?? new Set<string>();
|
||||
existing.add(agentId);
|
||||
aliasMap.set(normalized, existing);
|
||||
};
|
||||
for (const agent of agents) {
|
||||
@@ -310,8 +316,12 @@ export function buildAgentCrudMethods(
|
||||
}
|
||||
|
||||
const matched = new Set<string>();
|
||||
// Only aliases that unambiguously resolve to a single agent are
|
||||
// treated as mentions. Two agents sharing a role ("CEO" appearing
|
||||
// twice in the company) make `@ceo` ambiguous and we refuse to
|
||||
// pick one silently.
|
||||
const uniqueAliases = [...aliasMap.entries()]
|
||||
.filter(([, ids]) => ids.length === 1)
|
||||
.filter(([, ids]) => ids.size === 1)
|
||||
.sort((a, b) => b[0].length - a[0].length);
|
||||
for (const [alias, ids] of uniqueAliases) {
|
||||
const pattern = `@${alias}`;
|
||||
@@ -319,7 +329,8 @@ export function buildAgentCrudMethods(
|
||||
if (idx === -1) continue;
|
||||
const afterIdx = idx + pattern.length;
|
||||
if (afterIdx >= lowerText.length || /[\s,!?.;:\])}>]/.test(lowerText[afterIdx]!)) {
|
||||
matched.add(ids[0]!);
|
||||
const [onlyId] = ids;
|
||||
if (onlyId) matched.add(onlyId);
|
||||
}
|
||||
}
|
||||
return [...matched];
|
||||
|
||||
Reference in new issue
Block a user