diff --git a/products/tasks/backend/sandbox/images/Dockerfile.sandbox-base b/products/tasks/backend/sandbox/images/Dockerfile.sandbox-base index 52d03d66355a..1b762ef9dd62 100644 --- a/products/tasks/backend/sandbox/images/Dockerfile.sandbox-base +++ b/products/tasks/backend/sandbox/images/Dockerfile.sandbox-base @@ -105,9 +105,11 @@ RUN set -eux; \ ENV AGENTSH_SERVER=http://127.0.0.1:18080 # Install rtk (https://github.com/rtk-ai/rtk), a proxy that compresses the output of -# common dev commands before it reaches the model. The agent auto-detects it on PATH -# and routes eligible Bash commands through it; POSTHOG_RTK=0 (set per run from the -# task processing context) opts a run out. +# common dev commands before it reaches the model. Claude runs auto-detect it on PATH +# and route eligible Bash commands through it via a PreToolUse rewrite hook; Codex has +# no command-rewrite channel, so its runs are told to prefix eligible commands in the +# developer instructions instead. POSTHOG_RTK=0 (set per run from the task processing +# context) opts a run out of both. ARG RTK_VERSION=0.43.0 RUN set -eux; \ arch="$(dpkg --print-architecture)"; \ diff --git a/products/tasks/backend/temporal/metrics.py b/products/tasks/backend/temporal/metrics.py index be28d2deed34..52165f63345e 100644 --- a/products/tasks/backend/temporal/metrics.py +++ b/products/tasks/backend/temporal/metrics.py @@ -71,6 +71,16 @@ def _bool_label(value: bool | None) -> str: return "true" if value else "false" +_ALLOWED_RUNTIME_ADAPTERS = {"claude", "codex"} + + +def _runtime_adapter_label(value: str | None) -> str: + """Bounded label: unexpected values collapse to "other" to cap cardinality.""" + if not value: + return "unknown" + return value if value in _ALLOWED_RUNTIME_ADAPTERS else "other" + + def increment_snapshot_usage( used_snapshot: bool, *, @@ -139,6 +149,7 @@ def record_run_token_usage( origin_product: str | None, run_environment: str | None, rtk_enabled: bool | None, + runtime_adapter: str | None, status: str | None, ) -> None: """Record a terminal run's token expenditure (from ``TaskRun.state.token_usage``). @@ -150,6 +161,7 @@ def record_run_token_usage( "origin_product": origin_product or "unknown", "run_environment": run_environment or "unknown", "rtk_enabled": _bool_label(rtk_enabled), + "runtime_adapter": _runtime_adapter_label(runtime_adapter), "status": status or "unknown", } for kind, key in _RUN_TOKEN_KINDS.items(): diff --git a/products/tasks/backend/temporal/process_task/activities/tests/test_update_task_run_status.py b/products/tasks/backend/temporal/process_task/activities/tests/test_update_task_run_status.py index 67e75ff13e1f..4211ce9dd146 100644 --- a/products/tasks/backend/temporal/process_task/activities/tests/test_update_task_run_status.py +++ b/products/tasks/backend/temporal/process_task/activities/tests/test_update_task_run_status.py @@ -96,6 +96,7 @@ def test_terminal_transition_captures_analytics_with_usage( **(test_task_run.state or {}), "token_usage": dict(TOKEN_USAGE), "rtk_effective": True, + "runtime_adapter": "codex", } test_task_run.save(update_fields=["state"]) @@ -116,6 +117,7 @@ def test_terminal_transition_captures_analytics_with_usage( assert props["run_environment"] == test_task_run.environment mock_record.assert_called_once() assert mock_record.call_args.kwargs["rtk_enabled"] is True + assert mock_record.call_args.kwargs["runtime_adapter"] == "codex" assert mock_record.call_args.kwargs["status"] == status @pytest.mark.django_db(transaction=True) diff --git a/products/tasks/backend/temporal/process_task/activities/update_task_run_status.py b/products/tasks/backend/temporal/process_task/activities/update_task_run_status.py index 3e9c4126ce13..bafd38fb51c6 100644 --- a/products/tasks/backend/temporal/process_task/activities/update_task_run_status.py +++ b/products/tasks/backend/temporal/process_task/activities/update_task_run_status.py @@ -104,11 +104,13 @@ def _capture_terminal_analytics(task_run: TaskRun, input: UpdateTaskRunStatusInp state = task_run.state if isinstance(task_run.state, dict) else {} usage = state.get("token_usage") if isinstance(usage, dict): + adapter = state.get("runtime_adapter") record_run_token_usage( usage, origin_product=task_run.task.origin_product, run_environment=task_run.environment, rtk_enabled=task_run.effective_rtk(), + runtime_adapter=adapter if isinstance(adapter, str) else None, status=input.status, ) except Exception: