Skip to content

feat(providers): add open-design provider#559

Open
ozymandiashh wants to merge 1 commit into
getagentseal:mainfrom
ozymandiashh:pr/open-design-provider
Open

feat(providers): add open-design provider#559
ozymandiashh wants to merge 1 commit into
getagentseal:mainfrom
ozymandiashh:pr/open-design-provider

Conversation

@ozymandiashh

Copy link
Copy Markdown
Contributor

Closes #558.

What this adds

A new open-design provider that makes Open Design usage visible in codeburn, broken down per model. Open Design is a local-first AI design tool that orchestrates coding-agent CLIs (Codex, Hermes, Cursor, OpenCode, Copilot, and others) to turn prompts into design artifacts. It spends real tokens, but until now that spend was invisible to codeburn.

Why it was invisible

Open Design does not write the underlying CLIs' session stores (it does not, for example, write to ~/.codex/sessions). It keeps its own per-run event log instead, so none of the existing providers pick it up, even when the run is driven by a model codeburn already prices.

On-disk format (verified on real data, 26 runs)

One JSONL event log per run:

~/Library/Application Support/Open Design/namespaces/<ns>/data/runs/<run-uuid>/events.jsonl   # macOS
~/.config/Open Design/namespaces/<ns>/data/runs/<run-uuid>/events.jsonl                       # Linux
%APPDATA%/Open Design/namespaces/<ns>/data/runs/<run-uuid>/events.jsonl                        # Windows

Each line is { id, event, data, timestamp } (timestamp is epoch milliseconds). Relevant events:

  • start -> data.model seeds the run's model.
  • agent / data.type: "status" -> data.model updates the current model (a run can switch backends).
  • agent / data.type: "usage" -> data.usage = { input_tokens, output_tokens, cached_read_tokens, thought_tokens, total_tokens }. The usage event has no model, so it is attributed to the last-seen model.

How the provider works

  • Discovery: globs namespaces/*/data/runs/*/events.jsonl for Open Design / Code variants on macOS, Linux, and Windows, with a CODEBURN_OPEN_DESIGN_DIR override used by the tests.
  • Model correlation: streams each run, tracking the active model from start and status events, and emits one ParsedProviderCall per usage event attributed to the model that was active at that point. This yields correct per-model attribution even when a single run mixes models.
  • Token mapping: input_tokens, output_tokens, cached_read_tokens -> cache-read, thought_tokens -> reasoning. Dedup is per (run, event id) so re-parsing a file does not double-count.
  • Pricing: computes cost from tokens via the existing engine; adds a single BUILTIN_ALIASES entry 'openai-codex:gpt-5.5' -> 'gpt-5.5' (glm-5.2 already resolves in the snapshot).

Two correctness decisions worth calling out

  1. Cache-read is subtracted from input before pricing. Verified from the raw data: total_tokens == input_tokens + output_tokens, and cached_read_tokens is a subset of input_tokens. So the provider prices max(0, input_tokens - cached_read_tokens) as uncached input plus cached_read_tokens as cache-read, exactly the normalization src/providers/codex.ts already does. Charging the full input_tokens plus cached_read_tokens would double-bill the cached portion.
  2. Numeric epoch timestamps are converted to ISO. Open Design's timestamp is a number (epoch ms), and an empty timestamp would be dropped by codeburn's date-scoped parsing. The provider converts finite numeric timestamps to ISO strings (and still accepts string timestamps), so usage lands in the correct date range.

Coverage and limits

Backends that emit a usage frame (in my data: glm-5.2, openai-codex:gpt-5.5) are fully accounted with a per-field token breakdown. Aborted runs and CLIs that do not report usage have no token data on disk and are left out rather than guessed, which is a limit of the upstream CLI, not the provider.

Verification

  • New tests/providers/open-design.test.ts (fixture-based): a mixed-model run yields two calls with the right model each and correct per-field tokens; a no-usage run yields nothing; the start-seeded model is used before any status transition; a usage event with input>cached is priced on uncached input (cache-read is not double-charged); a numeric epoch timestamp produces a non-empty ISO timestamp and is included in a date-scoped parse.
  • npx vitest run tests/providers/open-design.test.ts tests/provider-registry.test.ts passes (21 tests). npm test is green except the pre-existing locale-dependent tests/overview.test.ts assertion. npx tsc --noEmit is clean. pnpm/npx tsup build succeeds.
  • End to end on real Open Design history: codeburn overview --provider open-design reports per-model spend with the correct uncached-input and cache-read split.

Files

  • src/providers/open-design.ts (new)
  • src/providers/index.ts (register in coreProviders)
  • src/models.ts (one alias: openai-codex:gpt-5.5 -> gpt-5.5)
  • tests/provider-registry.test.ts (add open-design to the expected provider list)
  • tests/providers/open-design.test.ts + tests/fixtures/open-design/** (new)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add an Open Design provider (per-model usage from its local event logs)

1 participant