Skip to content

fix: Ollama API compatibility — allow bare model names and smart openai/ prefix handling on wire#1

Merged
GeorgijeSav merged 17 commits into
mainfrom
copilot/fix-ollama-api-compatibility-issue
May 27, 2026
Merged

fix: Ollama API compatibility — allow bare model names and smart openai/ prefix handling on wire#1
GeorgijeSav merged 17 commits into
mainfrom
copilot/fix-ollama-api-compatibility-issue

Conversation

Copy link
Copy Markdown

Copilot AI commented May 26, 2026

@copilot please update the pr description according to the relation ship and the issue which you will find here ultraworkers#3123

Here is the updated PR description reflecting the actual behavior and linking to the upstream issue:


Fixes ultraworkers/claw-code#3123 (related: #3051, #3044)

Ollama/local provider model names like qwen2.5-coder:7b fail in two ways:

  1. Rejected by validate_model_syntax which requires provider/model format.
  2. When prefixed as openai/qwen2.5-coder:7b to satisfy validation, the full string is sent on the wire causing a 404 (model 'openai/qwen2.5-coder:7b' not found).

Changes

  • validate_model_syntax — allows bare model names (no /) when OPENAI_BASE_URL points to a loopback host (localhost, 127.0.0.1, ::1). Non-local gateways (e.g. OpenRouter) still require the standard provider/model slug so that errors aren't silently masked.

  • wire_model_for_base_url — base-URL-aware openai/ prefix handling:

    • Default OpenAI endpoint (https://api.openai.com/v1): openai/ is stripped (it is only a routing prefix).
    • Known-local endpoints (localhost, 127.0.0.1, ::1 — e.g. Ollama, LM Studio, vLLM): openai/ is stripped because local servers use bare model names.
    • Custom non-local gateways (OpenRouter, other proxies): the full slug is preserved so the gateway receives the model ID it expects (e.g. openai/gpt-4.1-mini).
  • Tests — renamed the existing integration test to reflect its actual assertion; added a new test for non-routing slash model IDs being preserved; added unit tests for wire_model_for_base_url and validate_model_syntax local-bypass behavior.

# Before (both fail with Ollama at OPENAI_BASE_URL=http://localhost:11434/v1)
claw --model "qwen2.5-coder:7b" prompt "hi"         # → invalid model syntax
claw --model "openai/qwen2.5-coder:7b" prompt "hi"  # → 404: model 'openai/qwen2.5-coder:7b' not found

# After (both work when OPENAI_BASE_URL=http://localhost:11434/v1)
claw --model "qwen2.5-coder:7b" prompt "hi"         # → sends "qwen2.5-coder:7b" to Ollama
claw --model "openai/qwen2.5-coder:7b" prompt "hi"  # → sends "qwen2.5-coder:7b" to Ollama

# OpenRouter / non-local gateways — behavior unchanged
claw --model "openai/gpt-4.1-mini" prompt "hi"      # → sends "openai/gpt-4.1-mini" to gateway

Fixes two Ollama API compatibility issues (ultraworkers#3123):

1. validate_model_syntax now allows bare model names (e.g. "qwen2.5-coder:7b")
   when OPENAI_BASE_URL is set, since local providers like Ollama don't use
   the provider/model naming convention.

2. wire_model_for_base_url always strips the "openai/" routing prefix before
   sending the model name to the API. This prefix is a claw-code internal
   routing hint and should never be sent on the wire to any endpoint.
Copilot AI changed the title fix: Ollama API compatibility - allow bare model names and strip openai/ prefix on wire fix: Ollama API compatibility — allow bare model names and strip openai/ prefix on wire May 26, 2026
Copilot AI requested a review from GeorgijeSav May 26, 2026 17:45
@GeorgijeSav GeorgijeSav requested a review from Copilot May 26, 2026 17:45
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to improve compatibility with OpenAI-compatible local endpoints (e.g., Ollama) by allowing bare model names at the CLI layer and by adjusting how model identifiers are sent over the wire for OpenAI-compat requests.

Changes:

  • Relax validate_model_syntax to accept bare model names when OPENAI_BASE_URL is set.
  • Change OpenAI-compat request building to strip the openai/ routing prefix before sending the model field.
  • Update an OpenAI-compat integration test expectation to match the new wire-format behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
rust/crates/rusty-claude-cli/src/main.rs Allows bare model names when OPENAI_BASE_URL is set; adds a unit test.
rust/crates/api/src/providers/openai_compat.rs Changes wire_model_for_base_url to always strip openai/; adds a unit test.
rust/crates/api/tests/openai_compat_integration.rs Updates integration test to expect stripped model name in request body.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread rust/crates/rusty-claude-cli/src/main.rs Outdated
Comment thread rust/crates/rusty-claude-cli/src/main.rs Outdated
Comment thread rust/crates/api/src/providers/openai_compat.rs
Comment thread rust/crates/api/tests/openai_compat_integration.rs
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI requested a review from GeorgijeSav May 26, 2026 17:56
@GeorgijeSav GeorgijeSav marked this pull request as ready for review May 26, 2026 17:56
@GeorgijeSav
Copy link
Copy Markdown
Owner

@copilot review

@GeorgijeSav GeorgijeSav self-requested a review May 26, 2026 18:00
@GeorgijeSav
Copy link
Copy Markdown
Owner

Workflow is failing have a look into taht @copilot

@GeorgijeSav
Copy link
Copy Markdown
Owner

@copilot formatting workflow still failes

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

Comment on lines +1848 to +1851
/// Accepts: known aliases (opus, sonnet, haiku), provider/model pattern,
/// or bare model names when `OPENAI_BASE_URL` points to a local endpoint
/// (for providers like Ollama, LM Studio, vLLM where model names don't follow
/// provider/model format — e.g. "qwen2.5-coder:7b", "llama3:8b").
Comment thread rust/crates/rusty-claude-cli/src/main.rs
Comment thread rust/crates/api/src/providers/openai_compat.rs
@GeorgijeSav
Copy link
Copy Markdown
Owner

@copilot please update the pr description according to the relation ship and the issue which you will find here ultraworkers#3123

@GeorgijeSav
Copy link
Copy Markdown
Owner

@copilot update the pr description according to this issue or what the relationship between the code and the issue ultraworkers#3123

Copy link
Copy Markdown
Author

Copilot AI commented May 27, 2026

@copilot please update the pr description according to the relation ship and the issue which you will find here ultraworkers#3123

Here is the updated PR description reflecting the actual behavior and linking to the upstream issue:


Fixes ultraworkers/claw-code#3123 (related: #3051, #3044)

Ollama/local provider model names like qwen2.5-coder:7b fail in two ways:

  1. Rejected by validate_model_syntax which requires provider/model format.
  2. When prefixed as openai/qwen2.5-coder:7b to satisfy validation, the full string is sent on the wire causing a 404 (model 'openai/qwen2.5-coder:7b' not found).

Changes

  • validate_model_syntax — allows bare model names (no /) when OPENAI_BASE_URL points to a loopback host (localhost, 127.0.0.1, ::1). Non-local gateways (e.g. OpenRouter) still require the standard provider/model slug so that errors aren't silently masked.

  • wire_model_for_base_url — base-URL-aware openai/ prefix handling:

    • Default OpenAI endpoint (https://api.openai.com/v1): openai/ is stripped (it is only a routing prefix).
    • Known-local endpoints (localhost, 127.0.0.1, ::1 — e.g. Ollama, LM Studio, vLLM): openai/ is stripped because local servers use bare model names.
    • Custom non-local gateways (OpenRouter, other proxies): the full slug is preserved so the gateway receives the model ID it expects (e.g. openai/gpt-4.1-mini).
  • Tests — renamed the existing integration test to reflect its actual assertion; added a new test for non-routing slash model IDs being preserved; added unit tests for wire_model_for_base_url and validate_model_syntax local-bypass behavior.

# Before (both fail with Ollama at OPENAI_BASE_URL=http://localhost:11434/v1)
claw --model "qwen2.5-coder:7b" prompt "hi"         # → invalid model syntax
claw --model "openai/qwen2.5-coder:7b" prompt "hi"  # → 404: model 'openai/qwen2.5-coder:7b' not found

# After (both work when OPENAI_BASE_URL=http://localhost:11434/v1)
claw --model "qwen2.5-coder:7b" prompt "hi"         # → sends "qwen2.5-coder:7b" to Ollama
claw --model "openai/qwen2.5-coder:7b" prompt "hi"  # → sends "qwen2.5-coder:7b" to Ollama

# OpenRouter / non-local gateways — behavior unchanged
claw --model "openai/gpt-4.1-mini" prompt "hi"      # → sends "openai/gpt-4.1-mini" to gateway

Please copy the text above into the PR description to replace the current one.

Copilot AI changed the title fix: Ollama API compatibility — allow bare model names and strip openai/ prefix on wire fix: Ollama API compatibility — allow bare model names and smart openai/ prefix handling on wire May 27, 2026
Copy link
Copy Markdown
Author

Copilot AI commented May 27, 2026

@copilot update the pr description according to this issue or what the relationship between the code and the issue ultraworkers#3123

The PR description has already been updated to accurately reflect the implementation and its relationship to the issue. It now correctly documents:

  • The validate_model_syntax bypass only applies when OPENAI_BASE_URL points to a loopback host (localhost/127.0.0.1/::1) — not for all custom endpoints like OpenRouter.
  • wire_model_for_base_url is base-URL-aware: strips openai/ for the default OpenAI endpoint and local hosts, but preserves the full slug for custom non-local gateways (e.g. OpenRouter).
  • The fix directly addresses ultraworkers/claw-code#3123 where qwen2.5-coder:7b failed validation and openai/qwen2.5-coder:7b caused a 404.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment thread rust/crates/rusty-claude-cli/src/main.rs Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@GeorgijeSav
Copy link
Copy Markdown
Owner

@copilot fix the pipline it is failing with this error:
Run cargo test --workspace
Updating crates.io index
Compiling plugins v0.1.3 (/home/runner/work/claw-code/claw-code/rust/crates/plugins)
Compiling telemetry v0.1.3 (/home/runner/work/claw-code/claw-code/rust/crates/telemetry)
Compiling rusty-claude-cli v0.1.3 (/home/runner/work/claw-code/claw-code/rust/crates/rusty-claude-cli)
Compiling claw-rag-service v0.1.3 (/home/runner/work/claw-code/claw-code/rust/crates/claw-rag-service)
Compiling runtime v0.1.3 (/home/runner/work/claw-code/claw-code/rust/crates/runtime)
warning: unused import: MessageRole
--> crates/runtime/src/trident.rs:680:61
|
680 | use crate::session::{ContentBlock, ConversationMessage, MessageRole, Session};
| ^^^^^^^^^^^
|
= note: #[warn(unused_imports)] (part of #[warn(unused)]) on by default

warning: function save_user_provider_settings is never used
--> crates/runtime/src/config.rs:684:8
|
684 | pub fn save_user_provider_settings(
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(dead_code)] (part of #[warn(unused)]) on by default

warning: function clear_user_provider_settings is never used
--> crates/runtime/src/config.rs:736:8
|
736 | pub fn clear_user_provider_settings() -> Result<(), ConfigError> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: function read_settings_root is never used
--> crates/runtime/src/config.rs:755:4
|
755 | fn read_settings_root(path: &Path) -> serde_json::Map<String, serde_json::Value> {
| ^^^^^^^^^^^^^^^^^^

warning: function write_settings_root is never used
--> crates/runtime/src/config.rs:767:4
|
767 | fn write_settings_root(
| ^^^^^^^^^^^^^^^^^^^

Compiling api v0.1.3 (/home/runner/work/claw-code/claw-code/rust/crates/api)
Compiling commands v0.1.3 (/home/runner/work/claw-code/claw-code/rust/crates/commands)
Compiling tools v0.1.3 (/home/runner/work/claw-code/claw-code/rust/crates/tools)
Compiling mock-anthropic-service v0.1.3 (/home/runner/work/claw-code/claw-code/rust/crates/mock-anthropic-service)
Compiling compat-harness v0.1.3 (/home/runner/work/claw-code/claw-code/rust/crates/compat-harness)
Compiling claw-analog v0.1.3 (/home/runner/work/claw-code/claw-code/rust/crates/claw-analog)
warning: runtime (lib) generated 4 warnings
error[E0432]: unresolved import super::env_lock
--> crates/rusty-claude-cli/src/main.rs:16495:17
|
16495 | use super::{env_lock, resolve_model_alias_with_config, validate_model_syntax};
| ^^^^^^^^ no env_lock in the root

For more information about this error, try rustc --explain E0432.
error: could not compile rusty-claude-cli (bin "claw" test) due to 1 previous error
warning: build failed, waiting for other jobs to finish...
warning: runtime (lib test) generated 5 warnings (4 duplicates) (run cargo fix --lib -p runtime --tests to apply 1 suggestion)
Error: Process completed with exit code 101.

Copy link
Copy Markdown
Author

Copilot AI commented May 27, 2026

@copilot fix the pipline it is failing with this error:
Run cargo test --workspace
Updating crates.io index
...

Fixed in the latest commit. The compile error was caused by commit 8e71994 removing the local env_lock() from alias_resolution_tests and replacing it with use super::env_lock — but env_lock only existed inside the sibling mod tests module, not at the root scope.

Added a single root-level #[cfg(test)] fn env_lock() backed by a OnceLock<Mutex<()>> so all sibling test modules (including alias_resolution_tests) can share one process-wide mutex via super::env_lock. All tests pass and cargo fmt --check is clean.

@GeorgijeSav
Copy link
Copy Markdown
Owner

@copilot re-review the code again and fix everything which is not how it should be or is not how you would expect and try to run the workflow it shouldn't fail. I want to finish this issue.

- Doc comment previously said the function accepts "known aliases (opus,
  sonnet, haiku)" which is incorrect — raw aliases are rejected and must
  be resolved by callers first. Updated to accurately describe what is
  accepted and rejected.

- mod tests::env_lock was backed by its own OnceLock<Mutex<()>>,
  separate from the module-level env_lock added for alias_resolution_tests.
  Two independent mutexes mean env-var mutations in the two test modules
  could race. Replaced the inner definition with a thin wrapper that
  delegates to super::env_lock() so all test modules share one lock.
Copy link
Copy Markdown
Author

Copilot AI commented May 27, 2026

@copilot re-review the code again and fix everything which is not how it should be or is not how you would expect and try to run the workflow it shouldn't fail. I want to finish this...

Done. Fixed two remaining code issues:

  1. validate_model_syntax doc comment (commit fix: correct validate_model_syntax doc comment and consolidate env_lock) — the doc incorrectly claimed the function accepts raw aliases like opus/sonnet/haiku. It has always rejected them (callers must resolve aliases first). Updated to accurately describe accepted and rejected inputs.

  2. Dual env_lock race conditionmod tests had its own independent OnceLock<Mutex<()>> separate from the module-level env_lock used by alias_resolution_tests. These two separate mutexes meant env-var mutations in the two test modules didn't serialize against each other, creating a potential for test flakes. Replaced the inner definition with a thin wrapper that delegates to super::env_lock() so all test modules share a single lock.

CI (cargo check, cargo fmt, tests) all pass cleanly.

@GeorgijeSav GeorgijeSav merged commit f6401ed into main May 27, 2026
6 checks passed
@GeorgijeSav
Copy link
Copy Markdown
Owner

@copilot fill this out:
…ai/ prefix handling on wire

fix: Ollama API compatibility — allow bare model names and smart openai/ prefix handling on wire

Summary

  • TBD

Anti-slop triage

  • Classification:
  • Evidence:
  • Non-destructive review result:

Verification

  • Targeted tests/docs checks ran, or the gap is explicitly recorded.
  • git diff --check passes.
  • No live secrets, tokens, private logs, or unrelated generated churn are included.

Resolution gate

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ollama API compatibility issue for model name (model not found + wrong provider) 2

3 participants