Skip to content

feat: config-first construction API (Agent::from_config)#59

Merged
yuanhao merged 2 commits into
mainfrom
feat/from-config
Jul 5, 2026
Merged

feat: config-first construction API (Agent::from_config)#59
yuanhao merged 2 commits into
mainfrom
feat/from-config

Conversation

@yuanhao

@yuanhao yuanhao commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

What

Phase B of the roadmap, landed additively — the pre-0.10 builder (Agent::new + with_model/with_model_config) still works unchanged. Nothing is deprecated yet, so no existing call site breaks and there's no forced ~240-site sweep in this PR.

The win

Before — provider and config must be paired correctly by hand, and the model id is passed twice:

let agent = Agent::new(OpenAiCompatProvider)
    .with_model_config(ModelConfig::zai("glm-4.7", "GLM 4.7"))
    .with_model("glm-4.7")
    .with_api_key(key);

After — provider inferred from config.api, key from ZAI_API_KEY:

let agent = Agent::from_config(ModelConfig::zai("glm-4.7", "GLM 4.7"));

New API

  • Agent::from_config(ModelConfig) — provider from config.api, model id from config.id, key from the provider-conventional env var.
  • Agent::from_provider(provider, ModelConfig) — explicit provider (custom impls, test doubles); pair with ModelConfig::mock().
  • Agent::from_config_with(&registry, ModelConfig) -> Result<_, AgentBuildError> — custom registry.
  • Agent::set_model(ModelConfig) — mid-session model switch (re-resolves provider + env key; explicit keys preserved).
  • SubAgentTool::from_config / from_provider mirror these.

Supporting: ProviderRegistry now stores Arc<dyn StreamProvider> + a resolve() accessor; ModelConfig::mock(); exported AgentBuildError.

Docs migrated

lib.rs quick-start, README, mdBook quick-start, CLAUDE.md (new Construction API section), and all examples. cli.rs is the headline demo: 12 Agent::new(X).with_model_config(...) sites + the per-provider env-key ceremony collapse into one from_config each. Remaining mdBook provider/concept pages keep the still-valid old API and move in the deprecation follow-up.

Verification

  • cargo clippy --all-targets --all-features — 0 warnings under -Dwarnings
  • 172 lib + all integration + 9 doctests pass
  • RUSTDOCFLAGS=-Dwarnings cargo doc --all-features clean

Not in this PR (follow-up before 0.10.0)

#[deprecated(since = "0.10.0")] on Agent::new/with_model/with_model_config (+ SubAgentTool mirrors), the full ~240-site + remaining-mdBook sweep, and the 0.10.0 release with a migration guide.

🤖 Generated with Claude Code

yuanhao and others added 2 commits July 5, 2026 23:01
Introduces the 0.10 construction API from the roadmap (Design 2), additively
— the pre-0.10 builder (Agent::new + with_model/with_model_config) still works
unchanged, so nothing is deprecated yet and no existing call site breaks.

New constructors:
- Agent::from_config(ModelConfig) — selects the built-in provider from
  config.api, sets the model id from config.id, and resolves the API key from
  the provider-conventional env var. Kills the provider↔config pairing footgun
  and the doubly-specified model id.
- Agent::from_provider(provider, ModelConfig) — explicit provider (custom impls
  and test doubles); pair with ModelConfig::mock().
- Agent::from_config_with(&registry, ModelConfig) -> Result<_, AgentBuildError>
  — resolve against a custom ProviderRegistry.
- Agent::set_model(ModelConfig) — switch model mid-session (re-selects provider
  and re-resolves the env key; explicit keys preserved).
- SubAgentTool::from_config / from_provider mirror the above.

Supporting changes:
- ProviderRegistry stores Arc<dyn StreamProvider> instead of Box, and gains
  resolve() -> Option<Arc<...>> so a resolved provider can be owned by an Agent
  without borrowing the registry.
- ModelConfig::mock() — a zero-cost, provider="mock" config for tests.
- AgentBuildError (exported) for the fallible from_config_with path.

Docs & examples migrated to from_config: lib.rs quick-start, README, the
mdBook quick-start page, CLAUDE.md (new Construction API section), and all
examples. cli.rs is the headline demo — its 12 Agent::new(X).with_model_config
sites and the per-provider env-key ceremony collapse into one from_config call
each. The remaining mdBook provider/concept pages keep the still-valid old API
and will move in the deprecation follow-up.

Tests: default-registry protocol coverage + empty-registry miss; from_config
wiring/env-key resolution; from_config_with error; from_provider end-to-end;
set_model switch; ModelConfig::mock; SubAgentTool::from_provider.

Refs the Phase B roadmap; deprecation of the old constructors + full doc sweep
+ 0.10.0 release land in a focused follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Multi-agent review of the config-first construction API surfaced no shipping
bugs but a cluster of real improvements, several flagged independently by
multiple reviewers.

