Skip to content

fix(api): restore model_id field in /workers response - #774

Merged
slin1237 merged 2 commits into
mainfrom
slin/fix-worker-model-id
Mar 16, 2026
Merged

slin1237 merged 2 commits into
mainfrom
slin/fix-worker-model-id

Conversation

@slin1237

@slin1237 slin1237 commented Mar 16, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Restores the model_id field in /workers API response for backwards compatibility
  • The WorkerModels refactor removed the flat model_id from worker responses, breaking clients that parsed it for model registration

Closes #773

What changed

  • crates/protocols/src/worker.rs: Added model_id: Option<String> to WorkerInfo, computed from models.primary().id via with_model_id(). The field is serialization-only (skip_deserializing) and omitted for wildcard workers.
  • model_gateway/src/core/worker.rs: worker_to_info() now calls .with_model_id() to populate the field.
  • e2e_test/router/test_worker_api.py: test_list_workers now asserts worker.model is present.

Response format (before → after)

Before:

{"id": "...", "url": "http://...", "models": [{"id": "my-model"}], ...}

After:

{"id": "...", "url": "http://...", "model_id": "my-model", "models": [{"id": "my-model"}], ...}

Test plan

  • cargo test -p openai-protocol -p smg -- worker passes
  • E2E test_list_workers asserts model_id is present in response
  • Wildcard workers (no models) omit model_id from response (null/absent)

Summary by CodeRabbit

  • New Features
    • Workers now expose an optional primary model identifier for improved model tracking and backwards compatibility.
  • Bug Fixes / Validation
    • Runtime validation enforces that any present model identifier is non-empty.
  • Tests
    • Worker listing output and tests updated to include and verify the model identifier in displayed results.

What changed:
- crates/protocols/src/worker.rs: add model_id field to WorkerInfo,
  computed from the primary model in the models array via with_model_id().
  Field is serialization-only (skip_deserializing) and omitted when null
  (wildcard workers).
- model_gateway/src/core/worker.rs: call with_model_id() in
  worker_to_info() so all /workers responses include model_id.
- e2e_test/router/test_worker_api.py: assert worker.model is present
  in test_list_workers.

Why: the WorkerModels refactor removed the flat model_id field from
worker API responses, breaking clients that depend on it for model
registration. This restores backwards compatibility while keeping the
full models array.

Closes #773

Signed-off-by: Simo Lin <linsimo.mark@gmail.com>
@github-actions github-actions Bot added tests Test changes model-gateway Model gateway crate changes labels Mar 16, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request reintroduces the model_id field into the /workers API response. This change is crucial for backward compatibility, as the field was unintentionally removed during a recent refactor, causing issues for clients that relied on it for model registration. The model_id is now derived from the primary model and is conditionally serialized, ensuring that existing integrations continue to function as expected.

Highlights

  • Backward Compatibility Restoration: The model_id field has been restored in the /workers API response to ensure backward compatibility for clients that relied on it.
  • Addressing Breaking Change: This change addresses a breaking issue where a previous WorkerModels refactor inadvertently removed the model_id from worker responses, impacting client functionality.
  • WorkerInfo Struct Update: A new model_id: Option<String> field was added to the WorkerInfo struct in crates/protocols/src/worker.rs, configured for serialization only and omitted for wildcard workers.
  • Model ID Population Logic: A with_model_id() method was implemented to derive and populate the model_id from the primary model's ID within the WorkerInfo struct.
  • API Response Generation Update: The worker_to_info() function in model_gateway/src/core/worker.rs was updated to utilize the new with_model_id() method, ensuring proper model_id population in API responses.
  • End-to-End Test Enhancement: End-to-end tests were enhanced in e2e_test/router/test_worker_api.py to verify the presence of the model_id in the /workers API response.
Changelog
  • crates/protocols/src/worker.rs
    • Added model_id: Option<String> to WorkerInfo struct, marked with #[serde(default, skip_deserializing, skip_serializing_if = "Option::is_none")].
    • Implemented with_model_id() method to populate model_id from spec.models.primary().map(|m| m.id.clone()).
    • Initialized model_id to None in WorkerInfo::pending.
  • e2e_test/router/test_worker_api.py
    • Updated test_list_workers to include worker.model in the logger info.
    • Added an assertion assert worker.model, "Worker should have a model_id" to verify its presence.
  • model_gateway/src/core/worker.rs
    • Modified worker_to_info() to call .with_model_id() on the constructed WorkerInfo to ensure the model_id is populated.
    • Initialized model_id to None in the WorkerInfo struct creation within worker_to_info().
Activity
  • No specific activity (comments, reviews, etc.) has been recorded for this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@coderabbitai

coderabbitai Bot commented Mar 16, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds an optional model_id: Option<String> to WorkerInfo, initializes it to None for pending workers, and populates it from a worker's primary model during worker→info conversion; tests updated to include and validate the model field in worker listings.

Changes

