feat(pricing): add machine-wide pricing overrides via ~/.conductor/pricing.yaml#173
Open
PolyphonyRequiem wants to merge 1 commit into
Open
Conversation
f47d86f to
2afa98f
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #173 +/- ##
=======================================
Coverage ? 86.63%
=======================================
Files ? 62
Lines ? 8983
Branches ? 0
=======================================
Hits ? 7782
Misses ? 1201
Partials ? 0 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
2afa98f to
2d79029
Compare
…icing.yaml ## Problem Workflow-level `runtime.cost.pricing` is per-workflow. If a model isn't in the built-in pricing table (`engine/pricing.py:DEFAULT_PRICING`), every workflow that uses it either reports $0 silently or fuzzy-matches a coarser ancestor and reports plausible-but-wrong numbers. There's no shared place to put pricing for models that haven't shipped to the default table yet (the `claude-opus-4.7-*` family, `gpt-5.3` / `5.4` / `5.5`, etc.). ## Solution A machine-wide pricing file at `~/.conductor/pricing.yaml`, with `CONDUCTOR_PRICING_FILE` as an env-var override (with `~` expansion). The file uses the same `PricingOverride` schema as `runtime.cost.pricing`. Precedence (highest wins): 1. Exact match in workflow `runtime.cost.pricing` 2. Exact match in user `~/.conductor/pricing.yaml` 3. Exact match in built-in `DEFAULT_PRICING` 4. Fuzzy (versioned-suffix) match in built-in `DEFAULT_PRICING` Override entries are exact-match only — list each concrete model name. The existing built-in fuzzy match (microsoft#143) is unchanged. `conductor pricing path` prints the resolved file location (honors the env var). ## Failure modes - **Missing file**: silent no-op. Workflows that don't need overrides aren't affected. - **Malformed file**: hard error at engine construction with a pointer to the file path and the bypass instruction `CONDUCTOR_PRICING_FILE=/dev/null` in the error message itself. Silent acceptance of corrupted overrides was the original bug we're solving for. The loader rejects non-mapping `pricing:` values (e.g. `pricing: true`, `pricing: []`) and non-string model keys with clear `ConfigurationError` messages, rather than crashing later with `AttributeError`. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2d79029 to
4210599
Compare
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.
Problem
Workflow-level
runtime.cost.pricingis per-workflow. If a model isn't in the built-in pricing table, every workflow that uses it either reports $0 silently or fuzzy-matches a coarser ancestor and reports plausible-but-wrong numbers. No shared place exists for pricing on models not yet inDEFAULT_PRICING(theclaude-opus-4.7-*family,gpt-5.3/5.4/5.5, etc.).Solution
A machine-wide pricing file at
~/.conductor/pricing.yaml, withCONDUCTOR_PRICING_FILEas env-var override (with~expansion). The file uses the samePricingOverrideschema asruntime.cost.pricing.Precedence (highest wins):
runtime.cost.pricing~/.conductor/pricing.yamlDEFAULT_PRICINGDEFAULT_PRICINGOverride entries are exact-match only — list each concrete model name (e.g.
claude-opus-4-20250514, not justclaude-opus-4). Keeps the surface narrow; the existing built-in fuzzy match from #143 is unchanged.One CLI command:
conductor pricing pathprints the resolved file location.Failure modes
CONDUCTOR_PRICING_FILE=/dev/nullbypass in the error message itself.pricing:value or non-string model key: clearConfigurationErrorinstead of crashing later withAttributeError.Diff size
~578 net new lines:
config/user_pricing.py(+112) — loader:~expansion, env-var, missing→empty, malformed→error, value/key validationengine/workflow.py(+50/-10) — layering in_build_pricing_overridescli/pricing.py(+28) — singlepathsubcommandtest_user_pricing.py(+195),test_pricing_layering.py(+97),test_pricing_cmd.py(+46)57 new tests pass; lint/format/typecheck clean.
Try it
History
init/showtemplate/table),extra="forbid"schema hardening, override-side fuzzy match,UserPricingFilePydantic wrapper,$VARexpansion.path. Schema hardening split out.UserPricingFileand$VARdropped. Override-side fuzzy initially kept, then dropped in v3 to keep the surface lean — users list concrete model names; built-in fuzzy is unchanged.pricing: true,pricing: [], non-string keys). Error message escape hatch surfaced.Draft for maintainer review.