Python: fix(python): Filter unsupported kwargs in OllamaChatClient._inner_get_response#4404
Conversation
…_response Orchestration layers like HandoffBuilder inject kwargs such as allow_multiple_tool_calls that ollama.AsyncClient.chat() does not accept, causing a TypeError. Filter these kwargs before forwarding to the Ollama API, matching the behavior documented in OllamaChatOptions where these fields are explicitly marked as unsupported. Fixes microsoft#4402
There was a problem hiding this comment.
Pull request overview
Fixes a compatibility bug in the Python Ollama adapter where orchestration-injected parameters can be forwarded to ollama.AsyncClient.chat() and cause a TypeError.
Changes:
- Add a small denylist of unsupported chat kwargs and filter them before calling
AsyncClient.chat()(streaming and non-streaming). - Add regression tests ensuring
allow_multiple_tool_callsis stripped when passed as a top-level kwarg.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
python/packages/ollama/agent_framework_ollama/_chat_client.py |
Introduces _UNSUPPORTED_CHAT_KWARGS and filters **kwargs before delegating to ollama.AsyncClient.chat(). |
python/packages/ollama/tests/test_ollama_chat_client.py |
Adds regression tests validating that unsupported kwargs are not forwarded in both streaming and non-streaming paths. |
| # Filter out kwargs that are not supported by ollama.AsyncClient.chat(). | ||
| # Orchestration layers (e.g. HandoffBuilder) may inject kwargs like | ||
| # allow_multiple_tool_calls that the Ollama Python client doesn't accept. | ||
| filtered_kwargs = {k: v for k, v in kwargs.items() if k not in _UNSUPPORTED_CHAT_KWARGS} | ||
|
|
There was a problem hiding this comment.
filtered_kwargs prevents unsupported values coming in via **kwargs, but allow_multiple_tool_calls can also arrive via the options mapping (e.g., from Agent.default_options / handoff cloning). Since _prepare_options() currently forwards unknown option keys to ollama.AsyncClient.chat(), this can still raise TypeError even after this change. Consider also stripping allow_multiple_tool_calls (and any other unsupported keys) from options before _prepare_options() runs (e.g., add it to exclude_keys in _prepare_options, or validated_options.pop(...) in _inner_get_response).
| ollama_client = OllamaChatClient() | ||
| # Pass allow_multiple_tool_calls as a kwarg — this is what HandoffBuilder does | ||
| await ollama_client.get_response( | ||
| messages=chat_history, | ||
| allow_multiple_tool_calls=True, | ||
| ) |
There was a problem hiding this comment.
These new tests verify filtering when allow_multiple_tool_calls is passed as a top-level kwarg, but they don’t cover the (common) case where the flag is present inside the options dict (e.g., via Agent.default_options / workflow cloning). Adding a regression assertion for get_response(..., options={"allow_multiple_tool_calls": ...}) (streaming and/or non-streaming) would better ensure the TypeError can’t reappear through the options path.
Address Copilot review feedback: allow_multiple_tool_calls can also arrive via the options mapping (e.g. Agent.default_options, workflow cloning), not just via **kwargs. - Add allow_multiple_tool_calls to exclude_keys in _prepare_options() - Add test_cmc_filters_unsupported_options regression test
LEDazzio01
left a comment
There was a problem hiding this comment.
Good catches! Pushed a follow-up commit (f9b01dc) addressing both:
-
Options path — Added
allow_multiple_tool_callstoexclude_keysin_prepare_options(), so it's stripped whether it arrives via**kwargsor theoptionsdict (e.g. fromAgent.default_options/ workflow cloning). -
Options-path test — Added
test_cmc_filters_unsupported_optionswhich passesallow_multiple_tool_callsinside theoptionsdict and asserts it doesn't reachollama.AsyncClient.chat().
Both entry points are now covered.
| @@ -268,6 +268,13 @@ class OllamaChatOptions(ChatOptions[ResponseModelT], Generic[ResponseModelT], to | |||
| } | |||
| """Maps ChatOptions keys to Ollama model option parameter names.""" | |||
|
|
|||
| # Kwargs that may be injected by orchestration layers (e.g. HandoffBuilder) | |||
There was a problem hiding this comment.
nit: We shouldn't mention downstream modules in the comment. We can just say this framework level key is not supported by the ollama client or it's handled separately.
Address TaoChenOSU nit: use generic 'framework-level kwargs' wording instead of mentioning HandoffBuilder specifically.
LEDazzio01
left a comment
There was a problem hiding this comment.
Good point! Updated the comment in commit 3948f4d to use generic wording ("Framework-level kwargs that are not supported by ollama.AsyncClient.chat()") instead of referencing downstream modules.
| # These are silently stripped in _inner_get_response so they never reach the | ||
| # Ollama API. | ||
| _UNSUPPORTED_CHAT_KWARGS: set[str] = { | ||
| "allow_multiple_tool_calls", |
There was a problem hiding this comment.
this is not a approach we want to take, since that parameter is already set to None in the OllamaChatOptions, people will get notified by their IDE if that is set, if that is being set by something like a workflow then we need to update that. The reason we don't want to hardcode filtering like this is because we want to not block future updates, let's say at some point Ollama does implement support for this parameter, then that will not be usable, because we filter it out, so we decided we would prefer to use the None above to notify the user beforehand that it is likely not right, and then we just let the API tell the user exactly what's wrong.
There was a problem hiding this comment.
So reading more of the above, the real issue is that the HandoffBuilder set's parameters that are not universally applicable, which is what we would need to fix.
|
Closing due this being a duplicate of #4403. |
Summary
Fixes #4402
OllamaChatClient._inner_get_response()forwards**kwargsdirectly toollama.AsyncClient.chat(). When used withHandoffBuilder, kwargs likeallow_multiple_tool_calls=Trueleak through, causing aTypeErrorsince the Ollama Python client doesn't accept this parameter.Changes
_chat_client.py_UNSUPPORTED_CHAT_KWARGSset containing kwargs that orchestration layers inject but Ollama doesn't supportkwargsbefore passing toself.client.chat()in both streaming and non-streaming pathstest_ollama_chat_client.pytest_cmc_filters_unsupported_kwargs— verifiesallow_multiple_tool_callsis stripped in non-streaming modetest_cmc_streaming_filters_unsupported_kwargs— verifies the same for streaming modeMotivation
When
HandoffBuilderis used withOllamaChatClient, it injectsallow_multiple_tool_calls=Trueas a kwarg.OllamaChatOptionsalready documents this as unsupported (allow_multiple_tool_calls: None), but the kwarg was still forwarded to the Ollama API.The fix matches the existing pattern in
_prepare_options()wheretool_choiceis excluded viaexclude_keys.