Repository navigation
Conversation
POST /api/playground/simulate-route read combo.targets, but getCombos() returns records normalized by normalizeComboRecord(), which is schema version 2 and keeps its steps under models as a ComboStep[]. There is no targets property, so the target loop dereferenced undefined.length and every persisted combo came back as HTTP 500. The inline body.combo branch worked only because the caller supplies targets explicitly, which is why the dashboard was the only broken path. A step's provider comes from step.providerId or the provider/model prefix of step.model, never from a top-level step.provider, so the connection lookup would have reported "Provider undefined not configured" even once targets existed. Both are handled here. combo-ref and provider-wildcard steps are not expanded by the simulator. They now surface as warnings instead of disappearing. The mapping lives in src/lib/combos/simulatorTargets.ts rather than in the route file, since a Next.js route module cannot export anything besides its handlers and the documented route config. Closes cheaper-inference#11822
|
Thanks for this — and sorry for the overlap. #11862 landed first and already fixed the Your one genuinely distinct contribution — surfacing |
… keep cheaper-inference#11862's string-step handling (cheaper-inference#11930) Ports the specific-warning improvement from cheaper-inference#11882 (combo-ref/provider-wildcard steps get their own message instead of a generic count) onto cheaper-inference#11862's already-merged crash fix. 4/4 focused tests passing.
Summary
POST /api/playground/simulate-routereturned HTTP 500 for every persisted combo, which made the Combo Playground page unusable. Every "Simulate Route" click failed, whichever combo was selected:{"error":"Simulation error: Cannot read properties of undefined (reading 'length')"}This is not the "combo not found" path. A bogus
comboIdcorrectly returns 404, so the combo is found and then the handler crashes while iterating its targets.The route read
combo.targets, butgetCombos()returns records normalized bynormalizeComboRecord(), which is schema version 2 and keeps its steps undermodelsas aComboStep[]. There is notargetsproperty, socomboInfo.targetswas alwaysundefinedand the loop below dereferencedundefined.length. The inlinebody.combobranch worked only because the caller suppliestargetsexplicitly persimulateRequestSchema, which is why the dashboard was the only broken path.There is a second mismatch in the same loop. A step's provider comes from
step.providerId, or from theprovider/modelprefix ofstep.model, never from a top-levelstep.provider. So even withtargetspopulated, the connection lookup would have failed to resolve and produced spuriousProvider undefined not configuredwarnings. Both are handled here.combo-refandprovider-wildcardsteps are not expanded by the simulator. Rather than dropping them silently they now surface as warnings, and the wildcard is listed unresolved so the operator can see it is in the route.Related Issues
Validation
npm run lintTests Added Or Updated
tests/unit/playground-simulate-route-combo-steps-11822.test.ts(new)Covers the three step kinds,
providerIdwinning over the model prefix, a serializedmodelscolumn, and the malformed inputs (null, unparseable JSON, junk entries) that should degrade to an empty target list rather than throw.Coverage Notes
The mapping lives in
src/lib/combos/simulatorTargets.tsand is fully covered by the new test file. The route itself keeps its existing shape and just calls into it.Reviewer Notes
I put the mapping in
src/lib/combos/rather than inline in the route, for two reasons. A Next.js App Router route module cannot export anything besides its handlers and the documented route config, so the helper would not have been testable where the issue suggested putting it. AndComboStepalready lives undersrc/lib/combos/, so the mapping sits next to the type it consumes.Routing itself was never affected. Real requests through these combos always dispatched correctly, this was only the simulator's view of them.
If you would rather have
combo-refsteps expanded throughresolveComboTargets()instead of surfacing as a warning, say so and I will do that instead. I went with the warning because expanding nested combos in the simulator raises cycle-handling questions that felt out of scope for a 500 fix.