Repository navigation
[Kiro] Event stream already carries per-request credit metering — adapter drops meteringEvent #5948
Description
Area: Provider adapters
What are you trying to accomplish?
Accurate per-request cost accounting for the kiro provider. Every Kiro request row in usage.jsonl currently records estimated: true token counts and cacheProvenance: "unknown", so there is no real usage/cost signal for Kiro traffic at all — not even the one the upstream already sends.
What prevents this today?
The Kiro event stream already emits a meteringEvent frame carrying the actual credits charged for the request, but KNOWN_EVENT_TYPES in src/adapters/kiro-events.ts does not include it, so parseKiroEvent() returns null and the frame is dropped silently — ocx debug provider on does not log it either.
Live capture (fresh free-tier Builder ID account, opencodex 2.65.0, raw decodeEventStream probe against runtime.us-east-1.kiro.dev):
glm-5:
#1 :event-type=initial-response {"conversationId": "..."} <- dropped
#2 :event-type=assistantResponseEvent {"content": "...", "modelId"}
#3 :event-type=metadataEvent {"stopReason": "END_TURN"} <- no tokenUsage
#4 :event-type=contextUsageEvent {"contextUsagePercentage": 1.94}
#5 :event-type=meteringEvent {"unit": "credit", "unitPlural": "credits",
"usage": 0.04582331509121062} <- dropped
claude-sonnet-4.5 (same account/endpoint):
#1 initial-response, #2 assistantResponseEvent, #3 metadataEvent {stopReason},
#4 contextUsageEvent {contextUsagePercentage: 2.03},
#5 meteringEvent {"unit":"credit","usage":0.009624912835820896}
q.us-east-1.amazonaws.com/generateAssistantResponse emits the same meteringEvent shape.
Two facts worth stating plainly:
metadataEventcarried notokenUsagein any observed frame, on either model, on either endpoint — the token-count absence is real upstream behavior, not an adapter miss.- The
meteringEventcredit value is present every request and is currently invisible to opencodex.
What should OpenCodex do?
- Recognize
meteringEvent(and defensivelyusageEvent/metricsEvent/tokenMetricswrappers) and record the reported credit amount on the request log/usage row — e.g. acreditUsagefield alongsideOcxUsage, sousage.jsonlcarries real spend instead of only heuristic tokens. - Log dropped/unknown
:event-typenames viadebugProviderDiagnosticwhen provider debug is on — today they leave no trace even in debug mode, which hides exactly this class of upstream data. - Optionally:
initial-responsealso carriesconversationIdand is dropped; whenmessageMetadataEventis absent (it was on both captures above), the conversation id is lost.
Example
Current row:
"usage": {"inputTokens": 8, "outputTokens": 1, "contextTotalTokens": 3701, "estimated": true},
"cacheProvenance": "unknown"Desired (exact field naming up to you):
"usage": { ..., "estimated": true },
"creditUsage": {"unit": "credit", "amount": 0.04582331509121062}Alternatives or workarounds
The heuristic estimator (devlog 142/160) is the right answer for input_tokens/output_tokens display and Codex auto-compact — keep it. This proposal only adds the billing signal next to it. Another implementation of the same subscription surface, 0a00/Kiro-Go-Plus (proxy/eventstream_payload.go, proxy/kiro.go), already classifies meteringEvent/usageEvent/metricsEvent frames and recursively hunts nested usage envelopes, including Anthropic-style cacheReadInputTokens/cacheCreation splits when present — useful reference for the priority order.
Additional context
- Account type: Kiro free tier (Builder ID / social OAuth), profile
us-east-1 - opencodex 2.65.0 on macOS; both
KIRO_CLIandAI_EDITORrequest shapes receivedmeteringEvent - Related prior art in this repo: [Bug]: Account pool routing destroys prompt cache and triggers 10x-50x token burn death-spiral above 80% usage threshold #4546 (unreported cache counter kept as unknown), devlog 142 (kiro token-usage heuristics), devlog 143 phase 160 (estimated usage tagging)
Activity
Smartnewb commentedon Sep 26, 2026
Follow-up evidence from live probing (same free-tier account, today). Three things that sharpen the picture:
1. Server-side prompt caching demonstrably exists — it's just invisible
Same ~4KB prefix re-sent seconds apart,
glm-5,runtime.us-east-1.kiro.dev:The cold→warm→cold→warm pattern by prefix content (not request order — B1 was 4th and still cold) shows a real server-side prefix cache. Credits are charged in full either way — caching affects latency, not billing. So the practical signal pair is: credits identical + large TTFT drop = cache hit, which an operator could only notice if the credit field is captured at all.
2. meteringEvent scales with input size — it's a real usage signal, not a flat fee
0.0319–0.0458credits0.0548credits0.0096creditsModel and size dependent → worth recording as the per-request cost field.
3. kiro-cli's own v3 engine shows what richer usage looks like
kiro-cli chat --v3 --output-format stream-jsonruns a local KAS (Kiro Agent Server) and emitssession_info_updatenotifications carrying:{"contextUsage":{"usagePercentage":1.97, "breakdown":{"tools":{"tokens":5122,"percent":0.5}, "yourPrompts":{"tokens":4100,"percent":0.4}, "contextFiles":{"tokens":0},"kiroResponses":{"tokens":0}, "sessionFiles":{"tokens":0}}}, "promptTurnSummaries":[{"unit":"credit","usage":0.0624}],"requestIds":["..."]}Per-category token counts here are computed by the local agent server (it tokenizes the context it assembles) — not upstream-reported — but it's proof the information is obtainable client-side. Meanwhile the wire stream's
metadataEvent.tokenUsageexists in the schema yet was absent from every frame we observed; kiro-cli's TUI nonetheless hascachedReadTokens/cachedWriteTokensfields in its/usagepanel, so the upstream can populate it under some conditions (see also kirodotdev/Kiro#9992: ACP only emits credits since kiro-cli 2.10).Independent implementation cross-check:
pi-provider-kirodeclares 12 event keys (assistantResponseEvent,codeReferenceEvent,contextUsageEvent,documentCitationEvent,error,metadataEvent,meteringEvent,reasoningContentEvent,serviceUnavailableError,throttlingError,toolResultEvent,toolUseEvent,validationError) — vs the 7 inKNOWN_EVENT_TYPES.0a00/Kiro-Go-Plusadditionally huntstokenUsage/usage/tokenMetricsenvelopes recursively inside any frame, preservingcacheRead/cacheCreation5m/1hsplits when present.Net ask stands: capture
meteringEvent(and any usage-bearing envelope) into the request log — it is the only authoritative per-request usage the wire actually sends today, and it also makes server-side cache hits indirectly observable via the credits-vs-TTFT pattern.lidge-jun commentedon Sep 26, 2026
Fixed on
devby #5951, carried in bug-PR merge train batch 9B, #5985 (merge bf04176). KirometeringEventframes are now parsed, the latest credit reading is kept for the turn, and it is written to the usage ledger. Closing; please reopen if a build that includes bf04176 still drops the credits.