Commit graph

16 commits

Author SHA1 Message Date
Bryan Helmkamp
3e157d3356
Format the Petri test fixtures after the engine key removal
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 10:54:45 -04:00
Bryan Helmkamp
a36bea15d2
Remove the engine flag: every run is a Petri run
Delete `Engine`, `RunEngine`, `[workflow] engine`, `[server.execution]
engine`, `FABRO_SERVER_ENGINE` and `fabro server start --engine`. The run
spec records what Petri admitted as `admission: PetriAdmission`; the
create handler always admits through `Runtime::check`; `execute_run`
always launches the Petri worker (or executes in process under the test
override); the CLI runner takes only the Petri worker path, and its
legacy control arm, artifact uploader, signal pause handlers and
credential helpers go with it. The CLI's `attach` and `events` read the
run stream only.

Two gaps this surfaced are closed here: the check adapter binds the
server's run variables as Petri compile variables (`{{ vars.* }}` in a
prompt no longer fails admission), and deleting a run removes its Petri
records, lease, platform records, projection and stream.

Tests: the config engine tests are replaced (an engine key is unknown),
the API round-trip test covers `PetriAdmission`, the server and CLI
Petri scenarios drop their engine settings, and the API tests that read
legacy event names now read the run stream or the session events. The
remaining red tests are fixtures and scenarios of the legacy executor
and the legacy event store (`fabro-store` `slate` and `run_state`,
`fabro-types` legacy `run.created` JSON, the server's handler-registry
scenarios, the CLI dry-run snapshots), which the next steps of the F4.3
series delete or port.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 09:58:21 -04:00
Bryan Helmkamp
ef86ad278a
Carry usage as lithos-llm's Usage and rename billing to usage
Re-pin lithos-llm to 55add4596b861a0623d00c3a54aa5c147c8d504b and
pebble to c91810fe51aece80359b9cd8efea971af0c46925, where token usage
and cost travel together as Usage { tokens: TokenCounts, cost:
Option<Cost> }. Fabro now carries that one type everywhere it used to
carry BilledTokenCounts, BilledModelUsage, UsdMicros, or a token count
beside a cost_usd_micros.

fabro-types: billing.rs is usage.rs with ModelRef, ModelUsage { model,
usage }, sum_usage, and usage_is_empty; billing_rollup.rs is
usage_rollup.rs with ProjectionUsageStage, ProjectionUsageByModel,
ProjectionUsageRollup, and usage_rollup_from_projection. Every usage
field is named usage: StageProjection.usage and usage_by_model,
Outcome<Option<ModelUsage>>, stage.completed and stage.failed usage and
usage_by_model, prompt.completed usage, run.completed and run.failed
usage (total_usd_micros is gone), Conclusion.usage, StageSummary.usage,
Run.usage. RunSize buckets by Cost.

fabro-workflow: model_usage_from_llm prices tokens from the catalog with
a Catalog cost source, with_reported_cost keeps a provider cost, and the
pebble handler's stage_usage groups pebble's accounts by model and sums
rows with Usage::saturating_add, so a total has a cost only when every
priced part was priced. The store fold's live usage is the agent's
usage plus its descendants'.

API: the OpenAPI spec deletes BilledTokenCounts, BilledModelUsage,
CompletionUsage, CompletionCost, TokenUsage, and RunBillingSummary,
adds TokenCounts, Cost, Usage, and ModelUsage, and renames every
billing schema, property, tag, path, and operation to usage. fabro-api
reuses lithos-llm's and fabro-types' types through with_replacement,
with a round-trip test per replacement.

Old stored runs get no migration: their pebble events in the old shape
read back with zero usage, and their rebuilt projections lose agent
usage.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 12:31:34 -06:00
Bryan Helmkamp
2e8d6b8a3d
Merge origin/main into the sandbox-driver adoption
Both sides rewrote the same crates. This branch replaced fabro's sandbox
layer with the sandbox driver: one RunSandbox, no Sandbox trait, driver
events consumed directly, MockSandbox over the driver's doubles. Main
replaced fabro's LLM layer with lithos-llm: fabro-model deleted, the
catalog and provider ids from lithos, credentials through the lithos
CredentialProvider, clients built with build_client.

Every conflict was one of those two renames meeting in an import list or
a signature, so the rule was mechanical: sandbox names resolve to this
branch, LLM names to main. Where main's newer code still used the old
sandbox API — new session tests over Arc::new(MockSandbox), the SDK
example's LocalSandbox, test fakes typed as Arc<dyn Sandbox> — it is
ported to RunSandbox and the mock helper. Where this branch still used
fabro-model or Client::from_source, main's replacement stands. One
combined future in the CLI runner crossed clippy's size budget and is
boxed at its call.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 13:37:11 -06:00
Bryan Helmkamp
619cb44e3c
Import lithos-llm types directly instead of through fabro-types
fabro-types no longer re-exports the lithos catalog and request types
(ProviderId, ModelId, ModelHandle, Message, ContentPart, TokenCounts,
Cost, Speed, ReasoningEffort, ReasoningOutput, and the rest). Every
crate that uses them depends on lithos-llm and names them there, and
the fabro-api progenitor replacements point at the lithos paths.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 10:03:08 -06:00
Bryan Helmkamp
fa3e485c95
Name built-in providers through lithos catalog::builtin
lithos-llm now ships the built-in provider ids and constructors, so
fabro-types drops its provider_ids module and every caller uses
lithos_llm::catalog::builtin directly. The crates that name a provider
now depend on lithos-llm themselves.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 09:48:37 -06:00
Bryan Helmkamp
3a998196ff
Answer catalog questions with the lithos catalog queries
fabro-llm's catalog module held some 250 lines of listing and picking
helpers over lithos data: enabled and listed providers, model lookup by
id, alias, or wire id, matches ranked as the resolver ranks, default and
probe models, the small utility model across ready providers, the nearest
model on another provider, and cost by handle. lithos-llm now answers all
of those on `Catalog` and `CatalogProvider` through `Offering`, so the
helpers and the `ModelEntry` wrapper go.

What stays in Fabro's catalog module is its own: building the catalog from
the operator overlay, and reading the agent harness and
`reasoning_by_default` from the shared `metadata.agent` namespace. The
passthrough selection policy in `selection.rs` keeps its rules and calls
lithos for the lookups.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 09:26:40 -06:00
Bryan Helmkamp
2a2fc41807
Read catalog policy from lithos core fields and metadata.agent
Fabro's policy layer restated the lithos built-ins under `metadata.fabro`:
enabled flags, credentials, display facts, probe and small-default roles,
and agent profiles. lithos-llm now carries every one of those as a core
field or under the shared `metadata.agent` namespace, so the layer and its
typed view go:

- Delete `fabro-policy.toml` and `FABRO_POLICY_TOML`. The catalog is the
  lithos built-ins plus the operator's `[llm]` overlay, nothing between.
- Delete `fabro_types::catalog_policy`. `enabled`, `stands_in_for`,
  `api_key_url`, `family`, the cutoffs, `estimated_output_tps`,
  `small_default`, and `probe` are read from lithos accessors; the agent
  profile and `reasoning_by_default` come from `metadata.agent`, which
  Pebble reads too.
- `catalog::provider`, `enabled_providers`, and `listed_providers` return
  the lithos `CatalogProvider` directly; `ModelEntry` loses its policy
  field and gains `agent_profile()`.
- Test fixtures move `[providers.x.metadata.fabro] enabled = true` onto
  the provider table, drop `credentials` lists in favor of the secret name
  lithos derives from the provider id, and spell `agent_profile` as
  `metadata.agent.profile`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 23:20:12 -06:00
Bryan Helmkamp
28d4242df0
Route Daytona sandboxes through the sandbox driver
The `daytona` provider kind now maps onto the sandbox-driver Daytona
provider instead of fabro's own SDK client. Fabro keeps what is its own:
the HMAC-named snapshot built from the environment's image or Dockerfile,
the explicit 120 minute auto-stop default, the managed labels that gate
destructive operations, the clone decision and layout, and push
credentials. The driver creates the sandbox, clones natively, and serves
exec, files, search, terminal, SSH, preview, and VNC through its facets.

- `daytona.rs` builds the driver `SandboxSpec` (snapshot source,
  `/home/daytona/workspace`, labels, timers, network policy, run name),
  ensures the snapshot through the driver `SnapshotProvider`, attaches by
  persisted id with fabro's label guard, and probes credentials through
  the provider health check under fabro's 20 second budget.
- `DriverSandbox` gains a create plan that settles the spec right before
  the provider call, records the snapshot a sandbox came from, and
  reports the provider console URL on `Ready`.
- Terminals use the driver `Pty` facet; the server's SSH, preview, and
  VNC endpoints use the `SshAccess`, `PreviewUrls`, and `Vnc` facets
  through the driver-typed reconnect. The preview endpoint now answers
  for every provider with a preview facet, so the local sandbox returns
  its loopback URL.
- Daytona credentials travel as `DaytonaCredentials` built from the
  vault key plus configured URL and organization; nothing reads the
  process environment implicitly. The inventory registry uses the shared
  `DriverInventoryProvider`.
- The SDK-based `daytona/mod.rs`, `provider/daytona.rs`, the Daytona
  terminal, the `daytona` cargo feature, and the direct daytona-sdk,
  git2 (in fabro-sandbox), tungstenite, and rustls dependencies are
  gone. The live Daytona tests run against the driver-backed sandbox.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 19:14:13 -06:00
Bryan Helmkamp
75e5f34c0d
Expose lithos request and response shapes through the API, server, CLI, and web
The OpenAPI spec adopts the lithos request, response, content part,
tool, usage, and cost schemas. The completions endpoint returns the
lithos `Response` JSON verbatim and SSE carries lithos `StreamEvent`s
verbatim. The models and providers endpoints serve the fabro-types
catalog views, and the install and model-test flows probe providers
through fabro-llm.

The CLI builds its catalog from the operator overlay, drives `fabro exec`
through the server gateway adapter, and parses reasoning effort with the
shared controls. The web app reads content parts as lithos-tagged
objects. The TypeScript client is regenerated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 17:26:57 -06:00
Bryan Helmkamp
24f9ac6bd1
refactor(model): rename Kimi provider to Moonshot 2026-07-31 09:00:52 -04:00
Bryan Helmkamp
9d828a8688
Merge remote-tracking branch 'origin/main' into refactor/remove-env-interpolation
# Conflicts:
#	lib/components/fabro-workflow/src/pipeline/pull_request.rs
2026-07-28 17:44:03 -04:00
Bryan Helmkamp
04c931e9d3
Simplify edge-only node validation 2026-07-28 14:14:32 -04:00
Bryan Helmkamp
e54fef760a
refactor(auth): remove EnvCredentialSource and make the run vault required
`EnvCredentialSource` resolved provider credentials from the process
environment. It had no production entry point of its own — it was only
ever reached as the `None` arm of an `Option<Vault>` in three places:
`build_llm_source`, `configured_providers_for_start`, and
`configured_providers_from_process_env`.

That optional vault is not a state the product can be in. Every run has a
server behind it, the server always spawns workers with `--storage-dir`
(`worker_runtime.rs`), and `SqlVaultCredentialSource` backs both the
server and the CLI. So the fallback only served to silently degrade
credential resolution to whatever the worker process happened to have in
its environment.

Make the vault required across the run path — `RunOptions`,
`StartServices`, `build_llm_source`, `tool_secrets_from_configured_sources`,
`vault_token_lookup`, and the CLI GitHub helpers — so the invariant is
enforced by types rather than assumed. A worker spawned without
`--storage-dir` now fails with a clear message instead of quietly
continuing without a vault.

`configured_providers_from_process_env` had no callers at all and is
deleted. `AgentApiBackend::new_from_env` was public but only ever called
from its own tests; it is deleted too.

Test-only credential sources move to a feature-gated
`fabro_auth::test_support`, wired through dev-dependencies so they never
link into production builds. The CLI worker tests now pass
`--storage-dir`, matching what the server actually does.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 20:36:54 -04:00
Bryan Helmkamp
c501c67185
Show each diagnostic's suggested fix in CLI output
Diagnostics have carried a `fix` field all along, but the CLI renderer
never printed it — the suggestion was only reachable through --json. The
actionable half of every validation failure was invisible to the person
running the command.

print_diagnostics now emits the fix as a dim-labelled continuation line
under any diagnostic that has one, at both error and warning severity.
Gating it behind --verbose would defeat the point, and printing it only
for errors would read as "this warning has no fix" — the warning
suggestions are useful on their own. Diagnostics that set no fix simply
omit the line.

The severity match moved into print_diagnostic so the fix line is
appended once in the loop rather than copied into all five arms; the
rest of the diff is reindentation.

print_diagnostics is shared by validate, preflight, graph, exec, and
dry-run, so this covers all five. Eleven inline snapshots across four
files gain a fix line; every change is additive.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 14:06:31 -04:00
Scott Werner
47bc772f7b refactor: organize crates into three layers 2026-07-23 17:59:34 -04:00