Skip to content

Rewrite the model-router Python server in Go #10261

Open
8 of 8 issues completed
Open

Description

@pelikhan

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, and POST /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_id handling, and explicit no_route outcomes 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions