Skip to content

Commit 847f6f6

Browse files
committed
fix(core): preserve speaker names in prior dialogue context
1 parent fa83dde commit 847f6f6

2 files changed

Lines changed: 150 additions & 1 deletion

File tree

packages/core/src/__tests__/message-runtime-stage1.test.ts

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2100,6 +2100,98 @@ android smoke model works`,
21002100
);
21012101
});
21022102

2103+
it("keeps speaker names on structured prior dialogue", async () => {
2104+
const runtime = makeRuntime([
2105+
stage1Response({
2106+
contexts: ["simple"],
2107+
replyText: "I see the prior chat context.",
2108+
extra: { requiresTool: false },
2109+
}),
2110+
]);
2111+
const state: State = {
2112+
values: {
2113+
availableContexts: "simple, general",
2114+
},
2115+
data: {
2116+
providers: {
2117+
RECENT_MESSAGES: {
2118+
text: "# Conversation Messages\nprovider text should not render",
2119+
data: {
2120+
recentMessages: [
2121+
{
2122+
id: "00000000-0000-0000-0000-00000000bb01" as UUID,
2123+
entityId: "00000000-0000-0000-0000-00000000bb11" as UUID,
2124+
agentId: runtime.agentId,
2125+
roomId: "00000000-0000-0000-0000-000000001111" as UUID,
2126+
createdAt: 1,
2127+
content: {
2128+
text: "Hey, nice to meet shebotdick.",
2129+
source: "discord",
2130+
},
2131+
metadata: {
2132+
type: "message",
2133+
sender: {
2134+
id: "discord-botdick",
2135+
name: "botdick",
2136+
username: "botdick",
2137+
},
2138+
},
2139+
},
2140+
{
2141+
id: "00000000-0000-0000-0000-00000000bb02" as UUID,
2142+
entityId: "00000000-0000-0000-0000-00000000bb12" as UUID,
2143+
agentId: runtime.agentId,
2144+
roomId: "00000000-0000-0000-0000-000000001111" as UUID,
2145+
createdAt: 2,
2146+
content: {
2147+
text: "i was asking about shedick",
2148+
source: "discord",
2149+
},
2150+
metadata: {
2151+
type: "message",
2152+
sender: {
2153+
id: "discord-1gig",
2154+
name: "1gig",
2155+
username: "1gig",
2156+
},
2157+
},
2158+
},
2159+
],
2160+
},
2161+
providerName: "RECENT_MESSAGES",
2162+
},
2163+
},
2164+
},
2165+
text: "fallback text should not be needed",
2166+
};
2167+
2168+
await runV5MessageRuntimeStage1({
2169+
runtime,
2170+
message: makeMessage({
2171+
text: "whats the compatibility between her and botdick",
2172+
}),
2173+
state,
2174+
responseId: "00000000-0000-0000-0000-000000000005" as UUID,
2175+
});
2176+
2177+
const firstCall = useModelCalls(runtime)[0];
2178+
const params = firstCall?.[1] as {
2179+
messages?: Array<{ role?: string; content?: string | null }>;
2180+
};
2181+
const userContent = params.messages?.[1]?.content ?? "";
2182+
expect(userContent).not.toContain("# Conversation Messages");
2183+
expect(userContent).not.toContain("provider text should not render");
2184+
expect(userContent).toContain(
2185+
"prior_message:user:\nbotdick: Hey, nice to meet shebotdick.",
2186+
);
2187+
expect(userContent).toContain(
2188+
"prior_message:user:\n1gig: i was asking about shedick",
2189+
);
2190+
expect(userContent).toContain(
2191+
"message:user:\nwhats the compatibility between her and botdick",
2192+
);
2193+
});
2194+
21032195
it("recomposes planner state with selected context providers but excludes catalogs", async () => {
21042196
const runtime = makeRuntime([
21052197
stage1Response({

packages/core/src/services/message.ts

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1599,6 +1599,61 @@ function asProviderRecord(value: unknown):
15991599
};
16001600
}
16011601

1602+
function asPlainRecord(value: unknown): Record<string, unknown> | undefined {
1603+
if (!value || typeof value !== "object" || Array.isArray(value)) {
1604+
return undefined;
1605+
}
1606+
return value as Record<string, unknown>;
1607+
}
1608+
1609+
function cleanPriorDialogueSpeakerName(value: unknown): string | undefined {
1610+
if (typeof value !== "string") return undefined;
1611+
const normalized = value.trim().split(/\s+/).join(" ");
1612+
if (!normalized) return undefined;
1613+
return normalized.length > 80 ? `${normalized.slice(0, 77)}...` : normalized;
1614+
}
1615+
1616+
function senderIdentityName(value: unknown): string | undefined {
1617+
const record = asPlainRecord(value);
1618+
if (!record) return undefined;
1619+
return (
1620+
cleanPriorDialogueSpeakerName(record.name) ??
1621+
cleanPriorDialogueSpeakerName(record.username) ??
1622+
cleanPriorDialogueSpeakerName(record.tag)
1623+
);
1624+
}
1625+
1626+
function priorDialogueSpeakerName(memory: Memory): string | undefined {
1627+
const metadata = asPlainRecord(memory.metadata);
1628+
const content = asPlainRecord(memory.content);
1629+
const contentMetadata = asPlainRecord(content?.metadata);
1630+
const sender =
1631+
senderIdentityName(metadata?.sender) ??
1632+
senderIdentityName(contentMetadata?.sender);
1633+
if (sender) return sender;
1634+
for (const record of [metadata, contentMetadata, content]) {
1635+
const name =
1636+
cleanPriorDialogueSpeakerName(record?.entityName) ??
1637+
cleanPriorDialogueSpeakerName(record?.senderName) ??
1638+
cleanPriorDialogueSpeakerName(record?.authorName) ??
1639+
cleanPriorDialogueSpeakerName(record?.displayName) ??
1640+
cleanPriorDialogueSpeakerName(record?.userName) ??
1641+
cleanPriorDialogueSpeakerName(record?.username) ??
1642+
cleanPriorDialogueSpeakerName(record?.name);
1643+
if (name) return name;
1644+
}
1645+
return undefined;
1646+
}
1647+
1648+
function priorDialogueContent(text: string, speaker?: string): string {
1649+
if (!speaker) return text;
1650+
const trimmedStart = text.trimStart();
1651+
if (trimmedStart.toLowerCase().startsWith(`${speaker.toLowerCase()}:`)) {
1652+
return text;
1653+
}
1654+
return `${speaker}: ${text}`;
1655+
}
1656+
16021657
function appendPriorDialogueEvents(
16031658
events: ContextEvent[],
16041659
runtime: IAgentRuntime,
@@ -1657,6 +1712,7 @@ function appendPriorDialogueEvents(
16571712
for (const memory of dialogue) {
16581713
const text = getUserMessageText(memory);
16591714
if (!text) continue;
1715+
const speakerName = priorDialogueSpeakerName(memory);
16601716
events.push({
16611717
id: `history:${memory.id}`,
16621718
type: "segment",
@@ -1665,11 +1721,12 @@ function appendPriorDialogueEvents(
16651721
segment: {
16661722
id: `history:${memory.id}`,
16671723
label: "prior_message:user",
1668-
content: text,
1724+
content: priorDialogueContent(text, speakerName),
16691725
stable: false,
16701726
metadata: {
16711727
roomId: memory.roomId,
16721728
entityId: memory.entityId,
1729+
...(speakerName ? { speakerName } : {}),
16731730
},
16741731
},
16751732
});

0 commit comments

Comments
 (0)