Skip to content

Fix Z.AI Coding Plan model routing#210

Merged
jamiepine merged 3 commits intomainfrom
fix/zai-coding-plan-model-routing
Feb 25, 2026
Merged

Fix Z.AI Coding Plan model routing#210
jamiepine merged 3 commits intomainfrom
fix/zai-coding-plan-model-routing

Conversation

@jamiepine
Copy link
Member

@jamiepine jamiepine commented Feb 25, 2026

Summary

Fixes model routing for Z.AI Coding Plan provider. The API expects model names with the zai/ prefix (e.g., zai/glm-5) rather than bare model names (e.g., glm-5).

Changes

  • Added remap_model_name_for_api() helper method to SpacebotModel
  • Applied remapping in all three OpenAI-compatible API call methods:
    • call_openai()
    • call_openai_responses()
    • call_openai_compatible_with_optional_auth()

Fix

When users select zai-coding-plan/glm-5, the system now correctly sends {\"model\": \"zai/glm-5\"} to the API instead of {\"model\": \"glm-5\"}.

Affects all Z.AI Coding Plan models:

  • zai-coding-plan/glm-5 → API receives zai/glm-5
  • zai-coding-plan/glm-4.7 → API receives zai/glm-4.7
  • zai-coding-plan/glm-4.5-air → API receives zai/glm-4.5-air

Note

Implementation verified against actual changes. The fix introduces a single private helper method remap_model_name_for_api() that applies the provider-specific prefix transformation consistently across all three OpenAI-compatible API call paths in src/llm/model.rs.

Written by Tembo for commit 3eed019.

The Z.AI Coding Plan API expects model names with the 'zai/' prefix
(e.g., 'zai/glm-5') rather than bare model names (e.g., 'glm-5').

Added remap_model_name_for_api() helper to handle provider-specific
model name formatting. Applied to all OpenAI-compatible API call methods.
@coderabbitai
Copy link

coderabbitai bot commented Feb 25, 2026

Walkthrough

Added SpacebotModel::remap_model_name_for_api(&self) -> String to map internal model names to API-specific formats (notably for the "zai-coding-plan" provider). Multiple OpenAI-compatible request builders now use the remapped model name instead of self.model_name when constructing request bodies.

Changes

Cohort / File(s) Summary
Model Name Remapping
src/llm/model.rs
Added remap_model_name_for_api() to return an API-specific model name (e.g., prefix with zai/ for zai-coding-plan). Replaced direct uses of self.model_name with a local api_model_name (result of the new method) in call_openai, call_openai_with_optional_auth, call_openai_responses, and related OpenAI-compatible request builders.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix Z.AI Coding Plan model routing' directly and clearly summarizes the main change: fixing model name routing for the Z.AI Coding Plan provider by adding a remapping helper.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, clearly explaining the fix, the changes made, and the specific API model name transformation being implemented.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/zai-coding-plan-model-routing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jamiepine jamiepine marked this pull request as ready for review February 25, 2026 05:46
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/llm/model.rs`:
- Around line 824-832: The remap_model_name_for_api method currently
unconditionally prefixes "zai/" when provider == "zai-coding-plan", which
double-prefixes if model_name already starts with "zai/"; update
remap_model_name_for_api to be idempotent by returning model_name.clone() if it
already starts_with("zai/") and only prefixing otherwise (keep the provider
check on self.provider == "zai-coding-plan" and use self.model_name to decide
whether to add "zai/"). Ensure the function still returns
self.model_name.clone() for non-zai providers.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ee8b6dd and d7144a9.

📒 Files selected for processing (1)
  • src/llm/model.rs

Co-authored-by: tembo[bot] <208362400+tembo[bot]@users.noreply.github.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
src/llm/model.rs (2)

757-760: call_openai_compatible still uses bare self.model_name — inconsistent with the other three paths.

call_openai_compatible is the only OpenAI-compatible call path that bypasses remap_model_name_for_api(). Currently this method only handles Gemini, which doesn't need remapping, so there's no active bug. However, if any future provider is routed through this path and requires name translation, the remapping will silently be skipped.

♻️ Suggested fix
-        let mut body = serde_json::json!({
-            "model": self.model_name,
-            "messages": messages,
-        });
+        let api_model_name = self.remap_model_name_for_api();
+        let mut body = serde_json::json!({
+            "model": api_model_name,
+            "messages": messages,
+        });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/llm/model.rs` around lines 757 - 760, The JSON body construction in
call_openai_compatible uses the raw self.model_name (the snippet building let
mut body = serde_json::json!({ "model": self.model_name, "messages": messages,
});) and thus bypasses remap_model_name_for_api; update call_openai_compatible
to call self.remap_model_name_for_api() (or the equivalent method used
elsewhere) and use that returned string/value for the "model" field so model
name translation is applied consistently across all OpenAI-compatible paths.

1526-1566: Consider adding a unit test for remap_model_name_for_api.

The test module already covers reverse_map_tool_names. Given that remap_model_name_for_api is the core logic of this PR — and the idempotency edge case is worth locking in — a targeted test would be a cheap safety net.

#[test]
fn remap_model_name_for_api_adds_zai_prefix() {
    // bare model name gets prefixed
    // ...
}

#[test]
fn remap_model_name_for_api_is_idempotent() {
    // already-prefixed model name is not double-prefixed
    // ...
}

#[test]
fn remap_model_name_for_api_noop_for_other_providers() {
    // non-zai provider returns model_name unchanged
    // ...
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/llm/model.rs` around lines 1526 - 1566, Add unit tests for
remap_model_name_for_api in the existing tests module: create three tests that
call remap_model_name_for_api directly and assert behavior — (1)
remap_model_name_for_api_adds_zai_prefix: when provider == "zai" and model_name
is "gpt-4o-mini" it returns "zai-gpt-4o-mini", (2)
remap_model_name_for_api_is_idempotent: when provider == "zai" and model_name
already starts with "zai-" it returns the same string unchanged, and (3)
remap_model_name_for_api_noop_for_other_providers: when provider != "zai" it
returns the original model_name; place them in the same mod tests block
alongside reverse_map_restores_original_tool_names and use assert_eq! comparing
remap_model_name_for_api(provider, model_name) to the expected string.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/llm/model.rs`:
- Around line 757-760: The JSON body construction in call_openai_compatible uses
the raw self.model_name (the snippet building let mut body = serde_json::json!({
"model": self.model_name, "messages": messages, });) and thus bypasses
remap_model_name_for_api; update call_openai_compatible to call
self.remap_model_name_for_api() (or the equivalent method used elsewhere) and
use that returned string/value for the "model" field so model name translation
is applied consistently across all OpenAI-compatible paths.
- Around line 1526-1566: Add unit tests for remap_model_name_for_api in the
existing tests module: create three tests that call remap_model_name_for_api
directly and assert behavior — (1) remap_model_name_for_api_adds_zai_prefix:
when provider == "zai" and model_name is "gpt-4o-mini" it returns
"zai-gpt-4o-mini", (2) remap_model_name_for_api_is_idempotent: when provider ==
"zai" and model_name already starts with "zai-" it returns the same string
unchanged, and (3) remap_model_name_for_api_noop_for_other_providers: when
provider != "zai" it returns the original model_name; place them in the same mod
tests block alongside reverse_map_restores_original_tool_names and use
assert_eq! comparing remap_model_name_for_api(provider, model_name) to the
expected string.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d7144a9 and a15577c.

📒 Files selected for processing (1)
  • src/llm/model.rs

@jamiepine jamiepine merged commit e05ea0e into main Feb 25, 2026
3 of 4 checks passed
@mmmeff
Copy link

mmmeff commented Feb 25, 2026

This seems to have broken all GLM Coding Plan model routing for me

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.

2 participants