diff --git a/products/tasks/backend/temporal/process_task/utils.py b/products/tasks/backend/temporal/process_task/utils.py index b9f7a6bbd1cd..afd4bba1da3f 100644 --- a/products/tasks/backend/temporal/process_task/utils.py +++ b/products/tasks/backend/temporal/process_task/utils.py @@ -97,6 +97,13 @@ class ReasoningEffort(StrEnum): CLAUDE_REASONING_EFFORTS_BY_MODEL: dict[str, tuple[ReasoningEffort, ...]] = { + # GLM 5.2 is a Cloudflare-served model driven through the `claude` runtime adapter: the LLM + # gateway exposes it over its Anthropic-Messages surface and translates the `@cf/` id upstream, + # so the derived `provider="anthropic"` is the intended routing, not a direct Anthropic call. + "@cf/zai-org/glm-5.2": ( + ReasoningEffort.HIGH, + ReasoningEffort.MAX, + ), "claude-opus-4-5": ( ReasoningEffort.LOW, ReasoningEffort.MEDIUM, diff --git a/products/tasks/backend/tests/test_api.py b/products/tasks/backend/tests/test_api.py index af6feeefe41f..c9eb3b9982af 100644 --- a/products/tasks/backend/tests/test_api.py +++ b/products/tasks/backend/tests/test_api.py @@ -2471,25 +2471,29 @@ def test_run_endpoint_accepts_token_even_without_linked_identity(self, mock_work @parameterized.expand( [ - ("gpt_5_3_low", "gpt-5.3-codex", "low"), - ("gpt_5_3_medium", "gpt-5.3-codex", "medium"), - ("gpt_5_3_high", "gpt-5.3-codex", "high"), - ("gpt_5_5_xhigh", "gpt-5.5", "xhigh"), - ("gpt_5_6_sol_xhigh", "gpt-5.6-sol", "xhigh"), - ("gpt_5_6_sol_max", "gpt-5.6-sol", "max"), - ("gpt_5_6_luna_xhigh", "gpt-5.6-luna", "xhigh"), - ("gpt_5_6_luna_max", "gpt-5.6-luna", "max"), + ("gpt_5_3_low", "codex", "gpt-5.3-codex", "low", "openai"), + ("gpt_5_3_medium", "codex", "gpt-5.3-codex", "medium", "openai"), + ("gpt_5_3_high", "codex", "gpt-5.3-codex", "high", "openai"), + ("gpt_5_5_xhigh", "codex", "gpt-5.5", "xhigh", "openai"), + ("gpt_5_6_sol_xhigh", "codex", "gpt-5.6-sol", "xhigh", "openai"), + ("gpt_5_6_sol_max", "codex", "gpt-5.6-sol", "max", "openai"), + ("gpt_5_6_luna_xhigh", "codex", "gpt-5.6-luna", "xhigh", "openai"), + ("gpt_5_6_luna_max", "codex", "gpt-5.6-luna", "max", "openai"), + ("glm_5_2_high", "claude", "@cf/zai-org/glm-5.2", "high", "anthropic"), + ("glm_5_2_max", "claude", "@cf/zai-org/glm-5.2", "max", "anthropic"), ] ) @patch("products.tasks.backend.temporal.client.execute_task_processing_workflow") - def test_run_endpoint_persists_runtime_metadata(self, _case_name, model, reasoning_effort, mock_workflow): + def test_run_endpoint_persists_runtime_metadata( + self, _case_name, runtime_adapter, model, reasoning_effort, provider, mock_workflow + ): task = self.create_task() response = self.client.post( f"/api/projects/@current/tasks/{task.id}/run/", { "mode": "interactive", - "runtime_adapter": "codex", + "runtime_adapter": runtime_adapter, "model": model, "reasoning_effort": reasoning_effort, }, @@ -2499,12 +2503,12 @@ def test_run_endpoint_persists_runtime_metadata(self, _case_name, model, reasoni assert response.status_code == status.HTTP_200_OK latest_run = response.json()["latest_run"] task_run = TaskRun.objects.get(id=latest_run["id"]) - assert task_run.state["runtime_adapter"] == "codex" - assert task_run.state["provider"] == "openai" + assert task_run.state["runtime_adapter"] == runtime_adapter + assert task_run.state["provider"] == provider assert task_run.state["model"] == model assert task_run.state["reasoning_effort"] == reasoning_effort - assert latest_run["runtime_adapter"] == "codex" - assert latest_run["provider"] == "openai" + assert latest_run["runtime_adapter"] == runtime_adapter + assert latest_run["provider"] == provider assert latest_run["model"] == model assert latest_run["reasoning_effort"] == reasoning_effort mock_workflow.assert_called_once() @@ -2736,17 +2740,25 @@ def test_run_endpoint_rejects_unsupported_codex_reasoning_effort( } mock_workflow.assert_not_called() + @parameterized.expand( + [ + ("unknown_model", "claude-sonnet-4-5", "high", "none"), + ("glm_medium", "@cf/zai-org/glm-5.2", "medium", "high, max"), + ] + ) @patch("products.tasks.backend.presentation.serializers.posthoganalytics.capture") @patch("products.tasks.backend.temporal.client.execute_task_processing_workflow") - def test_run_endpoint_rejects_unsupported_claude_reasoning_effort(self, mock_workflow, mock_capture): + def test_run_endpoint_rejects_unsupported_claude_reasoning_effort( + self, _case_name, model, reasoning_effort, supported_values, mock_workflow, mock_capture + ): task = self.create_task() response = self.client.post( f"/api/projects/@current/tasks/{task.id}/run/", { "runtime_adapter": "claude", - "model": "claude-sonnet-4-5", - "reasoning_effort": "high", + "model": model, + "reasoning_effort": reasoning_effort, }, format="json", ) @@ -2756,8 +2768,8 @@ def test_run_endpoint_rejects_unsupported_claude_reasoning_effort(self, mock_wor "type": "validation_error", "code": "invalid_input", "detail": ( - "Reasoning effort 'high' is not supported for runtime_adapter 'claude' " - "and model 'claude-sonnet-4-5'. Supported values: none." + f"Reasoning effort '{reasoning_effort}' is not supported for runtime_adapter 'claude' " + f"and model '{model}'. Supported values: {supported_values}." ), "attr": "reasoning_effort", } @@ -2771,11 +2783,11 @@ def test_run_endpoint_rejects_unsupported_claude_reasoning_effort(self, mock_wor event="task run reasoning effort rejected", properties={ "runtime_adapter": "claude", - "model": "claude-sonnet-4-5", - "reasoning_effort": "high", + "model": model, + "reasoning_effort": reasoning_effort, "error": ( - "Reasoning effort 'high' is not supported for runtime_adapter 'claude' " - "and model 'claude-sonnet-4-5'. Supported values: none." + f"Reasoning effort '{reasoning_effort}' is not supported for runtime_adapter 'claude' " + f"and model '{model}'. Supported values: {supported_values}." ), }, groups=ANY,