Repository navigation
Add Ollama provider that injects empty parameters for zero-argument tools - #12879
Andrea-Bruno wants to merge 2 commits into
Conversation
Ollama rejects a function tool that carries no parameters field, failing the whole request with a 400 parser error. Add an Ollama provider that injects an empty object schema for parameterless tools, mirroring the MiniMax provider. Closes QwenLM#12878.
doudouOUC
left a comment
There was a problem hiding this comment.
Thanks for this — the approach mirrors the MiniMax provider (#11834) faithfully, and the factory placement checks out: no existing check claims localhost or ollama-labelled hosts ahead of the new branch, the injection sits on the wire path (
pipeline.tscallsprovider.buildRequestand nothing re-processes tools afterwards), and the scoping stays Ollama-only as intended. Two items:
packages/core/src/core/openaiContentGenerator/provider/ollama.ts:15—'::1'inOLLAMA_LOCAL_HOSTScan never match.new URL('http://[::1]:11434/v1').hostnamereturns'[::1]'(WHATWG URL keeps the square brackets on IPv6 literals), so the comparison at line 31 never hits and an Ollama server reached viahttp://[::1]:11434/v1silently misses this fix. A one-line change to'[::1]'(or stripping brackets before comparing) plus a positive test case inollama.test.ts— the IPv6 path is currently untested, which is how this slipped through.- A note on factory ordering (
index.ts:110): the Zai check matches anyglm-*model name on any hostname and runs before Ollama, so a GLM model served by a local Ollama routes to Zai and keeps the 400. Pre-existing routing, not introduced here — but worth one line in the description's scope section so the fix's coverage is stated precisely. (The other direction works in this PR's favor: Mistral-family models on Ollama now correctly route to Ollama, since the new check precedes Mistral's model-name fallback.)The open item from the triage round also still stands: the description needs the PR template sections (Reviewer Test Plan, Evidence, Tested on, Risk & Scope — including the URL-heuristic breadth — Linked Issues, and the Chinese translation).
感谢提交——方案忠实地复用了 MiniMax provider(#11834)的既有模式,工厂中的放置位置也验证无误:新分支之前没有任何检查会认领 localhost 或带 ollama 标签的主机名;注入位于请求上链路径上(
pipeline.ts调用provider.buildRequest,之后没有任何环节再处理 tools);作用域也如期只限于 Ollama。有两个问题:
packages/core/src/core/openaiContentGenerator/provider/ollama.ts:15——OLLAMA_LOCAL_HOSTS中的'::1'永远无法命中。new URL('http://[::1]:11434/v1').hostname返回的是'[::1]'(WHATWG URL 对 IPv6 字面量保留方括号),因此第 31 行的比较永远不会成立,通过http://[::1]:11434/v1访问的 Ollama 服务会静默地错过本次修复。修复只需一行:改为'[::1]'(或在比较前去掉方括号),并在ollama.test.ts补一个正向用例——IPv6 路径目前没有测试覆盖,问题正是因此漏进来的。- 关于工厂链顺序的一点说明(
index.ts:110):Zai 的检查会按glm-*模型名匹配任意主机名,且排在 Ollama 之前,因此在本地 Ollama 上跑 GLM 模型的用户仍会被路由到 Zai、继续遇到那个 400。这是既有路由行为、并非本 PR 引入——但建议在描述的 scope 章节里写上一句,准确说明本次修复的覆盖范围。(另一个方向对本 PR 有利:Mistral 系模型跑在 Ollama 上现在会正确路由到 Ollama,因为新检查位于 Mistral 的模型名回退匹配之前。)另外 triage 轮次中尚未完成的事项依然有效:描述需要按 PR 模板补齐各章节(Reviewer Test Plan、Evidence、Tested on、Risk & Scope——包括 URL 识别规则的覆盖面——Linked Issues,以及中文翻译)。
|
Thanks for the precise review. I fixed the IPv6 case. The loopback list now holds the bracketed form, so a server reached over http://[::1]:11434/v1 is matched, and I added a positive test for that path. The unit tests pass locally, eight in all. |
|
We opened issue #13205 to note that this pull request is held up by the "review-pr" check timing out. That failure is inside the review job and not in our code, so it is outside our control and stops the pull request from completing. |
|
Thanks for the careful read. Both points are now addressed at the current head. For the IPv6 case, the loopback list now holds the bracketed form '[::1]', which is what WHATWG URL.hostname actually returns for an IPv6 literal, so a server reached at http://[::1]:11434/v1 is matched. A positive test for that path is included in ollama.test.ts. This is in commit 28a9f23. For the factory ordering note, the Risk and Scope section now states plainly that a GLM model served by a local Ollama still routes to the Zai provider because that check runs first, that this is pre-existing routing we did not change, and that the other direction (Mistral-family models on Ollama) now routes to Ollama as intended. Could a maintainer take another look when there is time? Happy to adjust anything else. |
What this PR does
Adds a provider for Ollama in the OpenAI-compatible content generator. When Qwen Code talks to a local Ollama server through the
openaiauth type, this provider adds an emptyparametersobject to any tool that has no arguments, so the request is accepted. It mirrors what the MiniMax provider already does for the same class of failure. The change is scoped to Ollama only, detected from the base URL.Why it's needed
Ollama rejects a function tool that carries no
parametersfield at all. Every request that includes a zero-argument tool fails with:The converter sets
parameters = undefinedfor parameterless tools because llama.cpp, LM Studio and vLLM reject the empty-object shape. Ollama has the opposite requirement: it needs aparametersobject on every function tool. Without this provider, tools likeget_goalandlist_agentsbreak every turn against a local Ollama server.Reviewer Test Plan
How to verify
Run a local Ollama server and point Qwen Code at it with
auth-type: openaiandbaseUrl: http://localhost:11434/v1. Load a zero-argument tool such asget_goalorlist_agents. Before this change the request returns the 400 shown above; after it the request returns 200 and the turn completes. The unit tests cover both the detection and the injection:Evidence (Before & After)
Before, a parameterless tool sent with no
parametersfield:After, the same tool with
parameters: { "type": "object", "properties": {} }injected by the provider:Tested on
Environment (optional)
Local Ollama server on Windows, plus the unit tests run through vitest.
Risk & Scope
my-ollama.lanorollama.example.com, matches on any port, and any loopback host on port 11434 matches regardless of what is actually serving it. A llama.cpp or vLLM server listening on 11434 would receive the empty-object shape that those backends reject.glm-*model name on any hostname and runs before the Ollama check. That is pre-existing routing and is not changed here, so such a setup keeps the 400. The other direction works in this PR's favor: Mistral-family models on Ollama now route to Ollama, because the new check runs before Mistral's model-name fallback.Linked Issues
Fixes #12878
中文说明
本 PR 做了什么
在 OpenAI 兼容的内容生成器中新增一个面向 Ollama 的 provider。当 Qwen Code 通过
openai认证类型连接本地 Ollama 服务时,该 provider 会为任何无参数的工具补上一个空的parameters对象,从而让请求被接受。这与 MiniMax provider 针对同类失败所做的事情一致。改动只作用于 Ollama,通过 base URL 识别。为什么需要它
Ollama 会拒绝一个完全没有
parameters字段的 function 工具。任何包含零参数工具的请求都会失败,报错如下:转换器对无参工具会把
parameters设为undefined,因为 llama.cpp、LM Studio 和 vLLM 会拒绝空对象结构。Ollama 的要求恰好相反:它需要每个 function 工具都带一个parameters对象。没有这个 provider,像get_goal和list_agents这样的工具会在连接本地 Ollama 服务时让每一轮对话都失败。测试者验证计划
如何验证
启动一个本地 Ollama 服务,并用
auth-type: openai和baseUrl: http://localhost:11434/v1把 Qwen Code 指向它。加载一个零参数工具,例如get_goal或list_agents。在本改动之前,请求返回上面那个 400;改动之后,请求返回 200,对话正常完成。单元测试同时覆盖识别与注入两部分:证据(改动前后)
改动前,一个无参工具在没有
parameters字段的情况下发出:改动后,同一个工具由 provider 注入
parameters: { "type": "object", "properties": {} }:测试平台
环境(可选)
Windows 上的本地 Ollama 服务,以及通过 vitest 运行的单元测试。
风险与范围
my-ollama.lan或ollama.example.com,在任意端口都会命中;而 11434 端口上的任意回环地址无论背后实际是什么服务都会命中。因此一个监听在 11434 的 llama.cpp 或 vLLM 服务会收到那些后端会拒绝的空对象结构。glm-*模型名,且排在 Ollama 检查之前。这是既有的路由行为,本 PR 未作改动,所以这样的配置仍会遇到那个 400。另一个方向对本 PR 有利:跑在 Ollama 上的 Mistral 系模型现在会正确路由到 Ollama,因为新检查位于 Mistral 的模型名回退匹配之前。关联 Issue
Fixes #12878