From b6b7d74f144dcf865ad123886955a0d327b638b7 Mon Sep 17 00:00:00 2001 From: Pranjal Parmar <76609992+pranjalparmar@users.noreply.github.com> Date: Fri, 28 Aug 2026 10:13:11 +0200 Subject: [PATCH 1/2] feat: Add first-class Z AI Coding Plan provider Resolves #546 by adding the Z AI Coding Plan provider (zai-coding). Implements dynamic configuration by updating the _compat factory to support model_choices, allowing users to select their preferred Coding Plan model (e.g., GLM-5.2 or GLM-4 Coder) directly from the settings menu. --- coworker/providers/matrix.py | 3 ++ coworker/providers/registry.py | 61 +++++++++++++++++++++++++--------- coworker/server/manager.py | 2 +- 3 files changed, 49 insertions(+), 17 deletions(-) diff --git a/coworker/providers/matrix.py b/coworker/providers/matrix.py index 052a19ff0..ea876d12c 100644 --- a/coworker/providers/matrix.py +++ b/coworker/providers/matrix.py @@ -161,6 +161,9 @@ class ModelEntry: ), ), "zai:glm-5.2": ModelEntry("GLM-5.2 · Z AI", _AGENTIC, 128_000), + "zai-coding:glm-5.2": ModelEntry("GLM-5.2 · Z AI Coding Plan", _AGENTIC, 128_000), + "zai-coding:glm-4.7": ModelEntry("GLM-4.7 · Z AI Coding Plan", _AGENTIC, 128_000), + "zai-coding:glm-4-coder": ModelEntry("GLM-4 Coder · Z AI Coding Plan", _AGENTIC, 128_000), "deepseek:deepseek-v4-flash": ModelEntry( "DeepSeek V4 Flash · DeepSeek", _AGENTIC, 128_000 ), diff --git a/coworker/providers/registry.py b/coworker/providers/registry.py index 397efee10..f4a7f6543 100644 --- a/coworker/providers/registry.py +++ b/coworker/providers/registry.py @@ -262,29 +262,45 @@ def _compat( recommended_model: str, env_key: str, endpoint_help: str = "", + model_choices: tuple = (), ) -> ProviderDescriptor: """Descriptor for an OpenAI-compatible vendor: key + a prefilled, editable endpoint.""" vendor = title.split(" (")[0] + + fields = [ + ProviderField( + "api_key", + f"{vendor} API key", + secret=True, + ), + ProviderField( + "base_url", + "Endpoint", + required=False, + default=base_url, + placeholder=base_url, + help=endpoint_help + or f"Prefilled with {vendor}'s official endpoint; edit only for a regional or proxy variant.", + ), + ] + + if model_choices: + fields.append( + ProviderField( + "recommended_model", + "Default Model", + required=False, + default=recommended_model, + choices=model_choices, + help="The model to activate as default when this provider is configured.", + ) + ) + return ProviderDescriptor( name=name, title=title, needs_key=True, - fields=[ - ProviderField( - "api_key", - f"{vendor} API key", - secret=True, - ), - ProviderField( - "base_url", - "Endpoint", - required=False, - default=base_url, - placeholder=base_url, - help=endpoint_help - or f"Prefilled with {vendor}'s official endpoint; edit only for a regional or proxy variant.", - ), - ], + fields=fields, build=_openai_compat(vendor, base_url, env_key), recommended_model=recommended_model, env_key=env_key, @@ -591,6 +607,19 @@ def _responses_compat( env_key="ZAI_API_KEY", endpoint_help="Prefilled with Z AI's international endpoint. China mainland: https://open.bigmodel.cn/api/paas/v4", ), + _compat( + "zai-coding", + "Z AI Coding Plan", + base_url="https://api.z.ai/api/coding/paas/v4", + recommended_model="glm-5.2", + env_key="ZAI_CODING_API_KEY", + endpoint_help="Prefilled with Z AI's Coding Plan endpoint. Note: This requires a separate Coding Plan subscription.", + model_choices=( + {"value": "glm-5.2", "label": "GLM-5.2"}, + {"value": "glm-4.7", "label": "GLM-4.7"}, + {"value": "glm-4-coder", "label": "GLM-4 Coder"}, + ), + ), _compat( "deepseek", "DeepSeek", diff --git a/coworker/server/manager.py b/coworker/server/manager.py index 1486d9064..e6371fcb1 100644 --- a/coworker/server/manager.py +++ b/coworker/server/manager.py @@ -3004,7 +3004,7 @@ def set_provider( self._refresh_provider(name) # Convenience: if the provider recommends a model and it's actually available, add it to # the curated list so it shows up in the composer right after configuring the provider. - rec = d.recommended_model + rec = profile.get("recommended_model") or d.recommended_model added: Optional[str] = None if rec and rec in self._suggested_models(name): # OpenAI models stay bare (the router's default); others carry their prefix. From 48db2a3fb7bea81c447fbd374834fca9ed525195 Mon Sep 17 00:00:00 2001 From: Pranjal Parmar <76609992+pranjalparmar@users.noreply.github.com> Date: Fri, 28 Aug 2026 10:46:11 +0200 Subject: [PATCH 2/2] chore: address PR 583 copilot review feedback --- coworker/providers/registry.py | 2 +- coworker/server/manager.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/coworker/providers/registry.py b/coworker/providers/registry.py index f4a7f6543..bc5cc438b 100644 --- a/coworker/providers/registry.py +++ b/coworker/providers/registry.py @@ -266,7 +266,7 @@ def _compat( ) -> ProviderDescriptor: """Descriptor for an OpenAI-compatible vendor: key + a prefilled, editable endpoint.""" vendor = title.split(" (")[0] - + fields = [ ProviderField( "api_key", diff --git a/coworker/server/manager.py b/coworker/server/manager.py index e6371fcb1..052e0523e 100644 --- a/coworker/server/manager.py +++ b/coworker/server/manager.py @@ -3004,7 +3004,8 @@ def set_provider( self._refresh_provider(name) # Convenience: if the provider recommends a model and it's actually available, add it to # the curated list so it shows up in the composer right after configuring the provider. - rec = profile.get("recommended_model") or d.recommended_model + supports_profile_rec = any(f.key == "recommended_model" for f in d.fields) + rec = (profile.get("recommended_model") if supports_profile_rec else None) or d.recommended_model added: Optional[str] = None if rec and rec in self._suggested_models(name): # OpenAI models stay bare (the router's default); others carry their prefix.