[spring-ai] Wrapping ChatModels without getOptions() override fail with ClassCastException when ADK tools are attached
維護者通常 1 天內回覆
@hirematha 已經在處理了。
開始於 2026年10月30日。
評估
這個 Issue 還沒有評估資料。
描述
Describe the Bug
When the configured ChatModel is a delegating/wrapping implementation that does not override getOptions() (the interface default returns an empty DefaultChatOptions), any ADK request with tools fails with a bare ClassCastException deep inside the provider model.
Chain:
SpringAI.resolveDefaultOptions()returns the model'sgetOptions()— for wrappers, the interface default: an emptyDefaultChatOptions, not null, so the existing null handling never engages;MessageConverter.buildChatOptions(...)sees defaults that are notToolCallingChatOptionsand falls into thehasToolsbranch, building provider-neutralToolCallingChatOptions;- Provider models that cast
Prompt.getOptions()to their own type — e.g.OpenAiChatModel.createRequest(...)casting toOpenAiChatOptions— throwClassCastException: DefaultToolCallingChatOptions cannot be cast to OpenAiChatOptions.
The failure surfaces several frames away from the cause and gives no hint that the wrapper's getOptions() is the origin. We hit this in production with a failover wrapper (2026-09-28): the non-streaming fallback path died on its first call.
Note the related hardening in resolveDefaultOptions() (avoiding the same cast by using the model's own options) covers the "options available" half; this report is the "defaults are the empty interface default" half.
To Reproduce
// Any delegating wrapper that forgets to override getOptions()
class ForgettingWrapper implements ChatModel, StreamingChatModel {
private final ChatModel delegate;
// call()/stream() delegate; getOptions() intentionally NOT overridden
}
SpringAI springAI = new SpringAI(new ForgettingWrapper(openAiChatModel));
springAI.generateContent(
LlmRequest.builder()
.contents(List.of(userContent("hello")))
.tools(Map.of("ping", pingTool)) // any ADK tool
.build(),
false);
// -> RuntimeException wrapping ClassCastException:
// DefaultToolCallingChatOptions cannot be cast to org.springframework.ai.openai.OpenAiChatOptions
(Verified with a probe test on current main: the wrapper's getOptions() returns DefaultChatOptions@..., instanceof ToolCallingChatOptions is false, and the cast fails exactly as above.)
Expected behavior
At minimum, an actionable warning/error at the bridge level naming the actual cause ("the wrapping model's getOptions() returns non-provider options; delegate it to the underlying model's options"), instead of a bare ClassCastException from inside the provider. Fail-fast would also be reasonable, except that dummy/test models legitimately use the same default — so we prototyped a WARN in MessageConverter.buildChatOptions (branch: https://github.com/google/adk-java/compare/main...caps-xia:adk-java:fix/wrapper-chatmodel-options-cce, 307 tests green) and are happy to open a PR if the direction sounds right.
Environment
- google/adk-java main (post the
resolveDefaultOptionshardening) - Spring AI 2.0.1, spring-ai-openai
Additional context
Wrapping/decorating ChatModels (failover, retry, caching, audit) are a common Spring AI pattern; any of them without an explicit getOptions() override hits this the moment ADK tools are attached. A one-line doc note in the SpringAI README ("wrappers must delegate getOptions()") would also help.
- 主要語言
- Java
- 星號
- 1.8k
- 分支
- 442
- 平均合併
- 3 天 13 小時
- 30 天內合併 PR
- 95
環境準備
在瀏覽器裡用你自己的 GitHub 帳號啟動這個專案的開發容器。
- 沒有 Dockerfile 或 Docker Compose 檔案
- 有 Pull Request 範本
- 閱讀貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
google/adk-java 的其他 Issue
-
InMemorySessionService.appendEvent recreates a deleted session可能已有人在做 @hirematha 於 5 天前認領。 未關閉needs review
難度 2/5 1-3 小時 新手友好度 84/100
google/adk-java#1697 · 2 則留言 · 已指派 1 人 ·
維護者通常 1 天內回覆
-
Runner drops callbackContextData written in onUserMessageCallback when it resumes an invocation可能已有人在做 @hirematha 於 5 天前認領。 未關閉needs review
難度 2/5 1-3 小時 新手友好度 78/100
google/adk-java#1695 · 1 則留言 · 已指派 1 人 ·
維護者通常 1 天內回覆
-
AgentExecutor ignores the A2A contextId when creating a session, so multi-turn conversations start over every turn可能已有人在做 @hirematha 於 3 天前認領。 未關閉needs review
google/adk-java#1718 · 2 則留言 · 已指派 1 人 ·
維護者通常 1 天內回覆
-
McpToolset hangs silently for ~5 minutes per retry (3 retries) when stdio command is an npm shim ("npx") on Windows可能已有人在做 @hemasekhar-p 於 9 天前認領。 未關閉needs review
google/adk-java#1686 · 4 則留言 · 已指派 1 人 ·
維護者通常 1 天內回覆
-
runLive passes partial events to appendEvent and never aggregates text chunks, unlike ADK Python可能已有人在做 @hemasekhar-p 於 19 天前認領。 未關閉needs review
難度 4/5 3-5 天 新手友好度 45/100
google/adk-java#1648 · 3 則留言 · 已指派 1 人 ·
維護者通常 1 天內回覆
相似的 Issue
-
難度 2/5 1-3 小時 新手友好度 82/100
維護者通常 1 天內回覆
-
難度 1/5 1 小時以內 新手友好度 88/100
quarkusio/quarkus-agent-mcp#302 ·
維護者通常 2 天內回覆
-
build
難度 1/5 1 小時以內 新手友好度 85/100
MetricsHub/metricshub-community#1472 ·
維護者通常 1 天內回覆
-
難度 2/5 1-3 小時 新手友好度 82/100
維護者通常 1 天內回覆
-
IdentityArrayObjectSet iterator remove may throw ArrayIndexOutOfBoundsException可能已有人在做 @jiteshkhatri11 今天認領。 未關閉
難度 2/5 1-3 小時 新手友好度 72/100
javapathfinder/jpf-core#660 · 1 則留言 ·