Resolves conflicts with main's typed reasoning_effort field (#609) and
the usage-buckets test (#616). The handler's manual string parse is
superseded by serde-level validation of the typed enum, so it is
removed along with its test; the client-side unsupported-effort
validation and 400 error mapping from this branch are kept.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The fallback provider set was always catalog.all_provider_ids(), computed
at every call site and threaded through five layers alongside the catalog
itself. Fold it into Catalog::resolve_selection_with_catalog_fallback and
carry only a catalog_fallback flag through the transform/validate/
materialize entry points.
- materialize_run delegates to resolve_run_model again instead of
re-inlining its provider normalization and selection
- run_preflight derives ready providers from llm_result instead of
taking both, so callers cannot pass inconsistent pairs; the legacy
tests now exercise the production ready-first routing path
- AppState::resolve_llm_client_with_ready_ids replaces three copies of
resolve-then-extract-provider-ids, and ready_llm_provider_ids
delegates to it
- the unreachable "model resolution failed" preflight check becomes an
invariant error where the materialized run is produced
- validate_prepared_manifest_with_vars/_for_preflight share the
ValidateInput construction
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replaces the per-field if-let cascade in the structured completion path
with a single struct-update expression. The cascade had to be extended
by hand for every request field and silently dropped stop_sequences and
provider_options, which the non-structured path already forwarded.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Return InvalidRequest (400) for unsupported speed too, matching the
reasoning_effort check and the complete()/stream() doc comments
- Centralize fabro_llm::Error -> ApiError mapping in a From impl so the
completions handler, playground handler, and Error::Llm arm agree on
the InvalidRequest -> 400 / else -> 502 split
- Reject unparseable reasoning_effort values with 400 instead of
silently dropping them
- Add classify_sdk_invalid_request test per fabro-workflow convention
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Unify list_events_from with list_events_from_with_limit so projection
replay shares the seek path instead of duplicating the decode loop
- Bound the event scan with keys::run_events_range instead of an
unbounded range plus a manual prefix break, so slatedb never touches
SSTs belonging to other runs or namespaces
- Store reader event_seq as None instead of a valid-looking sentinel of
1, so appends through a reader-built inner fail as ReadOnly rather
than writing duplicate sequences
- Borrow keys during scans instead of allocating a String per entry,
drop a dead branch in cached_events_from, collapse recover_next_seq's
single-caller parameters, and document the zero-padded key ordering
invariant the seek depends on
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Extract emit_branch_completed() to replace three near-identical
ParallelBranchCompleted constructions; status now reads consistently
from outcome.status
- Add context_diff_public() so parallel.rs and manager_loop.rs share the
diff-minus-engine-internal-keys step; move context_diff tests next to
the function in context.rs
- Replace fan_in's dead BranchShape struct with the canonical
Vec<ParallelBranchResult> (from_value moves, so no payload cloning)
- Narrow parseParallelOverview to ParallelBranchSummary {id, status};
its only consumer renders just those fields
- Drop helpers.test.ts's duplicate envelope() fixture in favor of the
shared makeEventEnvelope
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The unknown-value rejection test duplicated strum coverage in
fabro-model and the HTTP 422 test in fabro-server. Keep only the
field-type assertion, using the same field-pinning idiom as
stage_model_usage_round_trip.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adapted from poolside's official favicon mark: monochrome
fill="currentColor" at 24x24 to match the other provider logos, with the
brand's gradient-fade tail preserved via the original alpha mask.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review follow-ups: the ParallelBranchResult snippet showed status as
String (it is StageOutcome), and the cancellation section implied a
cancelled branch status that the type does not have — cancelled-while-
waiting branches record a failed outcome (reason "branch cancelled")
and the handler returns Error::Cancelled to the run executor.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The merge of main kept two copies of testProviderCredentials in the
generated models-api.ts; regeneration is authoritative.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Cumulative implement + simplify_fable diff recovered from the run's meta
branch (fabro/meta/01KY7YH7RYCJ1BDVTTP96ZA4HV, stage 006 diff.patch).
The run validated this tree clean: cargo nextest (7,007 passed), clippy,
fmt, TS client regen + typecheck, web tests (679 passed), docs check.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Extract the quadruplicated watchdog check-and-clear logic in
schedule_worker_cancel_escalation into ManagedRun methods
(escalation_still_current, clear_escalation_for)
- Derive strum::IntoStaticStr for WorkerRef instead of a hand-written
variant-to-string match in kind()
- Use the generated AgentControlState constant instead of the raw
"waiting_for_steer" literal in run-detail.tsx
- Replace optimisticCancellationRunId state with a boolean; the
component is keyed by run id, so the stored id could only ever be
this run's own
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The crate reorganization renamed lib/crates/ to lib/apps|components|foundation/.
Git followed all modified files across the rename; the only conflict was the
newly added codec/cache.rs, now placed at lib/components/fabro-llm/src/codec/cache.rs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>