Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions docs/providers/kiro.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,30 @@ VS Code-style globalStorage at `kiro.kiroagent`:
|---|---|
| macOS | `~/Library/Application Support/Kiro/User/globalStorage/kiro.kiroagent` |
| Windows | `%APPDATA%/Kiro/User/globalStorage/kiro.kiroagent` |
| Linux | `~/.config/Kiro/User/globalStorage/kiro.kiroagent` |
| Linux | `~/.config/Kiro/User/globalStorage/kiro.kiroagent` and `~/.kiro-server/data/User/globalStorage/kiro.kiroagent` (remote dev boxes / Cloud Desktop) |

Sessions are under hash-named workspace subdirectories. Discovery keeps backward compatibility with legacy `.chat` files and also scans the post-February 2026 extensionless format:
On Linux both the local and remote-server globalStorage paths are scanned when present.

Two more stores live outside globalStorage, under `~/.kiro/sessions` (honors `KIRO_HOME`):

- **CLI store:** `~/.kiro/sessions/cli/<id>.jsonl` (+ companion `<id>.json`)
- **IDE v2 store:** `~/.kiro/sessions/<workspace-hash>/sess_<id>/` (see below)

Sessions in globalStorage are under hash-named workspace subdirectories. Discovery keeps backward compatibility with legacy `.chat` files and also scans the post-February 2026 extensionless format:

- `<workspace-hash>/<execution-id>.chat` legacy session files
- `<workspace-hash>/<session-hash>` extensionless session index files
- `<workspace-hash>/<session-hash>/<execution-hash>` extensionless execution files inside session directories
- `workspace-sessions/<base64url(path)>/<uuid>.json` v1 session records, a sibling of the workspace-hash directories at the `kiro.kiroagent` root (conversation spine; execution-backed stubs are skipped to avoid double-counting the execution files)

## Storage format

Kiro has two known JSON formats:
Kiro has several known formats across generations:

- Legacy `.chat` files with `{ chat, metadata, executionId }`
- Modern extensionless execution files with identifiers/timestamps at the top level plus conversation fields such as `messages`, `conversation`, `chat`, `transcript`, `entries`, `events`, or direct prompt/response fields
- **Legacy `.chat`** files with `{ chat, metadata, executionId }`
- **Modern extensionless execution files** with identifiers/timestamps at the top level plus conversation fields such as `messages`, `conversation`, `chat`, `transcript`, `entries`, `events`, `context.messages`, or direct prompt/response fields. In v1 these are the *content* half; the paired `workspace-sessions/<uuid>.json` record is the *spine* (linked by `executionId` ⇄ `chatSessionId`).
- **CLI** JSONL: one `{ version, kind, data }` event per line + a companion `<id>.json` with `session_state` metering (`metering_usage` gives real per-turn cost in credits).
- **IDE v2** (`sess_<id>/`): a self-contained, event-sourced session directory — `session.json` (metadata incl. the real `modelId`, `title`, `workspacePaths`) + `messages.jsonl` (append-only `{ id, timestamp, payload:{ type, ... } }` events) + `publish.cursor` + `snapshots/`. Assistant content is inline (no separate execution files). Usage is billed in **credits** via `usage_summary.promptTurnSummaries` (no token counts): cost comes from credits at the public overage rate ($0.04/credit, `USD_PER_KIRO_CREDIT`), while token counts are estimated from transcript text.

Session index files with `{ executions: [...] }` are discovered but skipped during parsing because they do not contain conversation content.

Expand All @@ -37,14 +47,18 @@ None.

## Deduplication

Modern files deduplicate per session/execution pair. Legacy `.chat` files deduplicate per workflow/execution pair.
Modern files deduplicate per session/execution pair. Legacy `.chat` files deduplicate per workflow/execution pair. CLI turns key on `kiro-cli:<sessionId>:<turnIndex>`. v2 turns key on `kiro-v2:<sessionId>:<executionId>`.

The stores are disjoint (v2 sessions use `sess_`-prefixed IDs in a separate directory), so no session is counted twice today. Migration from v1 workspace-sessions to v2 is currently detect-only; if it begins moving records, add a guard preferring v2 when the same logical session appears in both.

## Quirks

- **Workspace hash resolution** is non-trivial. The parser tries `workspace.json` first; if that fails, it base64-decodes the directory name to recover the workspace path.
- **Model ID normalization.** Kiro stores models like `claude-1.2`; the parser rewrites the dot to a hyphen so they match `claude-1-2` in the pricing snapshot. Add new versions here when Kiro ships them.
- **Tool name extraction accepts text and structured calls.** Kiro can embed tool calls inside message text as `<tool_use><name>...</name>` or expose structured `toolCalls` / `tool_calls` / `tools` entries.
- Token counts are estimated via char count (`CHARS_PER_TOKEN = 4`).
- **Credits are the cost source; tokens stay estimated.** Kiro bills in credits ($20/mo for 1,000; overage $0.04/credit). CLI (`metering_usage`), v1 executions (`usageSummary[].usage`), and v2 (`usage_summary.promptTurnSummaries[].usage`) turns record real credits, converted to USD at `USD_PER_KIRO_CREDIT = 0.04` (the public overage rate — the same never-understate approach as Codebuff). Turns without credit data fall back to token-estimated cost (`costIsEstimated: true`); legacy `.chat` and workspace-session records carry no usage data, so they are always token-estimated. Note: an earlier CLI implementation summed credit values directly as dollars, overstating cost 25×. Token *counts* remain char-estimated everywhere (input undercounts: only visible transcript text is seen, not the full resent context; v2's `session_metadata.contextUsage.usagePercentage` × context window is a better input proxy if ever needed). v2 does keep the real `modelId`, so unlike the v1 execution-file path it is not mislabeled `kiro-auto`.
- **Cost is frozen at parse time.** Kiro is on the `costUSD` pass-through allowlist in `providerCallToCachedCall` (alongside mistral-vibe, devin, hermes, …), so its credit-based cost survives the session cache instead of being re-priced from estimated tokens — token re-pricing understated/overstated real kiro spend by up to 16× per model. The tradeoff, shared with all allowlisted providers: `codeburn price-override` and `model-alias` do not affect kiro dollar amounts (token *counts* are unaffected). Historical caches from before this change re-parse via the `CACHE_VERSION` bump to 5.

## When fixing a bug here

Expand Down
15 changes: 10 additions & 5 deletions src/daily-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,23 @@ import { homedir } from 'os'
import { join } from 'path'
import type { DateRange, ProjectSummary } from './types.js'

// Bumped to 10: cursor accounting changed (real composer context tokens on
// Bumped to 11: kiro cost accounting changed (metered credits pass through
// the session cache instead of being re-priced from estimated tokens), so
// days finalized at v10 carry token-estimated kiro costs that were off by up
// to 16× per model. Raising MIN_SUPPORTED_VERSION forces the one-time full
// re-hydration that backfills history under credit-based pricing.
//
// v10: cursor accounting changed (real composer context tokens on
// conversation-anchored records, Cursor-published composer pricing), so days
// finalized at v9 carry the old double-counted agentKv estimates and
// sonnet-proxy composer costs. Raising MIN_SUPPORTED_VERSION forces the
// one-time full re-hydration that backfills history under the new accounting.
// sonnet-proxy composer costs.
//
// v9: providers added since the v8 rollup (Grok, Hermes, ZCode) parse usage
// that older binaries skipped. v8 added local-model savings to the daily
// rollup; the `savingsConfigHash` field is invalidated separately when the
// user changes their `localModelSavings` mapping.
export const DAILY_CACHE_VERSION = 10
const MIN_SUPPORTED_VERSION = 10
export const DAILY_CACHE_VERSION = 11
const MIN_SUPPORTED_VERSION = 11
const DAILY_CACHE_FILENAME = 'daily-cache.json'

export type DailyEntry = {
Expand Down
2 changes: 1 addition & 1 deletion src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1754,7 +1754,7 @@ function providerCallToCachedCall(call: ParsedProviderCall): CachedCall {
webSearchRequests: call.webSearchRequests,
cacheCreationOneHourTokens: 0,
},
costUSD: (call.provider === 'mistral-vibe' || call.provider === 'antigravity' || call.provider === 'devin' || call.provider === 'vercel-gateway' || call.provider === 'hermes') ? call.costUSD : undefined,
costUSD: (call.provider === 'mistral-vibe' || call.provider === 'antigravity' || call.provider === 'devin' || call.provider === 'vercel-gateway' || call.provider === 'hermes' || call.provider === 'kiro') ? call.costUSD : undefined,
speed: call.speed,
timestamp: call.timestamp,
tools: call.tools,
Expand Down
Loading
Loading