feat(providers): add open-design provider#559
Open
ozymandiashh wants to merge 1 commit into
Open
Conversation
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.
Closes #558.
What this adds
A new
open-designprovider 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:
Each line is
{ id, event, data, timestamp }(timestampis epoch milliseconds). Relevant events:start->data.modelseeds the run's model.agent/data.type: "status"->data.modelupdates 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
namespaces/*/data/runs/*/events.jsonlfor Open Design / Code variants on macOS, Linux, and Windows, with aCODEBURN_OPEN_DESIGN_DIRoverride used by the tests.startandstatusevents, and emits oneParsedProviderCallperusageevent attributed to the model that was active at that point. This yields correct per-model attribution even when a single run mixes models.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.BUILTIN_ALIASESentry'openai-codex:gpt-5.5' -> 'gpt-5.5'(glm-5.2already resolves in the snapshot).Two correctness decisions worth calling out
total_tokens == input_tokens + output_tokens, andcached_read_tokensis a subset ofinput_tokens. So the provider pricesmax(0, input_tokens - cached_read_tokens)as uncached input pluscached_read_tokensas cache-read, exactly the normalizationsrc/providers/codex.tsalready does. Charging the fullinput_tokenspluscached_read_tokenswould double-bill the cached portion.timestampis 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
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 withinput>cachedis 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.tspasses (21 tests).npm testis green except the pre-existing locale-dependenttests/overview.test.tsassertion.npx tsc --noEmitis clean.pnpm/npx tsupbuild succeeds.codeburn overview --provider open-designreports per-model spend with the correct uncached-input and cache-read split.Files
src/providers/open-design.ts(new)src/providers/index.ts(register incoreProviders)src/models.ts(one alias:openai-codex:gpt-5.5->gpt-5.5)tests/provider-registry.test.ts(addopen-designto the expected provider list)tests/providers/open-design.test.ts+tests/fixtures/open-design/**(new)