- set_model no longer silently clobbers a custom provider (flagged by 4
  reviewers, the one code change reviewers agreed on). Agent now tracks
  provider provenance (provider_is_explicit): providers supplied via new /
  from_provider are KEPT across a model switch (with a warning if they may
  not serve the new protocol); only registry-resolved providers (from_config)
  are re-selected. The previously-dead "unregistered protocol" branch now
  warns instead of silently keeping a mismatched provider.

- ModelConfig::mock() doc hardened to a strong "do NOT use with from_config"
  warning — from_config(mock()) would build the real Anthropic provider
  pointed at a non-routable base_url and fail at first prompt.

- AgentBuildError now derives thiserror::Error (drops the hand-rolled
  Display/Error impls) to match ProviderError / McpError conventions.

- Compile-forced protocol exhaustiveness: the registry coverage test now
  drives off a wildcard-free match over ApiProtocol, so adding a variant
  fails to build until it's registered — the invariant behind from_config's
  unwrap can't silently rot. Added a dispatch-correctness test asserting each
  protocol resolves to a provider that actually speaks it.

- New StreamProvider::protocol() -> Option<ApiProtocol> (default None,
  overridden by the 7 built-in providers) enables the dispatch test and future
  mismatch diagnostics.

- SubAgentTool::from_config_with added for fallible parity with
  Agent::from_config_with (previously the sub-agent from_config had only the
  panic path).

- Doc fixes: from_config # Panics now states "never panics" unconditionally
  (every ApiProtocol is covered); set_model doc states the guaranteed
  provider handling; registry get() cross-references resolve(); CLAUDE.md
  "Construction API (0.10+)" heading softened (this PR doesn't bump the
  version) and notes the SubAgentTool mirrors.

Tests: set_model preserves an explicit provider + key across a switch;
SubAgentTool::from_config wiring and from_config_with empty-registry error;
per-protocol dispatch correctness; exhaustiveness anchor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@yuanhao yuanhao merged commit de28577 into main Jul 5, 2026
4 checks passed
@yuanhao yuanhao deleted the feat/from-config branch July 5, 2026 21:32
yuanhao added a commit that referenced this pull request Jul 6, 2026
…60)

* release: 0.10.0 — deprecate old constructors, migrate to from_config

Completes Phase B: the config-first construction API (shipped additively in
#59) becomes the recommended path, the old builders are deprecated, and every
call site across the codebase and docs migrates to it.

Deprecated (since 0.10.0, removed in 1.0 — all still work, with a compiler
warning pointing at the replacement):
- Agent::new, Agent::with_model, Agent::with_model_config
- SubAgentTool::new, SubAgentTool::with_model, SubAgentTool::with_model_config

The SubAgentTool from_* builders now route through a private `build()` so they
don't trip their own deprecation lint.

Migrated to the new API (CI is -Dwarnings, so every compiled call site had to
move in this commit):
- All examples (code_review, rlm, shared_state; basic/sub_agent/callbacks/
  persistence/cli were done in #59) and both src doctests.
- All tests, except two kept on the deprecated API under #[allow(deprecated)]
  to preserve its coverage until 1.0: test_agent_builder_pattern (asserts the
  builder's effect) and session_cost_usd_none_without_model_config (the
  no-config None branch is only reachable via Agent::new).
- All 19 mdBook pages (providers/concepts/guides/reference). Azure/Bedrock/
  Vertex use ModelConfig::custom since no preset exists.

Release:
- Version 0.10.0.
- CHANGELOG.md with a migration guide (before/after table).
- README install snippet 0.9 -> 0.10; docs/installation 0.5 -> 0.10 and MSRV
  1.56 -> 1.86; README OpenAI-compat example now builds an agent via
  from_config instead of dangling a registry.

Verified: cargo clippy --all-targets --all-features (-Dwarnings) clean; cargo
test --all-features all green; cargo doc (-Dwarnings) clean; doctests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: fix PR #60 review findings

Doc-accuracy review of the migrated (un-CI-compiled) mdBook pages surfaced:

- docs/providers/model-presets.md: `with_thinking_level` is not a real method
  (it's `with_thinking`) — fixed both occurrences. The migration rewrote these
  blocks and should have caught the invented call.
- docs/getting-started/installation.md: the openapi-feature snippet still
  pinned `version = "0.5"` (the main install line was bumped to 0.10 but this
  one was missed) → 0.10; and listed `serde_yaml` where the crate now uses
  `serde_yaml_ng`.
- docs/concepts/prompt-caching.md: the Bedrock row claimed "Automatic (where
  supported)", contradicting README's "Bedrock has no automatic caching" —
  reconciled to no automatic caching.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant