- Return 400 (not 500) for WorkflowError::ModelReference from run
creation, matching ModelSelection: an ambiguous model/provider token
is user input, not a server fault.
- Gate fabro-workflow's test_support module behind
cfg(any(test, feature = "test-support")) so the feature actually
controls exposure, per the repo's test-support boundary guidance.
Add the self dev-dependency so tests/it keeps compiling, and gate
the pipeline helpers that only test_support consumed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tag every LLM request in a run with an x-session-id header carrying the
run ID, so gateways that understand session tracing (e.g. OpenRouter
broadcast) can group a run's requests into one session.
Adds ExtraHeadersCredentialSource to fabro-auth: a CredentialSource
decorator that appends fixed headers to every resolved credential,
leaving operator-configured extra_headers untouched. The run pipeline
wraps its vault/env source with it, so agent stages, prompt stages,
hooks, and PR-content generation all pick up the header through the
existing extra_headers plumbing with no fabro-llm changes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both this branch and the remote qa branch fixed the same provider-pin
regression; the merge stacked the two implementations. Keep the remote's
semantics: pin the run's provider whenever it offers the model, otherwise
fall back to priority selection.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- rename resolve_route catalog-instance test to describe its actual
id-based resolution assertion
- use EnvVars::OPENAI_API_KEY instead of a raw string in the automation
scheduler test fixture
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Merging main brought in billing tests that construct ModelRef with String
model ids and an integration test that pins an OpenRouter run via the
backend's provider id. The ModelRef sites now use ModelId conversions.
The integration test also exposed a real regression: resolve_provider_context
ignored the persisted run provider whenever the model selector resolved
globally, re-routing pinned OpenRouter runs to a higher-priority provider for
nodes without explicit model/provider attrs. Request-time routing now treats
the run's selected provider as a pin with custom-model passthrough, matching
transform-time selection semantics.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The brew_command helper inherits the developer's environment (unlike
context.command(), which env_clears), so an exported FORCE_COLOR or
CLICOLOR_FORCE overrides the NO_COLOR=1 the harness sets and the CLI
renders ANSI codes into snapshot output, failing
upgrade_brew_install_refuses_and_prints_brew_command and
upgrade_brew_install_rejects_version_flag on any machine with
FORCE_COLOR exported.
Remove FORCE_COLOR, CLICOLOR_FORCE, and CLICOLOR from the spawned
command's env, and add the FORCE_COLOR constant to EnvVars.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Consolidate duplicated resolution logic introduced by the provider-aware
model alias work:
- Add Catalog::resolve_selection (with SelectedModel and ready_provider)
as the single home for the select -> passthrough -> default-fallback
policy, replacing six hand-rolled copies across fabro-server,
fabro-workflow, and fabro-llm.
- Move legacy [models] row resolution into a shared LegacyModelIndex and
LegacyModelError in fabro-model; delete fabro-config's parallel
implementation and its LlmNormalizationError enum, plus the now-unused
builtin_* catalog helpers.
- Drop redundant client.resolve_request calls (and their full-request
clones) from the completions and playground handlers.
- Remove the redundant resolve_provider_context round-trip in
resolve_start_llm and make resolve_run_model return a ProviderId
instead of a never-None Option.
- Replace the "<default model>" sentinel selector with a dedicated
ModelSelectionError::NoDefaultModel variant.
- Add a CatalogRoute trait so provider adapters call
self.api_model_id(...) instead of threading catalog/provider args.
- Delete the unused FromStr impl for ModelId; dedupe the CLI's
id-or-alias predicate.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A branch node reachable from multiple parallel nodes previously had its
warning and fix hint name an arbitrary first parent. Collect all unique
parallel parents (sorted) and render the full list in both.
Addresses review feedback on #595.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add two lint rules so the graph format stops silently accepting
attributes that nothing reads:
- inert_attribute: handler-specific attributes (script, language,
duration, join_policy, max_parallel, output_schema, prompt) placed on
node types that never read them. Attributes read by several handlers
(timeout), resolved for every node (fidelity, retry_policy), or
injectable via model stylesheets (model, reasoning_effort, ...) are
deliberately excluded.
- parallel_branch_inert_attribute: fidelity/thread_id on parallel
branch nodes and fork->branch edges. Branch dispatch bypasses the
fidelity lifecycle, so these are dead letters today; the warning
points at the parallel node, where fidelity does take effect.
Also reconcile the loop_restart docs with actual executor behavior:
taking a loop_restart edge restarts from the target with a fresh empty
context (visit counts preserved), on success as well as failure; the
transient_infra guard applies only to failure crossings.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Assert ParallelBranchStarted seeds started_at (the live-timer half of
the fix) and cover the failed-status fold to a Failed terminal state.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the billed_model_usage_from_llm_with_cost wrapper with a
with_reported_cost method on BilledModelUsage and BilledTokenCounts, and
centralize the optional-cost fold as UsdMicros::accumulate so fabro-agent
and fabro-workflow share one implementation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add Poolside as a built-in OpenAI-compatible provider and expose Laguna S 2.1 and XS 2.1 both directly and through OpenRouter. Include vault/env credential registration, secret redaction, live coverage, catalog tests, and user documentation.