mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-11 22:53:00 +00:00
fabro-auth defined its own `CredentialSource` trait beside the lithos `CredentialProvider`, with a parallel `ResolveError` and an adapter between them, because lithos had no way to ask which providers a store can serve right now. It does now: `credentials::readiness`, `ClientBuilder::build_ready`, and `CredentialError::Unusable`. - The vault, SQL vault, API-key, and extra-headers stores implement `CredentialProvider` directly. Material that is present but unusable (an expired token with no refresh, a wrong-typed vault entry, a header secret that did not resolve, a store read failure) is `CredentialError::Unusable` with the operator-facing reason; its `Display` replaces `auth_issue_message`. `is_configured` is the cheap presence check. - `fabro_llm::build_client` calls `build_ready`; `FabroClient::auth_issues` carries `CredentialError`. `fabro_llm::configured_providers` replaces the per-store `configured_providers` method. - `CredentialSource`, `ResolvedCredentials`, `lithos_credentials`, `ResolveError`, and `auth_issue_message` are deleted. Twenty files that held `Arc<dyn CredentialSource>` hold `Arc<dyn CredentialProvider>`. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
34 lines
2.4 KiB
Markdown
34 lines
2.4 KiB
Markdown
# LLM Client Resolution
|
|
|
|
This document defines how Fabro resolves LLM credentials and constructs `fabro-llm` clients.
|
|
|
|
## Core Rules
|
|
|
|
- The lithos `CredentialProvider` trait is the credential authority; Fabro's vault, SQL secret store, and API-key stores implement it directly.
|
|
- Long-lived runtime contexts store `Arc<dyn CredentialProvider>` and `Arc<Catalog>`, not `Client`.
|
|
- Call `fabro_llm::client::Client::from_source(&source, catalog).await?` at the point of use.
|
|
- Standalone setup and tests that use default settings build a default `Arc<Catalog>` locally, then pass it explicitly.
|
|
- `GenerateParams::new(model, client)` always receives an explicit `Arc<Client>`.
|
|
- When a caller needs diagnostics in runtime request-serving paths, read `FabroClient::ready` and `auth_issues` (from `ClientBuilder::build_ready`), or call `lithos_llm::credentials::readiness` directly.
|
|
- `VaultCredentialSource` is the normal source for vault-backed runtime contexts; `VaultCredentialSource::environment_only()` serves env-only or no-vault contexts.
|
|
|
|
## Why
|
|
|
|
- Rebuilding a client from the source at point of use preserves OAuth refresh behavior on long-running processes.
|
|
- Holding the source on contexts avoids process-global installs and cross-context leakage.
|
|
- Threading the catalog into credential resolution keeps custom providers, aliases, header-only providers, and API model IDs consistent across auth, client registration, and request translation.
|
|
- Requiring an explicit client on `GenerateParams` makes the old silent fallback bug unrepresentable.
|
|
|
|
## Application
|
|
|
|
- Workflow state lives on `RunServices.llm_source` and `RunServices.catalog`.
|
|
- Server state lives on `AppState.llm_source` and `AppState.catalog()`.
|
|
- Hooks and other long-lived executors receive a source plus catalog and derive clients when they actually generate.
|
|
- One-shot CLI commands may resolve a source locally, build a default settings catalog if they do not load runtime catalog settings, then derive a client once for that operation.
|
|
|
|
## Enforcement
|
|
|
|
- Do not add new `Client::from_env`-style shortcuts in production paths.
|
|
- Do not cache a long-lived `Client` where OAuth refresh or storage-dir rebinding matters.
|
|
- Do not construct LLM clients or resolve credentials without an explicit `Arc<Catalog>` or `&Catalog`.
|
|
- Mirror [server-secrets-strategy.md](server-secrets-strategy.md): production credential resolution should be explicit about where secrets come from and how they flow into subprocesses.
|