Skip to content

Add Model Provider Service routing for claude and codex #224

Add Model Provider Service routing for claude and codex

Add Model Provider Service routing for claude and codex #224

Workflow file for this run

name: CI
on:
workflow_dispatch:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
- run: uv run pytest --ignore=tests/test_e2e.py --ignore=tests/test_e2e_tracing.py
e2e:
runs-on: ubuntu-latest
env:
UCODE_TEST_WORKSPACE: ${{ secrets.UCODE_TEST_WORKSPACE }}
DATABRICKS_HOST: ${{ secrets.UCODE_TEST_WORKSPACE }}
# DATABRICKS_BEARER is the CI escape hatch: `databricks auth token`
# only retrieves cached user-OAuth tokens, so on a hosted runner
# (no databrickscfg, no cached login) it can never produce a bearer.
# Pre-fetch one (e.g. via M2M OAuth client_credentials against
# /oidc/v1/token) and store it as a repo secret. Both
# has_valid_databricks_auth + get_databricks_token + the agents'
# apiKeyHelper short-circuit to this value when set. Tokens are
# short-lived (~1h); rotate when CI starts failing with 401s.
DATABRICKS_BEARER: ${{ secrets.DATABRICKS_BEARER }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
- uses: databricks/setup-cli@bdb89f81c11a5bd647fd55b585b7c396ec68a25a # v1.0.0
# The agent launch tests `_require_binary("codex")` etc. and skip when
# the CLI isn't on PATH. Install all six so each TestXxxLaunch test
# actually runs instead of skipping.
- name: Install agent CLIs
run: npm install -g
@anthropic-ai/claude-code
@openai/codex
@google/gemini-cli
opencode-ai
@github/copilot
@earendil-works/pi-coding-agent
- run: uv tool install .
# Redirect stdin so any interactive `databricks auth login --no-browser`
# fallback EOFs instead of hanging the runner. With DATABRICKS_BEARER
# set, the auth code path doesn't shell out at all — this is a safety
# net for any code path we may have missed.
- run: uv run pytest tests/test_e2e.py -v < /dev/null
# MLflow tracing e2e lives in its own file and needs the `tracing`
# extra so `import mlflow` resolves (otherwise the test importorskips
# and silently passes as skipped). `!cancelled()` lets this run even
# when the previous pytest step failed — the two suites are
# independent and one shouldn't mask the other.
- if: ${{ !cancelled() }}
run: uv run --extra tracing pytest tests/test_e2e_tracing.py -v < /dev/null
# Diagnostic: the Claude Stop hook writes its trace-creation log to
# $cwd/.claude/mlflow/claude_tracing.log. If the tracing test failed
# because no root `claude_code_conversation` span landed, this shows
# whether the hook fired on the runner and what its MLflow write did.
- if: ${{ failure() }}
name: Dump Claude tracing hook log
run: |
echo "=== claude_tracing.log ==="
cat .claude/mlflow/claude_tracing.log 2>/dev/null || echo "(no hook log — Stop hook never ran)"
echo "=== installed claude-code + mlflow CLI ==="
claude --version || true
"$(uv tool dir --bin)/mlflow" --version || true
# Diagnostic: reproduce the client-side span export from the runner with
# verbose logging. The hook's `log_spans` failure is logged at WARNING to
# mlflow's own logger (not the hook file log), so surface it directly to
# see why the root span never reaches the trace server from CI.
- if: ${{ failure() }}
name: Probe MLflow span export
env:
DATABRICKS_TOKEN: ${{ secrets.DATABRICKS_BEARER }}
run: |
uv run --extra tracing python - <<'PY' 2>&1 || true
import logging
logging.basicConfig(level=logging.DEBUG)
import os, mlflow
mlflow.set_tracking_uri("databricks")
mlflow.set_experiment(experiment_id="2190569664060193")
print("=== starting probe span ===")
with mlflow.start_span(name="ci_export_probe") as span:
span.set_inputs({"probe": True})
try:
mlflow.flush_trace_async_logging()
except Exception as e:
print("flush error:", repr(e))
print("=== probe done ===")
PY