Decision: agentgateway does not displace Agent Proxy, but it is a live candidate to displace standalone LiteLLM as the inner gateway #150
Labels
No labels
burndown-2026-08
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/advocate
role/director
role/exec
role/frontend
role/gamedev
role/human
role/platform
role/qa
role/science
role/sysadmin
state
ambient
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/agent-proxy#150
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Filed by Portia (director seat) from a session where Kai raised deprecating Agent Proxy in favour of agentgateway. Recording the call so nobody re-derives it, and scoping the one probe that is actually live. Sub-answer to
coilysiren/inbox#428(Scout everything AAIF).Call 1 - Agent Proxy is not deprecated. Closed.
The comparison is category-mismatched. agentgateway is a commodity gateway. Agent Proxy already decided the commodity-gateway half is not its value and delegates it downward.
README.mdonmain(36d9e73): "LiteLLM will own provider protocols, routing, retry, fallback, keys, budgets, and cost accounting." What Agent Proxy keeps is the evidence plane - and the README is equally explicit that "SigNoz and OTLP carry operational traces, logs, and metrics, and are deliberately not the durable training-data store."agentgateway emits OpenTelemetry metrics, logs, and tracing. That is the SigNoz-shaped artifact the architecture already declines as the durable store. It does not ship the trajectory contract, append-only ingestion with idempotent receipts and replay, deterministic episode reconstruction with provenance and content hashes, immutable evaluation records with supersession, or dataset export with write-once manifests and trajectory-level leakage prevention.
Size of what a deprecation would discard, counted on
main:app/trajectory/is 4,072 lines, plusobs.py622,skill_use.py455,analysis.py303,body_capture.py236. Roughly 5.7K of ~10.9K app lines have no counterpart in agentgateway.Reverses if something ships durable trajectory-contract-shaped capture - episode reconstruction with provenance hashes, immutable evaluation records, leakage-preventing dataset export. OTel telemetry is not that artifact and adding more of it does not become that artifact.
Call 2 - agentgateway vs standalone LiteLLM as the inner gateway. Open, and worth one bounded probe.
docs/litellm-parity.mdselects standalone LiteLLM but holdscutover_authorizedfalse pending the retirement blockers. Nothing is deployed on that decision yet, so the switching cost today is the client shim (app/litellm_parity.py, 418 lines) rather than a migration.The parity gate is already built and gateway-agnostic:
just litellm-parity --baseline-url URL --candidate-url URL --model TAG. Pointing it at an agentgateway standalone binary is cheap.For agentgateway:
litellm-parity.mdlists "virtual key isolation, budget rejection, spend attribution, and its required Postgres dependency" as a retirement blocker. agentgateway deletes that blocker rather than satisfying it./mcpsurface Agent Proxy already ships.Against, or unweighed:
#128putssirens-echo/defaultat 276 calls a week, and the bottleneck is an Ollama tower generating tokens, not gateway QPS.fmind.dev/articles/agentgateway-vs-litellm/, 2026-08-16) discloses AAIF Ambassador status. Its 2026 advisory count - agentgateway 3 with 1 High, LiteLLM 12 with 3 Critical and 2 in CISA KEV - is single-sourced and not independently verified.docs.solo.ioas "Solo Enterprise for agentgateway", with an undocumented enterprise control plane. Open data plane, vendor-shaped docs and control plane.The deciding blocker, genuinely open: whether agentgateway passes Agent Proxy's derived safe
num_ctxthrough to Ollama as a top-level extension. Agent Proxy forwards it and then verifies delivered context; the LiteLLM boundary already accommodates that. agentgateway's provider docs cover base URL and auth passthrough and say nothing about unknown-parameter passthrough. Ifnum_ctxdoes not survive the hop, agentgateway is disqualified as the inner gateway regardless of everything above.The probe
Owned by the platform seat. Bounded, and it stops at evidence rather than at a cutover.
ollamaprovider.num_ctxand assert delivered-context verification stays green. Stop here if it fails and record the disqualification.just litellm-paritywith agentgateway as candidate and the current surface as baseline. Keep the JSON artifact.litellm-parity.mdstandalone-advantage list.Existing blockers stay where they are.
cutover_authorizedstays false either way - this probe changes which candidate the gate is aimed at, not whether the gate is passed.Related:
#134and#129(cancellation not propagating upstream),#111(automatic fallback model),#107(queue or shed under burst). Those are commodity-gateway defects in the hot path, and they are the standing argument for finishing this hand-off to some inner gateway rather than growing the custom one.Correction: the
num_ctxblocker is dead. agentgateway passes unknown top-level parameters through. I read the source instead of the docs, then measured the round-trip.Checked at
agentgateway/agentgateway@5fb188b.The mechanism
crates/llm/src/types/completions.rs, the OpenAI chat-completions request type, ends with a catch-all:Unknown top-level fields collect into
reston deserialize and are re-emitted on serialize.RequestMessagecarries the samerestfield, so unknown per-message fields survive too.crates/llm/src/conversion/vertex.rs:87names the intent outright: "output_dimensionalityhas no OpenAI equivalent and arrives via the passthroughrest."The outbound render for our path does no filtering,
crates/agentgateway/src/llm/mod.rs:355:Ollama is
ProviderPreset::Ollamaincrates/llm/src/custom.rs, so it routes asAIProvider::Customon the OpenAI completions format and lands on exactly that render.The measurement
Compiled a probe mirroring that struct field-for-field on the attributes that decide the outcome, and ran an Agent-Proxy-shaped body through deserialize then serialize:
Top-level
num_ctx, nestedoptions.num_ctx, and an arbitrary correlation key all survive. The negative control, the same struct with the flatten field removed, drops all three, which is the failure mode I had assumed and is not what agentgateway does.What this does and does not settle
Settled: agentgateway does not silently strip Agent Proxy's derived safe
num_ctx, and it does not strip arbitrary correlation fields either. No disqualification.Not settled, and the probe still runs to confirm:
apply_model_aliasmutatesmodelunder policy on this path. It does not touchrest, but policy-driven body mutation exists and delivered-context verification should still be asserted end to end.num_ctx, only that it arrives.Probe revised
Step 2 stops being a stop-or-go gate and becomes confirmation. Reordered:
ollamaprovider.just litellm-paritywith agentgateway as candidate against the current surface as baseline. Keep the JSON artifact.num_ctxarrives and delivered-context verification stays green through the live hop.litellm-parity.mdstandalone-advantage list. This is now the largest open question, since it is where LiteLLM's standalone advantage was argued.Effect on the calls
Call 1 is unchanged. Agent Proxy is still not deprecated, and none of this touches the trajectory plane.
Call 2 moves from open to leaning. The disqualifying risk is gone and the remaining case favours agentgateway on operational surface: one binary against FastAPI plus Postgres plus Redis, where
litellm-parity.mdlists that Postgres dependency as a retirement blocker in its own right. That is the reason to prefer it. The QPS benchmark is still irrelevant at 276 calls a week and the AAIF hosting is still not evidence.Second correction, and it closes Call 2. The estate does not use virtual keys or budgets. LiteLLM's entire standalone advantage is unexercised.
I carried that from
litellm-parity.md's capability list and called it the largest open question. It was a feature list, not usage. Kai asked whether we actually use it. We do not. Checkedcoilyco-bridge/deploy@main.The production key has no budget and no scope
services/litellm/scripts/provision-agent-proxy-key.shprovisions the one durable key at/coilysiren/litellm/agent-proxy-key:No
max_budget. Notpm_limitorrpm_limit.models: ["all-proxy-models"]is access to everything. That is a bearer token with an alias attached, and any gateway that checks anAuthorizationheader does the same job.max_budgetexists in exactly one file, and it is a test fixtureAcross the whole service,
max_budget,budget_duration,soft_budget,tpm_limit, andrpm_limitappear only inservices/litellm/scripts/evaluate.sh, at0.000001, on a key the evaluator creates to prove rejection fires and then deletes on exit.just evaluate-litellm-ser8proves the feature works. Nothing runs it in production.Nothing reads the spend
Grepped both repos for
/spend,spend/logs,global/spend, andLiteLLM_SpendLogs. Zero hits outside the evaluator. The only/key/infocall is the provisioner checking its own key is still valid.And the numbers would be fiction anyway for most traffic.
chart/templates/configmap.yamlappliessynthetic_accountingwith flatinputCostPerTokenandoutputCostPerTokento the local providers, so spend on the Ollama fleet is a made-up rate. Only hosted DeepSeek carries real provider accounting, and nothing queries it.Cost facts that Agent Proxy actually consumes arrive in the response and land in the
trajectory-contract-v1model-execution fields. They do not come from LiteLLM's Postgres.So Postgres is carrying nothing
services/litellm/README.mdputs PostgreSQL 16.14 on a 5 Gilocal-pathclaim to retain "spend and key state". The key state is one row. The spend state has no reader. That is a stateful dependency, a PVC, and a backup surface on ser8, held up entirely by a capability nobody exercises.litellm-parity.mdlists "virtual key isolation, budget rejection, spend attribution, and its required Postgres dependency" as a retirement blocker. It was never a blocker. It was a cost.Call 2 is closed: agentgateway is selected as the inner gateway
Deciding evidence, all of it now in:
num_ctxand arbitrary correlation fields pass through agentgateway. Measured, previous comment.DeepseekandOllamaare bothProviderPresetvalues incrates/llm/src/custom.rs, so hosted DeepSeek and the local towers both route natively.Foreclosed: standalone LiteLLM as the inner gateway, and with it the Postgres and PVC on ser8.
services/litellm/becomes a retirement candidate rather than an evaluation candidate, but not before the parity gate passes on the replacement. Deleting it is the sysadmin seat's call and a separate issue.Reverses if the parity gate fails on agentgateway, or a second independent consumer of the inner gateway appears and needs real per-tenant budget enforcement. One consumer is why none of this was ever needed.
Unchanged:
cutover_authorizedstays false. Selection is not cutover, exactly as the parity doc already frames it. The probe still runs, now as the gate on a chosen candidate rather than a bake-off.Also unchanged: Call 1. Agent Proxy is not deprecated, and none of this touches the trajectory plane.
Decision handed off. This issue stays the decision record and holds the probe.
docs/litellm-parity.mdto record the agentgateway selection, rename it off the candidate's name, and reconcileapp/litellm_parity.py. Platform seat, P2, headless. The doc currently states the retired answer, which is why it is P2 rather than P3.coilyco-bridge/deploy#819- retireservices/litellm/on ser8 and drop the Postgres and its 5 Gi PVC. Sysadmin seat, P3, blocked on the probe here and on an agentgateway service actually serving. Staged disable-observe-delete, with the PVC deletion held back as its own confirmation.One gap, named rather than filed. #819 is blocked on "an agentgateway service exists in this repo and is serving Agent Proxy", and no issue owns building that yet. It is deliberately sequenced after the probe, because the deployment shape (config format, listener, secret paths, SigNoz pipeline) is not knowable until the probe reports. Whoever closes the probe files that issue as its immediate successor. It is the one link in this chain with no owner, so it is the one most likely to be dropped.