Repository navigation
Rewrite the model-router Python server in Go #10261
Description
Summary
Replace the Python implementation of gh-aw-router in containers/router/ with a Go implementation, preserving its public HTTP and CLI contracts and AWF integration. Ship the router as a compiled binary without a Python runtime or Python web-framework dependencies in the production image.
Current implementation
The router is a self-contained Python service using FastAPI, with classification planning, deterministic heuristics, routing-table validation, and ranked model selection in containers/router/src/gh_aw_router/. Its container listens on port 8737, runs as UID:GID 10001:10001, and ships six routing profiles. AWF integrates it through src/services/router-service.ts, whose healthcheck currently invokes Python.
The authoritative HTTP contract is containers/router/openapi.yaml; shared contract fixtures live in containers/router/tests/fixtures/routing-contract/.
Scope
-
Port the HTTP server and underlying classification, heuristics, routing, request validation, and routing-table loading logic to Go. Keep the service stateless: no provider calls, agent execution, training, or stored task history.
-
Preserve
GET /healthz,GET /capabilities,POST /classify, andPOST /route, including response shapes, status codes, error codes, and strict rejection of unsupported or unknown request fields. -
Preserve ranking semantics, exact caller-supplied model/effort identities, candidate eligibility and context checks, classification prompts, automatic-mode resolution,
current_idhandling, and explicitno_routeoutcomes without invented fallbacks. -
Continue loading the existing schema-version-1 routing tables, validating them at startup, and supporting both a single file and a directory of profiles.
-
Preserve CLI commands (
serve,classify,route,validate-data), flags, environment-variable precedence, stdout/stderr separation, and exit statuses. -
Preserve HTTP safeguards: 1 MiB request-body limit including chunked uploads, bounded concurrency (currently 64 in-flight requests), request deadlines (currently 30 seconds), and validation errors that do not echo submitted values.
-
Replace Python-based Docker and Compose healthchecks. Update container builds, version metadata, dependency auditing, release packaging, CI, and documentation for Go while retaining non-root execution, read-only runtime compatibility, graceful shutdown, and verification of the shipped OpenAPI contract digest.
-
Add structured JSON logging to stderr with configurable levels, timestamps, service/version identity, request correlation, route template, HTTP status, latency, and actionable error codes. Cover startup, routing-table loading/validation, request failures, overload/timeouts, and shutdown. Keep CLI JSON output on stdout unchanged; suppress or sample routine healthcheck access logs.
-
Instrument the service with OpenTelemetry traces and metrics using Go HTTP semantic conventions. Accept W3C trace context for correlation with AWF, add classification/routing spans, and record request counts, latency, errors, in-flight requests, rejected/oversized requests, timeouts, and no-route outcomes. Use bounded, low-cardinality metric attributes; never use request IDs, trace IDs, arbitrary model names, or request content as metric labels.
-
Support opt-in OTLP export through standard OTEL_* environment variables (service/resource identity, endpoint, protocol, headers, sampling, and signal enablement), and wire the configuration through AWF router-service creation. Document supported settings and collector/network requirements. Telemetry must work without a collector, must not add mandatory external network access, and must not make routing fail when export fails. Use bounded queues/timeouts, visible but rate-limited exporter diagnostics, and bounded flush on graceful shutdown.
-
Apply the same privacy rules to logs, spans, metrics, and exporter diagnostics: never record secrets, credentials, authorization/OTLP headers, conversations, prompts, request/response bodies, or raw caller-supplied values in errors or exception events. Emit only explicitly allowlisted operational metadata.
Acceptance criteria
-
The production router image runs the Go binary and does not require Python, pip, uv, FastAPI, or Uvicorn.
-
Existing HTTP contract fixtures and representative CLI inputs produce equivalent results in the Python reference and Go implementation; add differential coverage for malformed input, Unicode, classification prompts, routing ties, context limits, explicit/omitted efforts, automatic modes, and no-route cases.
-
All six bundled routing profiles validate and preserve classification and routing behavior.
-
HTTP limits, error sanitization, startup validation, healthchecks, and graceful shutdown have automated coverage.
-
AWF can build, start, healthcheck, and use the Go router through its existing routing integration without caller configuration changes.
-
Router tests, image build/release checks, dependency scanning, and documentation are updated; obsolete Python production packaging and dependencies are removed.
-
Structured logging and OpenTelemetry are implemented and documented, with request/trace correlation and coverage for routing decisions, failures, resource limits, and service lifecycle; CLI stdout contracts remain unchanged.
-
Automated tests verify trace-context propagation, emitted spans/metrics via an in-process test exporter or local collector, low-cardinality labels, sensitive-data redaction, exporter-disabled/unavailable behavior, AWF configuration propagation, and bounded shutdown flushing.
Non-goals
Changing the routing algorithm, retraining routing tables, changing the public API, or migrating the separately maintained training/benchmark tooling.
Activity
feat(router): add the Go HTTP server, JSON logging and healthcheck (n…