Cohort / File(s) Summary
Protocols: WorkerInfo
crates/protocols/src/worker.rs
Add public model_id: Option<String> to WorkerInfo with serde default/skip, and set model_id: None in WorkerInfo::pending(...).
Gateway: worker conversion
model_gateway/src/core/worker.rs
worker_to_info now sets WorkerInfo.model_id from `spec.models.primary().map(
Tests: worker listing
e2e_test/router/test_worker_api.py
Update logging/format to include worker.model; add runtime validation that non-None model values are non-empty in test_list_workers.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

protocols, python-bindings

Suggested reviewers

  • CatherineSue
  • key4ng

Poem

🐰 I sniffed a model_id so neat,

tucked in WorkerInfo, small and sweet.
From spec it hopped to gateway's door,
now listings cheer and ask for more.
🥕 Hop on, code — we’ve got one feat!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR addresses issue #773 about --enable-mesh flag not working in Docker, but the actual code changes restore the model_id field in the /workers API response, which is unrelated to the mesh configuration issue. Clarify the relationship between the model_id restoration and the --enable-mesh bug fix, or address the actual mesh configuration argument parsing issue in the Python entrypoint.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(api): restore model_id field in /workers response' accurately describes the main change: restoring the model_id field to the /workers API response for backwards compatibility.
Out of Scope Changes check ✅ Passed All code changes are narrowly scoped to restoring the model_id field in WorkerInfo and its serialization, directly supporting the PR's stated objective.
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 slin/fix-worker-model-id
📝 Coding Plan
  • Generate coding plan for human review comments

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

@ekzhang ekzhang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you so much 👍

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request restores the model_id field to the /workers API response for backward compatibility, which was unintentionally removed during a refactor. The changes correctly add the field to the WorkerInfo struct and populate it from the primary model. The e2e tests are also updated to verify the presence of this field. My review includes a suggestion to simplify the instantiation of WorkerInfo to make the code more direct and efficient, aligning with best practices for handling optional fields.

Comment thread model_gateway/src/core/worker.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 61e95918c5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread crates/protocols/src/worker.rs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 `@e2e_test/router/test_worker_api.py`:
- Around line 45-55: The test currently asserts every worker has a model via the
unconditional assert on worker.model, which conflicts with the API contract that
model_id is optional for wildcard workers; update the loop that iterates over
workers to only assert presence of model when appropriate (e.g., skip or allow
missing model_id for wildcard workers) by checking the worker's nature before
asserting model (refer to the loop variable worker and its attributes model /
model_id), or replace the unconditional assert with a conditional assertion that
permits None for wildcard entries. Ensure you keep the existing assert for
worker.url unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0abc0c71-7a56-4aa0-9066-35b9c61f9685

📥 Commits

Reviewing files that changed from the base of the PR and between eae871e and 61e9591.

📒 Files selected for processing (3)
  • crates/protocols/src/worker.rs
  • e2e_test/router/test_worker_api.py
  • model_gateway/src/core/worker.rs

Comment thread e2e_test/router/test_worker_api.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@crates/protocols/src/worker.rs`:
- Around line 579-581: The doc comment for the field model_id is inaccurate: it
states that None is serialized as `null` but the field has #[serde(default,
skip_serializing_if = "Option::is_none")] so None is omitted from JSON. Update
the comment on the model_id field (the pub model_id: Option<String> declaration)
to state that when None the field is omitted from serialization (not serialized
as null), and clarify that the value is computed from models[0].id
(single/multi) or omitted for wildcard.

In `@model_gateway/src/core/worker.rs`:
- Around line 936-939: The WorkerInfo construction in worker_to_info currently
derives model_id from spec.models.primary(), which ignores models_override and
can be stale for workers updated via set_models(); update worker_to_info to
compute model_id from the runtime-visible models instead (e.g., prefer
spec.models_override or the worker's current models view such as
worker.models().primary()) so that WorkerInfo.id uses the live primary model id
rather than the static spec.models.primary() value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6acfdf7a-10db-4848-a164-5d52d1e5ab7d

📥 Commits

Reviewing files that changed from the base of the PR and between 61e9591 and 722d83c.

📒 Files selected for processing (3)
  • crates/protocols/src/worker.rs
  • e2e_test/router/test_worker_api.py
  • model_gateway/src/core/worker.rs

Comment thread crates/protocols/src/worker.rs
Comment thread model_gateway/src/core/worker.rs
What changed:
- crates/protocols/src/worker.rs: remove skip_deserializing so Rust
  consumers can also read model_id from JSON responses. Remove
  with_model_id() helper since model_id is now computed inline.
- model_gateway/src/core/worker.rs: compute model_id directly from
  spec.models.primary() in worker_to_info() instead of using
  with_model_id() builder.
- e2e_test/router/test_worker_api.py: make model_id assertion
  conditional — wildcard workers may have model_id as None.

Signed-off-by: Simo Lin <linsimo.mark@gmail.com>
@slin1237
slin1237 force-pushed the slin/fix-worker-model-id branch from 722d83c to 51dd8b4 Compare March 16, 2026 20:02

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (2)
model_gateway/src/core/worker.rs (1)

938-938: ⚠️ Potential issue | 🟠 Major

Use runtime-discovered models when deriving model_id.

