fix(ui): stop rendering the model's thought signature in the answer - #2355
Open
garlicKim21 wants to merge 5 commits into
Open
fix(ui): stop rendering the model's thought signature in the answer#2355garlicKim21 wants to merge 5 commits into
garlicKim21 wants to merge 5 commits into
Conversation
Gemini attaches an encrypted `thoughtSignature` to the parts it returns. It is
protocol state, meant to be round-tripped into the next request, not content.
It arrives as an unlabeled data part alongside the text part, so it matches
neither the function_call nor the function_response branch in the artifact
handler and falls through to the JSON.stringify fallback, which appends it to
the visible answer:
...verify the actual cluster resources before answering.{"thoughtSignature":"EjQKMgER..."}
There is no separator because the text and the stringified data are
concatenated. The same fallback exists in aggregatePartsToText for plain A2A
messages.
Data parts that carry only model-internal keys are now skipped in both places,
next to the existing skip for the empty lastChunk sentinel. Unlabeled data
parts that are real content still render as before.
The signature itself is unaffected: it reaches the UI as a structured field and
is stored as one, so nothing is lost by not printing it.
Signed-off-by: Golden Garlic <148346166+garlicKim21@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Gemini attaches an encrypted
thoughtSignatureto the parts it returns. It isprotocol state — meant to be round-tripped into the next request — not content.
It reaches the UI as an unlabeled data part next to the text part, so it matches
neither the
function_callnor thefunction_responsebranch inhandleA2ATaskArtifactUpdateand falls through to theJSON.stringifyfallback,which appends it to the visible answer. There is no separator because the text
and the stringified data are concatenated:
aggregatePartsToTexthas the same fallback for plain A2A messages.Data parts carrying only model-internal keys are now skipped in both places,
right next to the existing skip for the empty
lastChunksentinel. Unlabeleddata parts that are real content still render exactly as before.
What the stream actually contains
Captured from an agent's A2A
message/stream(Gemini 3 model, Go ADK runtime):The signature arrives structured and is stored structured — the persisted event
rows carry it as its own field and never inside message text. So nothing is lost
by not printing it; this is a rendering-only defect, and reasoning continuity is
not affected.
Environment
kagent controller/UI 0.9.12, kmcp controller 0.3.0, kagent tools 0.2.1.
Declarative agent, native Gemini
ModelConfig(provider: Gemini), Go ADK runtime.Related but not duplicates: #1631 preserves
thought_signatureacrossOpenAI-compatible tool-call round trips (encoded into the tool-call id), and
#2032 covers those ids overflowing the chat column. Both concern the tool-call
id; this is the assistant message body, and the field here is camelCase
thoughtSignature(the Gemini RESTPartspelling).Testing
ui/src/lib/__tests__/messageHandlers.test.tsgains two cases: the signaturepart is dropped, and an unlabeled data part that is genuine content still
renders. Full UI suite: 346 passed.
Independent of #2351 and #2352 — different file, no overlap.