fix(react-google-adk): keep every text part of a multi-part event (#6221)
This commit is contained in:
committed by
GitHub
parent
622ac53047
commit
31a049fcfa
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@assistant-ui/react-google-adk": patch
|
||||
---
|
||||
|
||||
fix: keep every text and reasoning part of a multi-part ADK event
|
||||
@@ -1477,3 +1477,86 @@ describe("AdkEventAccumulator - user message handling", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("AdkEventAccumulator - multiple parts in one event", () => {
|
||||
it("keeps every text part of a single non-partial event in order", () => {
|
||||
const acc = new AdkEventAccumulator();
|
||||
const msgs = acc.processEvent(
|
||||
makeEvent({
|
||||
author: "agent",
|
||||
content: { role: "model", parts: [{ text: "A" }, { text: "B" }] },
|
||||
}),
|
||||
);
|
||||
|
||||
expect(msgs[0]?.content).toEqual([
|
||||
{ type: "text", text: "A" },
|
||||
{ type: "text", text: "B" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("preserves the Gemini code-execution shape", () => {
|
||||
const acc = new AdkEventAccumulator();
|
||||
const msgs = acc.processEvent(
|
||||
makeEvent({
|
||||
author: "agent",
|
||||
content: {
|
||||
role: "model",
|
||||
parts: [
|
||||
{ text: "Here is the code:" },
|
||||
{ executableCode: { code: "print(1)", language: "python" } },
|
||||
{ codeExecutionResult: { outcome: "OUTCOME_OK", output: "1" } },
|
||||
{ text: "The result is 1." },
|
||||
],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(msgs[0]?.content).toEqual([
|
||||
{ type: "text", text: "Here is the code:" },
|
||||
{ type: "code", code: "print(1)", language: "python" },
|
||||
{ type: "code_result", output: "1", outcome: "OUTCOME_OK" },
|
||||
{ type: "text", text: "The result is 1." },
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps every reasoning part of a single non-partial event", () => {
|
||||
const acc = new AdkEventAccumulator();
|
||||
const msgs = acc.processEvent(
|
||||
makeEvent({
|
||||
author: "agent",
|
||||
content: {
|
||||
role: "model",
|
||||
parts: [
|
||||
{ text: "First thought", thought: true },
|
||||
{ text: "Second thought", thought: true },
|
||||
],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(msgs[0]?.content).toEqual([
|
||||
{ type: "reasoning", text: "First thought" },
|
||||
{ type: "reasoning", text: "Second thought" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("still replaces the streamed buffer with the final text", () => {
|
||||
const acc = new AdkEventAccumulator();
|
||||
acc.processEvent(makeTextEvent("Hel", true));
|
||||
acc.processEvent(makeTextEvent("lo", true));
|
||||
const msgs = acc.processEvent(
|
||||
makeEvent({
|
||||
author: "agent",
|
||||
content: {
|
||||
role: "model",
|
||||
parts: [{ text: "Hello" }, { text: "Again" }],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(msgs[0]?.content).toEqual([
|
||||
{ type: "text", text: "Hello" },
|
||||
{ type: "text", text: "Again" },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -191,6 +191,8 @@ export class AdkEventAccumulator {
|
||||
private messagesMap = new Map<string, AdkMessage>();
|
||||
private currentMessageId: string | null = null;
|
||||
private partialTextBuffer = "";
|
||||
private finalTextReplacedThisEvent = false;
|
||||
private finalReasoningReplacedThisEvent = false;
|
||||
private partialReasoningBuffer = "";
|
||||
private accumulatedStateDelta: Record<string, unknown> = {};
|
||||
private accumulatedArtifactDelta: Record<string, number> = {};
|
||||
@@ -387,6 +389,11 @@ export class AdkEventAccumulator {
|
||||
}
|
||||
}
|
||||
|
||||
// Replace-semantics close out the streamed partial buffer, which only
|
||||
// the first final text/reasoning part of an event may do; later parts
|
||||
// of the same event are distinct content and append.
|
||||
this.finalTextReplacedThisEvent = false;
|
||||
this.finalReasoningReplacedThisEvent = false;
|
||||
for (const [index, part] of parts.entries()) {
|
||||
this.processPart(part, event, index);
|
||||
}
|
||||
@@ -472,9 +479,12 @@ export class AdkEventAccumulator {
|
||||
if (event.partial) {
|
||||
this.partialReasoningBuffer += part.text;
|
||||
this.replaceLastReasoningContent(msg, this.partialReasoningBuffer);
|
||||
} else {
|
||||
} else if (!this.finalReasoningReplacedThisEvent) {
|
||||
this.finalReasoningReplacedThisEvent = true;
|
||||
this.partialReasoningBuffer = "";
|
||||
this.replaceLastReasoningContent(msg, part.text);
|
||||
} else {
|
||||
this.appendContent(msg, { type: "reasoning", text: part.text });
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -485,9 +495,12 @@ export class AdkEventAccumulator {
|
||||
if (event.partial) {
|
||||
this.partialTextBuffer += part.text;
|
||||
this.replaceLastTextContent(msg, this.partialTextBuffer);
|
||||
} else {
|
||||
} else if (!this.finalTextReplacedThisEvent) {
|
||||
this.finalTextReplacedThisEvent = true;
|
||||
this.partialTextBuffer = "";
|
||||
this.replaceLastTextContent(msg, part.text);
|
||||
} else {
|
||||
this.appendContent(msg, { type: "text", text: part.text });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user