fix(inspect): tolerate price tiers and cells with no when gate - #4
Tomauskasz wants to merge 1 commit into
Conversation
`formatInspectResult` called `Object.entries()` directly on `PriceTier.when`
and `PriceVariant.when`. The wire omits `when` on an ungated tier — one that
always applies and is metered by its `selector` alone — so the call threw
"Cannot convert undefined or null to object" and aborted the entire render.
exa `/search` ships exactly that shape today: a TIERED card whose sole tier
charges per result above 10 with no `when`. `monid inspect -p exa -e /search`
died right after printing the base price:
Pricing
Type: TIERED
Amount: from $0.01/call
Base: $0.01 (always)
monid: error: Cannot convert undefined or null to object
The endpoint schema, docs, and hints were all lost, and the exit path made it
look as though the endpoint itself was unavailable. `--json`, `discover`, and
`run` were unaffected.
Route both render sites through one `formatPriceWhen()` helper that treats a
missing gate as empty, and drop the clause when there is nothing to gate on,
so an ungated tier prints as `+ Results above 10: $0.001 / result` instead of
a dangling `when`. Mark `when` optional on `PriceTier` and `PriceVariant`: the
types claimed it was always present, which is what let the crash through.
Signed-off-by: Tomas <180413002+Tomauskasz@users.noreply.github.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (3)
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthroughPrice variants and tiers now support omitted ChangesPrice gate rendering
Merge Risk: ⚪ Minimal · up to Inspection output now renders pricing entries that omit optional gate conditions without crashing or leaving dangling gate text. The relevant rendering behavior is covered, with no remaining merge-readiness risk identified. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Problem
monid inspectcrashes on any endpoint whose price card carries an ungated tier — a tier with nowhenon the wire, which always applies and is metered by itsselectoralone.formatInspectResultcallsObject.entries()directly onPriceTier.whenandPriceVariant.when. When the key is absent, that throwsCannot convert undefined or null to objectand aborts the whole render.exa
/searchships exactly that shape today (0.1.7, and0.1.7-dev.20260905010537):Everything after the base price is lost — input schema, docs URL, and the
runhints. The failure reads like the endpoint is unavailable rather than a formatting bug, so the natural next step is to go looking for a different provider.--json,discover, andrunare all unaffected; only the human-readable render dies.The card the backend actually returns for
exa/search:{ "type": "TIERED", "default": { "type": "PER_CALL", "amount": { "value": 0.01, "currency": "USD" } }, "tiers": [ { "label": "Results above 10", "selector": { "label": "Results above 10", "key": "numResults", "in": "body", "offset": 10 }, "price": { "type": "PER_RESULT", "amount": { "value": 0.001, "currency": "USD" } } } ] }No
when— correctly so. The tier is not gated on a request value; it metersnumResultsabove an offset.Fix
formatPriceWhen()helper that treats a missing gate as empty.+ Results above 10: $0.001 / resultrather than a danglingwhen. Same for aPER_UNIT_MATRIXcell with no coordinates — no orphaned- :separator.whenoptional onPriceTierandPriceVariant. The types claimed it was always present, which is what let this through; the wire has never guaranteed it.This follows the existing convention in
types.tsof tolerating every shape the backend sends rather than trusting one. A malformed card should degrade a line, not kill the command.Tests
Three cases added to
test/output/price.test.ts, built from the real exa payload above:TIEREDtier renders instead of throwing;when deep=true(no regression);PER_UNIT_MATRIXvariant with nowhenrenders instead of throwing.The two "instead of throwing" tests fail on
mainwith the original error and pass with this change:Verified end to end against
api.monid.ai—monid inspect -p exa -e /searchnow renders the full card, schema, docs, and hints.Summary by CodeRabbit
Bug Fixes
Tests