Skip to content

feat(gateway): add per-request Kilo headers, body sanitization, and error contract - #15067

Merged
marius-kilocode merged 16 commits into
gateway-login-v2from
gateway-requests-errors
Oct 15, 2026
Merged

marius-kilocode merged 16 commits into
gateway-login-v2from
gateway-requests-errors

Conversation

@marius-kilocode

Copy link
Copy Markdown
Collaborator

Stacked on #15065.
Part of #14991 (and #13750), PR 3 of the Gateway series. Plan units U-E1-03 (error contract) and U-E1-04 (request attribution, body sanitization, and routed model metadata).

What Problem This Solves

In PR 2 (#15065), Kilo Gateway requests still lacked per-request attribution headers (X-KILOCODE-TASKID, X-KILOCODE-PARENT-TASKID, X-KILOCODE-PROJECTID, X-KILOCODE-MACHINEID, x-kilocode-mode, X-KILOCODE-TESTER, User-Agent), request body sanitization (credential metadata stripping, stateless /responses item_reference/id stripping, provider.data_collection, and Anthropic /messages x-api-key -> Bearer promotion), routedModelID and x-vercel-id extraction from SSE streams, and structured handling of the Gateway error contract (PAID_MODEL_AUTH_REQUIRED, PROMOTION_MODEL_LIMIT_REACHED, 402 usage_limit_exceeded with balance and buyCreditsUrl, top_up_in_progress, model_not_allowed, provider_not_allowed, data_collection_required, upgrade_required).

Why This Change Was Made

Following the architecture in #14991 and #15060:

  1. Per-request headers, project ID, and machine ID in packages/kilo-gateway-core (src/headers.ts, src/project.ts, src/machine.ts):
    • KiloHeaders.request: builds User-Agent: opencode-kilo-provider/<version>, X-KILOCODE-TASKID, X-KILOCODE-PARENT-TASKID, X-KILOCODE-PROJECTID, X-KILOCODE-MACHINEID, x-kilocode-mode (lowercased), and X-KILOCODE-TESTER: SUPPRESS (when configured), alongside the provider headers.
    • KiloProject: resolves project ID from .kilo/config.json, .kilocode/config.json, or git config --get remote.origin.url, normalized to the repository name and truncated to 100 chars (ported from v1 project-id.ts).
    • KiloMachine: resolves KILO_MACHINE_ID or persists telemetry-id in the data directory (ported from v1 identity.ts).
  2. Request body and auth normalization (src/requests.ts):
    • Promotes x-api-key to Authorization: Bearer <key> on Gateway requests (fixing Anthropic /messages key auth).
    • Strips leaked credential metadata keys (server, organizationID, email, etc.) from top-level JSON request bodies while preserving the original Request options and AbortSignal.
    • Strips item_reference items and item id fields on stateless /responses requests (store !== true), and injects provider.data_collection when configured (ported from v1 responses.ts).
  3. Gateway error contract and SSE stream metadata (src/errors.ts, src/stream.ts):
    • Parses both Gateway error envelopes ({ error: { code, message, title, balance, buyCreditsUrl }, error_type } and { error, error_type, message }) plus mid-stream SSE error frames (response.failed, envelope-less { error }, bare { code, message }).
    • Formats actionable messages for PAID_MODEL_AUTH_REQUIRED, PROMOTION_MODEL_LIMIT_REACHED, 402 usage_limit_exceeded (with current balance and buyCreditsUrl), top_up_in_progress (retryable), model_not_allowed, provider_not_allowed, data_collection_required, and upgrade_required.
    • Extracts routedModelID (from provider_metadata.gateway.routing.modelAttempts, routing.canonicalSlug, or response model) and x-vercel-id on 200 SSE streams, stamps routedModelID onto SSE usage, and exposes { routedModelID, vercelID } via kilocode.gateway session.metadata RPC.

Shared upstream files changed

None in this PR (all changes are in Kilo-owned paths packages/kilo-gateway-core/** and packages/core/**/kilocode/**).

User Impact

  • Every Kilo Gateway inference request carries full Kilo attribution headers (X-KILOCODE-TASKID, X-KILOCODE-PARENT-TASKID, X-KILOCODE-PROJECTID, X-KILOCODE-MACHINEID, x-kilocode-mode, User-Agent) so the Gateway backend attributes usage, rate limits, and billing accurately.
  • Gateway errors (sign-in required for paid models, promotion limits, depleted credits with balance and buy-credits link, organization allow-list blocks, and zero-data-retention blocks) display clear, actionable messages in the CLI and TUI.
  • Auto-routed models (kilo-auto/*) record the backend-selected routedModelID and x-vercel-id.

Evidence

Automated checks

  • bun script/check-opencode-annotations.ts: ok (39 shared files against 4d9678a79d6)
  • bun script/check-shared-patches.ts: ok (0 new shared upstream files touched)
  • bun run --cwd packages/kilo-gateway-core typecheck && bun run --cwd packages/kilo-gateway-core build: pass
  • bun run --cwd packages/core typecheck: pass
  • bun run --cwd packages/tui typecheck: pass
  • bun test --cwd packages/kilo-gateway-core: 33 pass, 0 fail (107 assertions)
  • bun test --cwd packages/core test/kilocode/gateway.test.ts test/plugin/provider-kilo.test.ts: 13 pass, 0 fail (60 assertions)

CLI & TUI Self-Test

  1. Verified outgoing HTTP request headers:
    • Captured on /api/gateway/chat/completions: http-referer: https://kilocode.ai, x-title: Kilo Code, user-agent: opencode-kilo-provider/..., x-kilocode-editorname, x-kilocode-feature, x-kilocode-machineid, x-kilocode-mode, x-kilocode-projectid: kilocode, x-kilocode-taskid: ses_....
  2. TUI request verification and error contract (402 usage_limit_exceeded and 401 PAID_MODEL_AUTH_REQUIRED):

Verified Gateway request with full Kilo attribution headers in TUI

402 usage_limit_exceeded error with balance and buyCreditsUrl in TUI

401 PAID_MODEL_AUTH_REQUIRED error in TUI

@github-actions github-actions Bot added area:cli CLI, TUI and core engine area:gateway Kilo Gateway and auth labels Oct 14, 2026
@kilo-code-bot

kilo-code-bot Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Reviewed the Gateway PR 3 changes: per-request attribution headers, request body/auth sanitization, the Gateway error contract, and SSE routing metadata. All 11 files are Kilo-owned paths; no shared upstream files changed.

Notable checks performed:

  • KiloHeaders.request/provider header construction and tester-suppression gating.
  • KiloRequests.rewriteRequest/transformBody: x-api-key -> Bearer promotion, credential-key stripping, stateless /responses item_reference/id stripping, and provider.data_collection injection.
  • KiloErrors.parse/rewriteHttpResponse: both envelopes, mid-stream SSE error frames, retryability classification, and 402 balance/buy-credits formatting.
  • KiloStream SSE transform buffering, [DONE]/non-record handling, UTF-8 boundary decoding, and routedModelID/x-vercel-id extraction.
  • Memory-leak review: the new sessionMetadata map in gateway.ts is bounded at 500 entries with oldest-key eviction on insert, so it does not grow unbounded; the SSE transform buffers are cleared on flush. No leak found.
  • request.clone().text() / response.clone().text() patterns in requests.ts and errors.ts match existing repository conventions (e.g. snowflake-cortex.ts, github-copilot.ts).
Files Reviewed (11 files)
  • packages/core/src/kilocode/gateway-rpc.ts
  • packages/core/src/kilocode/gateway.ts
  • packages/core/test/kilocode/gateway.test.ts
  • packages/kilo-gateway-core/src/errors.ts
  • packages/kilo-gateway-core/src/headers.ts
  • packages/kilo-gateway-core/src/index.ts
  • packages/kilo-gateway-core/src/machine.ts
  • packages/kilo-gateway-core/src/project.ts
  • packages/kilo-gateway-core/src/requests.ts
  • packages/kilo-gateway-core/src/stream.ts
  • packages/kilo-gateway-core/test/requests-errors.test.ts

Reviewed by deepseek-v4.1-flash · Input: 93.9K · Output: 30.1K · Cached: 1.5M

Base automatically changed from gateway-catalog to gateway-login-v2 October 15, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:cli CLI, TUI and core engine area:gateway Kilo Gateway and auth

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants