schema: ConcatAgenticMessages loses streamed MCP tool result chunks and corrupts reasoning signatures
Summary
Two field-merge defects in ConcatAgenticMessages (schema/agentic_message.go) cause data loss / data corruption when concatenating streamed agentic messages:
1. concatMCPToolResults keeps only the last content chunk
schema/agentic_message.go:1821 does ret.Content = r.Content, overwriting previous chunks. A streamed MCP tool result therefore keeps only its final chunk. The sibling concatMCPToolCalls correctly accumulates (ret.Arguments += c.Arguments, line 1781), so the asymmetry looks like a copy-paste mistake — and the existing test even asserted the buggy behavior.
msgs := []*AgenticMessage{
{Role: AgenticRoleTypeAssistant, ContentBlocks: []*ContentBlock{
NewContentBlockChunk(&MCPToolResult{CallID: "c1", Name: "tool", Content: `{"part1":`}, &StreamingMeta{Index: 0})}},
{Role: AgenticRoleTypeAssistant, ContentBlocks: []*ContentBlock{
NewContentBlockChunk(&MCPToolResult{CallID: "c1", Name: "tool", Content: `"value"}`}, &StreamingMeta{Index: 0})}},
}
m, _ := ConcatAgenticMessages(msgs)
// got: Content == `"value"}` (first chunk lost)
// want: Content == `{"part1":"value"}`2. concatReasoning corrupts the signature by string-concatenating it
schema/agentic_message.go:1327 does ret.Signature += r.Signature. A reasoning Signature is an opaque integrity/encryption token, not appendable text. Adapters commonly repeat the same signature across chunks; concatenating produces e.g. sig-abcsig-abc, which fails verification when the message is sent back to the model. The old *Message API (mergeReasoningParts, schema/message.go:1491-1493) keeps the last non-empty signature — the two APIs now disagree.
Expected behavior
- MCP tool result
Contentchunks append (likeMCPToolCall.Arguments). - Reasoning
Signaturekeeps the last non-empty value (parity withmergeReasoningParts).
Both reproduce on current main (9d983b36) and alpha/10. I have a fix with regression tests ready and will open a PR shortly.
Source: cloudwego/eino