Baseline for the Kong replacement on api.riotpiao.com. Brings the working tree under version control for the first time: gateway source, the task board that drives the agent runs, test fixtures, and K8s manifests. Anchor the gateway ignore rule to the repo root. Unanchored, "gateway" also matched the cmd/gateway/ source directory, so the program entrypoint was excluded from every commit. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
3.0 KiB
3.0 KiB
2.10 — Anthropic request translation (GREEN)
Phase: 2 — LLM surfaces Stage: GREEN Depends on: 2.9, 2.1
POST /llm/v1/messages accepts an Anthropic Messages request body and turns it into
the dialect-neutral canonical request. The path carries /v1/messages because the
Anthropic base-URL convention appends that suffix; the gateway prefix is /llm.
POST /llm/v1/messagesis accepted and selects its upstream from the body'smodelfield, using the same registry as/v1:reasoningreachesreasoning-predictor.llm-serving:80,ornith:35bandqwen2.5:3b-instructreachornith-predictor.llm-serving:80- The top-level
systemfield becomes the canonical system instruction; it is a distinct field in this dialect and is not a member ofmessages - Each message
contentmay be a plain string or an array of blocks; a string and a single text block carrying the same characters translate identically max_tokensis REQUIRED on this surface, matching the Anthropic contract; a request without it is rejected as a client error and no upstream is contactedmax_tokensabove what the upstream can serve is clamped rather than rejected, and the clamp is logged;reasoninghas--max-model-len=16384- Roles are restricted to
userandassistant; any other role, includingsysteminsidemessages, is a client error naming the offending role stop_sequencesbecomes the canonical stop sequences, andstreambecomes the canonical streaming flagtools,tool_choice, anytool_useortool_resultblock, anyimageblock, any cache-control marker, and any user message with more than one content block are rejected as unsupported, naming the feature; none is silently dropped- Unknown top-level fields are rejected rather than ignored, so a client cannot believe an unimplemented option took effect
- Reading the body respects the route's configured body size cap
max_tokens stays optional on /v1/chat/completions. The policy is per-surface: each
dialect keeps its own contract, and the canonical request records whichever value
resulted.
Verify
curl -s -o /dev/null -w '%{http_code}\n' localhost:8080/llm/v1/messages \
-H 'content-type: application/json' \
-d '{"model":"reasoning","max_tokens":64,"system":"be terse","messages":[{"role":"user","content":"hi"}]}'
# expected: 200, reasoning stub hit, system text present in the upstream request
curl -s localhost:8080/llm/v1/messages -H 'content-type: application/json' \
-d '{"model":"reasoning","messages":[{"role":"user","content":"hi"}]}'
# expected: 400, body names max_tokens as the missing required field, no upstream stub hit
curl -s localhost:8080/llm/v1/messages -H 'content-type: application/json' \
-d '{"model":"reasoning","max_tokens":8,"messages":[{"role":"system","content":"x"}]}'
# expected: 400, body names the rejected role, no upstream stub hit