feat(adk): generify all remaining middlewares for AgenticMessage support#1003
Open
shentongmartin wants to merge 11 commits intoalpha/09from
Open
feat(adk): generify all remaining middlewares for AgenticMessage support#1003shentongmartin wants to merge 11 commits intoalpha/09from
shentongmartin wants to merge 11 commits intoalpha/09from
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## alpha/09 #1003 +/- ##
===========================================
Coverage ? 83.09%
===========================================
Files ? 162
Lines ? 22712
Branches ? 0
===========================================
Hits ? 18872
Misses ? 2590
Partials ? 1250 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
c3269ee to
06d874d
Compare
a2349f8 to
91925ac
Compare
mrh997
reviewed
May 11, 2026
| }).(func(context.Context, []M, []*schema.ToolInfo) (int64, error)) | ||
| case *schema.AgenticMessage: | ||
| return any(func(ctx context.Context, msgs []*schema.AgenticMessage, tools []*schema.ToolInfo) (int64, error) { | ||
| var tokens int64 |
| } | ||
| // fromContent=true when there's exactly one text part (simple case), | ||
| // false when there are multiple parts (multi-part). | ||
| isSimple := len(parts) == 1 && parts[0].Type == schema.ToolPartTypeText |
| } | ||
| // A user-role agentic message that only contains FunctionToolResult blocks | ||
| // is a tool result message, not a normal user message. | ||
| for _, block := range m.ContentBlocks { |
Contributor
There was a problem hiding this comment.
有点别扭,user message 如果同时存在 UserInput 和 FunctionToolResult 是不是不能当作是普通 user message 处理
| } | ||
| case *schema.AgenticMessage: | ||
| // Find the first FunctionToolResult block and replace its Blocks. | ||
| for _, block := range m.ContentBlocks { |
Contributor
There was a problem hiding this comment.
写成一个方法?类似 toolResult.ToMessageInputParts()
| // (e.g., message reduction, tool call patching), which is naturally supported by composing | ||
| // middlewares in an agent pipeline. | ||
| func SummarizeMessages(ctx context.Context, cfg *Config, messages []adk.Message) (*SummarizeOutput, error) { | ||
| func TypedSummarizeMessages[M adk.MessageType](ctx context.Context, cfg *TypedConfig[M], messages []M) (*TypedSummarizeOutput[M], error) { |
| if block == nil { | ||
| continue | ||
| } | ||
| if block.UserInputText != nil { |
Contributor
There was a problem hiding this comment.
和extractTextContent的处理不一致,这个方法应该叫 getUserTextContent。原来 trim 逻辑也有点不太对,不应该破坏原来的 MultiPart 结构。第二点如果不好改,合入之后我来改也行。
| continue | ||
| } | ||
| if block.AssistantGenText != nil { | ||
| content += block.AssistantGenText.Text |
Refactor 7 ADK middlewares to be generic over M adk.MessageType, enabling support for both *schema.Message and *schema.AgenticMessage: - plantask: trivial conversion (no message access) - patchtoolcalls: dual implementation with type-switch dispatch - agentsmd: generic insertBeforeFirstUser with type-switch - toolsearch: generic extractToolSearchResult with ContentBlock iteration - reduction: full genericization of Config callbacks, token counting, message copying, clear rewrite, and tool result extraction - summarization: full genericization of all 6 callback types, internal methods, and new TypedSummarizeMessages[M] public API - skill: generic AgentHub, ModelHub, skillTool with fork mode support, TypedAgentHubOptions[M] with model.BaseModel[M] Each middleware follows the TypedXxx[M] + backward-compatible alias pattern. All generic code paths include native AgenticMessage implementations (no pass-through). Added AgenticState export to adk/react.go for compose.ProcessState usage. Added table-driven generic tests for all 7 middlewares, exercising both *schema.Message and *schema.AgenticMessage paths: helper functions, clear flow, truncation, end-to-end summarization, agent mode, fork mode, reminder insertion, tool search result extraction, and tool call patching. Change-Id: I4f97e61dbc451c42753b3e2847899d920b8d5e72
…compat Go 1.18/1.19 does not support type declarations inside generic functions. Move agentsMDTestCase struct to package level to fix CI build failure. Change-Id: I2617d8cde8a663420fab46fa32a9e7379896a409
Cover Image/Audio/Video/File branches in toolResultFromMsgGeneric and setToolResultContent for *schema.AgenticMessage, exercising all FunctionToolResultBlock media variants and their round-trip through ToolOutputPart conversion. Change-Id: I57ca915e9f92da9c1d6fe40d5c6fb25826d0b54b
Replace convoluted []M↔[]*ConcreteType round-trip conversions with a single generic iteration path. Extract isUserRole[M] and makeUserMsgWithExtra[M] helpers, remove the two duplicate concrete insertBeforeFirst* functions. Change-Id: Iee3fd5f7714710faea1429f124395890d1854643
Replace []M↔[]*ConcreteType round-trip conversions and two duplicate concrete ensureReminder* methods with a single generic loop using isSystemRoleTS[M] and makeReminderMsg[M] helpers. Change-Id: I05f5b2f16f9cd18e73957865fe626ef3bcc6c575
Delete AgenticState alias from react.go — the internal agenticState is unexported by design and should not leak to middleware packages. Mark fork mode unsupported for AgenticMessage with a clear error. Remove IsNilMessage from adk's exported API; skill package defines its own local isNilMessage helper instead. Change-Id: Idc972e578846f5f15b3220a949c147e565f633b5
Fix emitEvent crash for AgenticMessage agents by using TypedSendEvent[M] with generic TypedCustomizedAction[M]. Add missing afterToolCallsHook in newAgenticReact. Guard nil messages in reduction copy functions. Merge 3 valuable attack tests into formal test suites and remove attack test files. Change-Id: I295966fb752de88128571ed5149ff909ea745a06
…edMiddleware Remove inferable type arguments across all middleware packages and tests. Rename skill.NewTypedMiddleware to skill.NewTyped for consistency with other middlewares. Simplify typedInsertBeforeFirstUser by eliminating redundant inserted flag. Delete unused defaultShouldRetry in summarization. Change-Id: I97d08c6a8e6e74b02cceac726dd9019e2065fd34
The token counter was reading tools from TypedModelContext.Tools which is deprecated, constructed once at graph-build time, and never reflects modifications by earlier handlers. Switch to state.ToolInfos which is the persisted source of truth. Add test asserting the correct source is used. Change-Id: I15a41ac2a0b990956bd1f814951a513023dbb55b
…ter rebase Adapt to alpha/09's schema rename (39d5285): FunctionToolResultBlock → FunctionToolResultContentBlock, .Blocks → .Content. Export FunctionToolResultAgenticMessage from adk/wrappers.go for middleware use. Change-Id: Idde280443dedf33351897de885b5c0dd550eb817
91925ac to
85bdb37
Compare
- Extract defaultAgenticTokenCounter from inline lambda (reduction) - Add FunctionToolResult.ToToolOutputParts/SetFromToolOutputParts methods to schema, replacing manual conversion loops in reduction - Rename getTextContent → getMsgTextContent (summarization) for consistency with existing setMsgTextContent - Use newline-separated join for multi-block text in skill fork mode Change-Id: I0eebb193522d40f35aca75ac93a6730148c4e95c
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.
Generify All Remaining Middlewares for AgenticMessage
Problem
The ADK core, deep agent, and filesystem middleware already support
AgenticMessageviaTypedChatModelAgentMiddleware[M], but the 7 remaining middlewares underadk/middlewares/are hardcoded to*schema.Message. This blocks any agent using*schema.AgenticMessagefrom leveraging these middlewares for tool call patching, context reduction, summarization, skill execution, etc.Solution
Generify all 7 middlewares over
M adk.MessageTypeusing the establishedTypedXxx[M]+ backward-compatible alias pattern. Every middleware now has aNewTyped[M]constructor alongside the existingNew(), with internal struct renamed totypedXxxMiddleware[M].The key challenge:
*schema.Messageand*schema.AgenticMessagehave fundamentally different field structures (flatRole/Content/ToolCallsvs nestedAgenticRoleType/ContentBlocks). Each middleware needed type-switch dispatch to handle both:For hard middlewares (reduction, summarization, skill), this required genericizing Config callback types, internal helper functions, and deep message field accessors — not just the struct/constructor.
Decisions
Full AgenticMessage support vs pass-through: Initially considered making hard middlewares pass-through for
*schema.AgenticMessage(return messages unchanged). Rejected — the plan explicitly requires native support, and pass-through defeats the purpose of the middleware.Generic internal methods vs separate implementations: For reduction/summarization, chose generic helper functions (
isAssistantMsg[M],getToolCallsGeneric[M],copyMessagesGeneric[M], etc.) with type-switch dispatch over maintaining two complete parallel implementations. This keeps the main algorithm in one place while isolating type-specific field access.model.BaseModel[M]for skill:AgentHubOptions.ModelandModelHub.Get()changed frommodel.ToolCallingChatModeltomodel.BaseModel[M]. This is required becauseToolCallingChatModelis an alias forBaseModel[*schema.Message], which would leak*schema.Messageinto generic code.Key Insight
*schema.AgenticMessagehas no tool role — tool results areContentBlockTypeFunctionToolResultblocks in user-role messages. Any middleware that checks for "tool messages" (reduction, patchtoolcalls) needs fundamentally different detection logic for agentic messages: iterateContentBlockslooking forFunctionToolResultentries instead of checkingmsg.Role == schema.Tool.Summary
*schema.MessagetypedXxxMiddleware[M]withNewTyped[M]+New()delegation*schema.AgenticMessagehas different field structure*schema.MessageTypedConfig[M]withConfig = TypedConfig[*schema.Message]aliasAgentHubOptions.Modelleaks*schema.MessageviaToolCallingChatModelmodel.BaseModel[M]inTypedAgentHubOptions[M]AgenticMessageContentBlocksforFunctionToolResultinstead of role check泛化所有剩余中间件以支持 AgenticMessage
问题
ADK 核心、deep agent 和 filesystem 中间件已通过
TypedChatModelAgentMiddleware[M]支持AgenticMessage,但adk/middlewares/下的 7 个中间件仍硬编码为*schema.Message。这导致使用*schema.AgenticMessage的 agent 无法利用这些中间件进行 tool call 修补、上下文缩减、摘要生成、技能执行等。方案
将所有 7 个中间件泛化为
M adk.MessageType,使用已有的TypedXxx[M]+ 向后兼容别名模式。每个中间件新增NewTyped[M]构造函数,保留已有的New(),内部结构重命名为typedXxxMiddleware[M]。核心挑战:
*schema.Message和*schema.AgenticMessage的字段结构完全不同(扁平的Role/Content/ToolCallsvs 嵌套的AgenticRoleType/ContentBlocks)。每个中间件需要 type-switch 分发来处理两种类型:对于复杂中间件(reduction、summarization、skill),这要求泛化 Config 回调类型、内部辅助函数和深层消息字段访问器——不仅仅是 struct/constructor。
决策
完整 AgenticMessage 支持 vs 透传:最初考虑让复杂中间件对
*schema.AgenticMessage做透传(原样返回消息)。被否决——计划明确要求原生支持,透传违背中间件的本意。泛型内部方法 vs 独立实现:对于 reduction/summarization,选择使用泛型辅助函数(
isAssistantMsg[M]、getToolCallsGeneric[M]、copyMessagesGeneric[M]等)配合 type-switch 分发,而非维护两套完整的并行实现。这样主算法保持在一处,类型相关的字段访问被隔离。skill 使用
model.BaseModel[M]:AgentHubOptions.Model和ModelHub.Get()从model.ToolCallingChatModel改为model.BaseModel[M]。因为ToolCallingChatModel是BaseModel[*schema.Message]的别名,会将*schema.Message泄漏到泛型代码中。关键洞察
*schema.AgenticMessage没有 tool 角色——工具结果是 user 角色消息中的ContentBlockTypeFunctionToolResultblock。任何检查"工具消息"的中间件(reduction、patchtoolcalls)都需要针对 agentic message 采用完全不同的检测逻辑:遍历ContentBlocks查找FunctionToolResult条目,而非检查msg.Role == schema.Tool。总结
*schema.MessagetypedXxxMiddleware[M]+NewTyped[M]+New()委托*schema.AgenticMessage字段结构不同*schema.MessageTypedConfig[M]+Config = TypedConfig[*schema.Message]别名AgentHubOptions.Model通过ToolCallingChatModel泄漏*schema.MessageTypedAgentHubOptions[M]中的model.BaseModel[M]AgenticMessage没有 tool 角色ContentBlocks查找FunctionToolResult而非角色检查