At Line 938, deriving from spec.models.primary() can return stale model_id after lazy discovery (set_models updates models_override, not spec.models). This breaks the compatibility field for discovered workers.

🔧 Proposed fix
 pub fn worker_to_info(worker: &Arc<dyn Worker>) -> WorkerInfo {
     let metadata = worker.metadata();
     let spec = metadata.spec.clone();
+    let model_id = worker.models().into_iter().next().map(|m| m.id);

     WorkerInfo {
         id: worker.url().to_string(),
-        model_id: spec.models.primary().map(|m| m.id.clone()),
+        model_id,
         spec,
         is_healthy: worker.is_healthy(),
         load: worker.load(),
         job_status: None,
     }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@model_gateway/src/core/worker.rs` at line 938, The assignment deriving
model_id from spec.models.primary() can return stale values after lazy
discovery; change the logic in worker.rs (where model_id:
spec.models.primary().map(|m| m.id.clone()) is set) to prefer the
runtime-discovered models_override (e.g. models_override.primary().map(|m|
m.id.clone())) and fall back to spec.models.primary() only if models_override is
empty, so the compatibility field uses the discovered model IDs updated by
set_models.
crates/protocols/src/worker.rs (1)

578-581: ⚠️ Potential issue | 🟡 Minor

Fix model_id serialization contract and doc wording.

At Line 579, None is omitted (not null) because of skip_serializing_if. Also consider making this field serialization-only to match the intended derived-response behavior.

✏️ Proposed fix
-    /// Primary model ID for backwards compatibility.
-    /// Computed from `models[0].id` (single/multi) or `null` (wildcard).
-    #[serde(default, skip_serializing_if = "Option::is_none")]
+    /// Primary model ID for backwards compatibility.
+    /// Computed from `models[0].id` (single/multi) or omitted when wildcard.
+    #[serde(default, skip_deserializing, skip_serializing_if = "Option::is_none")]
     pub model_id: Option<String>,
#!/bin/bash
# Verify current serde contract and find WorkerInfo deserialization call sites.
rg -n -C2 'pub struct WorkerInfo|model_id: Option<String>|skip_deserializing|skip_serializing_if = "Option::is_none"' crates/protocols/src/worker.rs
rg -nP --type=rust -C2 'serde_json::from_(str|slice|value)\s*::\s*<\s*WorkerInfo\s*>' 
rg -nP --type=rust -C2 '\bWorkerInfo\b.*Deserialize|Deserialize.*\bWorkerInfo\b'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/protocols/src/worker.rs` around lines 578 - 581, The doc and serde
attributes for WorkerInfo::model_id are inconsistent: None is currently omitted
(not serialized as null) due to skip_serializing_if, and you want this field to
be serialization-only. Update the field's serde attributes to add
skip_deserializing and keep default + skip_serializing_if (e.g.
#[serde(skip_deserializing, default, skip_serializing_if = "Option::is_none")])
so model_id is emitted when present but ignored on input, and revise the doc
comment on model_id to state that it is derived for responses and omitted when
None (not serialized as null).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@crates/protocols/src/worker.rs`:
- Around line 578-581: The doc and serde attributes for WorkerInfo::model_id are
inconsistent: None is currently omitted (not serialized as null) due to
skip_serializing_if, and you want this field to be serialization-only. Update
the field's serde attributes to add skip_deserializing and keep default +
skip_serializing_if (e.g. #[serde(skip_deserializing, default,
skip_serializing_if = "Option::is_none")]) so model_id is emitted when present
but ignored on input, and revise the doc comment on model_id to state that it is
derived for responses and omitted when None (not serialized as null).

In `@model_gateway/src/core/worker.rs`:
- Line 938: The assignment deriving model_id from spec.models.primary() can
return stale values after lazy discovery; change the logic in worker.rs (where
model_id: spec.models.primary().map(|m| m.id.clone()) is set) to prefer the
runtime-discovered models_override (e.g. models_override.primary().map(|m|
m.id.clone())) and fall back to spec.models.primary() only if models_override is
empty, so the compatibility field uses the discovered model IDs updated by
set_models.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6da38676-9237-4c80-8597-8bd10d47c5d0

📥 Commits

Reviewing files that changed from the base of the PR and between 722d83c and 51dd8b4.

📒 Files selected for processing (3)
  • crates/protocols/src/worker.rs
  • e2e_test/router/test_worker_api.py
  • model_gateway/src/core/worker.rs

@slin1237
slin1237 merged commit 8a5afab into main Mar 16, 2026
57 of 60 checks passed
@slin1237
slin1237 deleted the slin/fix-worker-model-id branch March 16, 2026 21:05
smfirmin pushed a commit to smfirmin/smg that referenced this pull request Mar 20, 2026
Signed-off-by: Simo Lin <linsimo.mark@gmail.com>
smfirmin pushed a commit to smfirmin/smg that referenced this pull request Mar 20, 2026
Signed-off-by: Simo Lin <linsimo.mark@gmail.com>
@coderabbitai coderabbitai Bot mentioned this pull request Jun 11, 2026
2 tasks done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

model-gateway Model gateway crate changes tests Test changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: --enable-mesh does not work in smg docker image

2 participants