Repository navigation
feat(ai-gateway): custom auto routers on the gateway path - #7809
Merged
Merged
Conversation
Adds ADR 0005 shared contracts: custom router model IDs, pool entry schemas, the public decide API, client eval protocol schemas, web REST schemas, and the signed auto-decision token. AutoRoutingModeSchema moves next to AutoRouterSchema so the new module does not import the package entry.
Inside the accuracy band a candidate whose estimated request cost is exactly 0 outranks every paid candidate and drops the cost term (ADR 0005), ordered by effectiveLatency^1.5 / wilson^15. Paid ordering is unchanged. Bumps RANKING_POLICY_VERSION so tables republish.
Stores ADR 0005 custom router definitions with an XOR owner check, one unique slug per owner, and entries typed by the contracts pool entry union. Soft delete removes a user's own routers.
Consumers that typecheck packages/db source would otherwise pull in the contracts source, which needs a newer TypeScript lib than some of them set (services/ai-attribution failed on toSorted). The jsonb entry union mirrors the contracts shape, so call sites that pass contracts values still fail to compile if the shape drifts.
…ical An entries update must now send defaultEntryKey so the stored default cannot fall outside the new pool, and gateway model IDs must not start with the reserved client: prefix so a candidate model string maps to exactly one entry.
ADR 0005. The auto-routing worker reads custom router definitions from
PostgreSQL through Hyperdrive with an isolate cache and decides within the
router's pool:
- POST /v1/decide authenticates the caller's Kilo token, resolves the router
by scope or organization context, checks membership and the paying owner's
balance, decides, and returns a signed decision ID.
- POST /v1/eval/{plan,case,result} check router editor rights and the owner's
balance, then forward the router context and grader billing to the
benchmark worker.
- The internal /decide accepts an optional customRouter reference and
returns entry, stale, and fallback; platform requests are unchanged.
- Null decisions use the default entry, then the first servable entry, and
fail with custom_router_unavailable otherwise.
Token pepper, organization context, membership, member balance, the paid
usage balance gate, and the enterprise deny list move to
@kilocode/worker-utils/account-access; the gateway and web callers use it.
…den catalog and card
…eat/auto-custom-routers-web
…eat/auto-custom-routers-serve
…domains on the CLI path The public decide route now asks the AI gateway which of a router's gateway entries the organization model policy denies the member. A new internal gateway route runs the gateway's own evaluation (group policy grants, provider limits, and the data-collection rule) for named candidates, so the CLI path and the gateway share one implementation. The worker caches the answer for a minute and denies every gateway entry when the gateway cannot answer. Blocked email domain parsing and matching move to @kilocode/worker-utils/account-access. Every public worker route rejects a user in a blocked domain, read from the same Upstash key the web app uses.
…to feat/auto-custom-routers-gateway
…drop an unreachable deny-list branch
…isions Serve kilo-auto/custom/<slug> and kilo-auto/custom/org/<slug> through the internal /decide with the router reference and gateway entries only. A worker outage, a null decision, or a pick outside the pool fails the request instead of falling back to another model. Organization Auto routes may target an organization custom router. Requests carrying x-kilo-auto-decision are verified with AUTO_ROUTING_DECISION_SECRET and attributed to the router.
Only flagged owners can create custom routers, so the gateway resolves a router without a PostHog check, matching the auto-routing worker (ADR 0005).
…re benchmark admission
…ve-ready # Conflicts: # docs/adr/0005-custom-auto-routers.md # packages/auto-routing-contracts/src/custom-router.ts
…uters-serve' into fix/custom-router-gateway-ready
…eway-ready # Conflicts: # packages/web-shared/src/lib/ai-gateway/auto-routing-denied-models.test.ts # packages/web-shared/src/lib/ai-gateway/auto-routing-denied-models.ts
…to fix/custom-router-gateway-ready # Conflicts: # apps/web/src/app/api/auto-routing/custom-routers/route.test.ts # apps/web/src/lib/auto-routing-custom-routers.ts # packages/web-shared/src/lib/ai-gateway/auto-model/index.ts # packages/web-shared/src/lib/ai-gateway/auto-routing-benchmark-admin-client.test.ts # packages/web-shared/src/lib/ai-gateway/auto-routing-benchmark-admin-client.ts # packages/web-shared/src/lib/ai-gateway/custom-routers.ts
…eway-ready # Conflicts: # apps/web/src/lib/auto-routing-custom-routers.ts # packages/web-shared/src/lib/ai-gateway/auto-model/index.ts # packages/web-shared/src/lib/ai-gateway/custom-routers.ts
This was referenced Oct 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Gateway slice of ADR 0005. Stacked on #7791. The branch also merges #7790, because it reuses that PR's custom router reads.
Gateway path for custom routers
kilo-auto/custom/<slug>andkilo-auto/custom/org/<slug>are now auto models in the LLM proxy. The proxy resolves them like this:router_not_found(404), using the contract error codes and statuses. The gateway does not check thekilo-auto-custom-routersflag: only flagged owners can create routers, so a router's existence is the gate on both the gateway and CLI paths (ADR 0005).The proxy calls the internal
/decidewith:customRouterreference,requestedModel,It sends no
clientEntries.The worker handles null decisions (the default member, or
custom_router_unavailable). The gateway serves exactly the gateway entry that the worker returns, with its exact catalog variant. It never falls back outside the pool:auto_routing_unavailable(503 withRetry-After).Usage rows record the custom router model ID as
auto_model. Classifier billing stays on the worker-owned path: the decide request names the custom model ID, and the legacy positive-cost fallback is unchanged.Organization Auto targets
kilo-auto/orgroute or fallback target can namekilo-auto/custom/org/<slug>, but only for a router owned by the same organization. The target is resolved through the custom router path above. Targets that name a personal router are rejected, both by validation and by the stored-settings schema.Decision header
x-kilo-auto-decisionis checked withverifyAutoDecisionandAUTO_ROUTING_DECISION_SECRET. That secret is a new gateway env var, documented inENVIRONMENT.md; it must match the worker's secret.auto_modelto the token's router model ID.invalid_auto_decisionerror with a reason:Organization policy for auto candidates
deniedModelIdsfrom the Efficient table or the custom pool, so Frontier could pick a blocked model that the gateway then rejected.Deploy notes
AUTO_ROUTING_DECISION_SECRETon thekilocode-ai-gatewayproject with the same value as the worker'sAUTO_ROUTING_DECISION_SECRET_PROD, before CLIs send the header.Verification
On a work VM:
pnpm typecheckpasses inpackages/web-shared,packages/db,apps/ai-gateway, andapps/web.auto-model/**, including the newcustom-routerandauto-decisiontests,auto-routing-decision,auto-routing-denied-models,handlers/llm-proxy,llm-proxy-helpers, andhandlers/models,api/auto-routing/custom-routers,organization-modes-router,organization-settings-router, andopenrouter-models.auto-routing-denied-models,handlers/llm-proxy,auto-routing-models,handlers/models,handlers/organization-models, andorganization-settings-routerpass;packages/web-sharedtypecheck and oxlint pass.