Skip to content

Complete tinyagents inference migration (Motion B): crate-native provider clients, delete duplicated provider stack #4727

Description

@senamakel

Summary

Complete the tinyagents inference migration ("Motion B") by registering crate-native providers::openai clients directly in the turn ModelRegistry, eliminating the remaining openhuman Provider trait objects in the agent harness and deleting the duplicated in-house provider stack. This is the follow-up to Motion A (PR #4726), which put every agent turn path on a seam-owned TurnModelSource so that no harness struct holds Arc<dyn Provider>.

Problem / Context

After Motion A, the harness holds TurnModelSource everywhere, but the source still wraps openhuman's Box<dyn Provider> stack (inference/provider/compatible*.rs, reliable.rs, router.rs — ~30k lines) that re-implements what tinyagents 1.7 ships natively (harness::providers::openai, harness::retry, harness::model::ModelRegistry). The crate ModelRegistry + RunPolicy.fallback + capability gating are already wired in assemble_turn_harness (see docs/tinyagents-phase3-router-registry-design.md) — the registered models are just ProviderModel wrappers rather than crate-native clients. Consolidating removes the double-maintenance and the isomorphic type-conversion seam.

Context/links:

Scope

In scope — the remaining dyn Provider boundaries in agent/ (all provider-resolution/build sites that Motion A intentionally left):

  • inference/provider/factory.rs — build crate providers::openai clients (via ProviderSpec) for BYOK slugs, Ollama, LM Studio, the cloud slug, instead of CompatibleProvider; keep the provider-string grammar.
  • subagent_runner/ops/provider.rs::resolve_subagent_provider — return a TurnModelSource/registry entry instead of Arc<dyn Provider> (this churns its 9 unit tests — deferred from Motion A on purpose).
  • tools/delegate.rs, triage/routing.rs — build sources/crate clients instead of Box<dyn Provider>.
  • Builder .provider()/.provider_arc() setters and the TurnModelSource::provider() escape hatch — remove once nothing needs a raw provider (incl. the streaming session cap-hit checkpoint in session/turn/session_io.rs, which currently uses source.provider().chat(...) because crate ChatModel::invoke has no delta sink — needs the crate stream API).
  • Bespoke providers stay as host ChatModel impls (openhuman_backend.rs, claude_code/, claude_agent_sdk/, openai_codex.rs) — Phase 4.
  • Delete compatible*.rs, reliable.rs, router.rs after cutover.

Smaller stragglers (can land independently, ahead of the big cutover):

  • tinyflows/caps.rs — one-shot .chat() caller still on create_chat_provider (round-trips tool_calls + reasoning into a JSON envelope; needs the seam message converter exposed).
  • src/bin/inference_probe.rs — debug binary still names create_chat_provider.

Not in scope — the inference.* RPC surface, provider-string grammar, local-runtime process management, voice, /v1 server endpoint (all host-owned; unchanged).

Acceptance criteria

  • Crate-native clients registered — the turn ModelRegistry holds providers::openai clients built from config for BYOK/Ollama/LM Studio/cloud; ProviderModel no longer wraps the OpenAI-compat path.
  • Provider stack deleted — inference/provider/compatible*.rs, reliable.rs, router.rs removed; the 207-test compatible_tests.rs behavioral cases re-expressed against the crate providers::openai fixtures (upstream where generic).
  • No dyn Provider in agent/ — grep -rl 'dyn Provider' src/openhuman/agent/ --include='*.rs' returns only bespoke host ChatModel impls (if any); the TurnModelSource::provider() escape hatch and the builder provider setters are gone.
  • Streaming checkpoint on the crate API — session_io.rs cap-hit checkpoint streams via the crate ChatModel stream path, not source.provider().chat.
  • Stragglers migrated — tinyflows/caps.rs and inference_probe.rs off create_chat_provider.
  • Behavior parity — streaming deltas, cost footer (charged-USD + cached tokens), tool-call timeline, and the same-family fallback ordering are byte-parity vs. the current stack (golden mock-backend transcripts + per-provider live smoke); regressions Streamed model calls run in detached spawn: thread_id/task-locals lost, cancellation doesn't stop billed provider call #4460 / $0-turn are not reintroduced.
  • Diff coverage ≥ 80% — the implementing PR(s) meet the changed-lines coverage gate (Vitest + cargo-llvm-cov, enforced by .github/workflows/ci-lite.yml).

Related

https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions