字符串与 index 在读取中被改写
Bedrock Converse 消息的 `AIMessage.content_blocks` 看似只是读取派生表示,实际却会改写源 `message.content`:字符串会被替换成文本块列表,未知字典块的 `index` 会被 `pop()` 移除。第一次读取已经污染原始消息,连续两次读取还可能返回不同结果。

面向 Agent 与 LLM 应用的开源 Python 框架,通过统一的模型、消息、工具、检索与中间件接口连接不同提供商和组件,为可组合、可扩展的智能体工程提供核心基础设施。
`content_blocks` 可以规范化 provider 内容,但每次读取都必须从同一个未被污染的源消息出发。
"hello"[{"type": "text", …}]SOURCE MUTATEDmessage.content→ local derive →VIEWcontent_blocks{ type: "custom", index: 3 }copy · lift indexsource keeps index ✓Bedrock Converse 消息的 `AIMessage.content_blocks` 看似只是读取派生表示,实际却会改写源 `message.content`:字符串会被替换成文本块列表,未知字典块的 `index` 会被 `pop()` 移除。第一次读取已经污染原始消息,连续两次读取还可能返回不同结果。
`content_blocks` 是只读属性,调用方应能安全地重复读取,并继续序列化、持久化原始 provider 内容。修复边界不在于深拷贝整个消息,而是让字符串转换只使用局部列表,并在提升未知块的 `index` 前复制该字典,从最小范围切断写回源对象的路径。
字符串内容只在局部列表中转换,不再写回 `message.content`;处理未知字典块时先复制对象,再从副本提升 `index`。参数化回归覆盖 `AIMessage` / `AIMessageChunk`、字符串、自定义块及连续读取,直接锁定派生视图与源对象之间的只读边界。
读取 `content_blocks` 不再改变原始字符串或删除未知块的 `index`;同一消息的连续读取保持一致,后续序列化与持久化仍能获得完整的 provider 原始内容。两类消息对象与两条原地修改路径均由回归测试覆盖。
维护者通过 PR #40022 合并修复,并在最终提交中以 Co-authored-by 明确保留 Zhewen Tan(@tandede)的共同作者署名。