feat(inference): TinyAgents model-interface inversion — Motion A complete + managed-backend crate cutover (Motion B)#4769
Conversation
Record the model-layer inversion baseline (create_chat_model exists as a zero-behavior-change shim; ~7 runtime create_chat_provider call sites + 25 non-test files outside inference/provider/ still name dyn Provider) ahead of completing inference-migration-plan Phase 1. Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
Move the cron model-id resolver and the accessibility vision-locate fallback off Box<dyn Provider>/create_chat_provider onto the crate ChatModel factory (create_chat_model / create_chat_model_with_model_id), part of inference migration Phase 1 (tinyhumansai#4249). Zero behavior change: the factory wraps the same provider stack via ProviderModel; the [IMAGE:] marker survives the crate Message -> host ChatMessage round-trip verbatim; cron only needs the resolved model id (built model discarded). Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
P1-8: one-shot caller migration done (cron, vision); caps.rs + inference_probe deferred. P1-9: investigation finding that plan Buckets 2-4 (routing/channels, harness, subagent) are one coupled refactor gated on a ChatModel-accepting build_turn_models (async context-window + telemetry id must be re-homed), not independently landable — must be its own reviewed PR with behavior-parity tests. Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
The plan's 'harness holds Arc<dyn ChatModel>' is architecturally blocked in Phase 1: build_turn_models needs the raw Provider for route projection (per-tier ProviderModel re-aliasing) + separate-error-slot summarizer, and the crate ChatModel has no downcast to recover it. True inversion is gated on Phase 3 (RouterProvider -> crate ModelRegistry, upstream). Documents the host-only alternative (seam newtype boundary). Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
Ground-truth finding: RouterProvider -> crate ModelRegistry is ALREADY done at the seam (assemble_turn_harness registers routes + wires RunPolicy.fallback + RequiredCapabilitiesMiddleware). The crate's missing capability-selection / capability-aware-fallback are NOT needed (caller picks the tier; fallback chains are hand-safe). So Phase 3 needs no upstream crate change. Real remaining work is host-only Motion A: move build_turn_models to the producer/factory boundary so the harness holds crate ChatModels (TurnModels), not Arc<dyn Provider>. Motion B (crate-native clients, deletes compatible*.rs) is the later LOC win. Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
- Introduced a comprehensive document outlining the referral system, including an overview, main rules, data model, migration instructions, core services, API endpoints, and payment integration details. - The document specifies the structure of referral codes, transactions, and the rewards system, ensuring clarity for developers and users. - Added migration commands for setting up the referral system in the application, enhancing the onboarding process for new users.
…vider Phase 3 / Motion A (tinyhumansai#4249): introduce the seam-owned TurnModelSource — a model-agnostic handle that builds a turn's tiered crate ChatModel set (build_turn_models) — and thread it through the native-bus channel/triage turn path instead of Arc<dyn Provider>. TurnModels now carries the provider telemetry id + native-tool/vision/context-window metadata, so run_channel_turn_via_graph reads capabilities off the built crate models and no longer names the Provider trait. AgentTurnRequest.provider -> turn_model_source; channels/triage producers wrap their resolved provider at the bus boundary; the Provider stays confined to the inference factory + seam. Zero behavior change: same ProviderModels, same registry/fallback wiring. Both Cargo worlds' lib compile green; the 3 bus integration tests compile green. (Pre-existing full --tests breakage in unrelated modules — config load, web, ollama, sandbox — is untouched.) Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
TurnModelSource landed; channel/bus turn path fully off Arc<dyn Provider> (commit 30c7dfd). Records remaining subagent + session slices and their tentacles (SubagentCheckpoint summary provider; Agent lifecycle + model_vision). Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
Phase 3 / Motion A (tinyhumansai#4249): thread TurnModelSource through the sub-agent turn path instead of Arc<dyn Provider>. agent_graph::AgentTurnRequest.provider -> turn_model_source; run_subagent_via_graph takes the source, reads vision/ native-tool caps + telemetry id off the built crate models, and resolves the context window via the source. The cap-hit SubagentCheckpoint now summarizes on a crate ChatModel (built via TurnModelSource::build_summarizer) instead of provider.chat, so it no longer names the Provider trait. Runner wraps its resolved subagent_provider at both dispatch sites. Zero behavior change: same ProviderModels, same registry/fallback; checkpoint maps ChatRequest->ModelRequest faithfully (max_tokens preserved, temperature baked). Core lib green; changed files clean under --lib --tests. (extract_tool + subagent provider.rs resolution remain as documented exit-sweep stragglers.) Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
Subagent turn path off Arc<dyn Provider> (commit 8db8887); records remaining Agent session path + extract_tool/provider.rs stragglers + exit sweep. Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
…Provider Phase 3 / Motion A (tinyhumansai#4249): ExtractFromResultTool now holds a TurnModelSource — queries the model context window through it (source.effective_context_window) and builds a summarizer crate ChatModel per call (source.build_summarizer) that it invokes, replacing provider.chat_with_system. Runner wraps the resolved extract_provider at the tool boundary. Adds TurnModelSource::is_local_provider passthrough (needed by the upcoming ParentExecutionContext migration). Core lib green; extract_tool test module clean under --lib --tests; zero behavior change. Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
Phase 3 / Motion A (tinyhumansai#4249): the final major turn path. Agent + AgentBuilder, ParentExecutionContext, and ChatTurnGraph now hold a seam TurnModelSource / built TurnModels instead of Arc<dyn Provider>: - Agent.turn_model_source builds the tiered crate ChatModel set per turn; core resolves the context window + builds up front, reads vision off the built models, and hands TurnModels to ChatTurnGraph (which no longer builds/holds a provider). - ParentExecutionContext carries the source; sub-agent inheritance / extract summarization-route / rhai model build / is_local_provider read through it. TurnModelSource gains is_local_provider() + a provider() escape hatch for the few seam-boundary sites that still resolve a raw provider inline (sub-agent provider resolution + its 9 unit tests, rhai, payload summarizer) — no agent-harness struct holds a Provider. - The session_io cap-hit checkpoint keeps its streaming provider.chat via source.provider() (crate ChatModel::invoke doesn't expose the delta sink). - Builder .provider()/.provider_arc() setters wrap into a source; Agent provider_arc() accessor -> turn_model_source(). Zero behavior change: same ProviderModels, same registry/fallback wiring. Core lib green; all touched test files (inline + 10 integration tests) compile clean; remaining --tests errors are pre-existing unrelated modules (config load, web, ollama, sandbox, reliable_tests, memory) untouched by this change. Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
…ated) Session path migrated (9112330); no agent-harness struct holds Arc<dyn Provider>. Records the remaining provider-resolution boundaries (factory, resolve, delegate, triage, builder setters) as Motion B (crate-native client) territory. Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
Formatting-only (line wrapping) applied by cargo fmt over the Motion A changes. Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
Restore two e2e specs (cron-jobs-flow, telegram-channel-flow) to upstream/main; they rode into this branch via an upstream-sync merge and are not part of the TurnModelSource migration. Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
…nyagents#44) Re-pin vendor/tinyagents to the merged crate main (333f9a5), which adds the configurable AuthStyle (None/Bearer/XApiKey/Anthropic/Custom) + static headers to OpenAiModel needed to cut the host provider stack over to crate-native clients (Motion B, tinyhumansai#4727). Both Cargo worlds build green against it (the other 10 crate commits since our pin are additive — no seam adaptation needed); Cargo.lock picks up sha2 0.11 transitively. Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
…+temp+merge) Cutover-branch-only pin to the integration of tinyagents#44 (merged) + tinyhumansai#47 + tinyhumansai#48, so the host can build the crate-native OpenAiModel provider path against with_auth_style / with_temperature_* / with_merge_system_into_user. Replaced by a released-crate bump once tinyhumansai#47/tinyhumansai#48 merge. Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
…tion B) First host-side step of the provider cutover (tinyhumansai#4727): a new provider::crate_openai module that builds a crate-native tinyagents OpenAiModel (ChatModel) from resolved OpenAI-compatible provider config — mapping the host AuthStyle 1:1 to the crate's, and applying temperature suppression/override, merge-system-into-user, and static headers (the tinyagents tinyhumansai#44/tinyhumansai#47/tinyhumansai#48 config). This is the single boundary where host provider config becomes a crate-native ChatModel; bespoke providers (managed backend, claude-code/agent-sdk, codex) stay host ChatModel impls and don't route through here. Additive + unit-tested (auth mapping 1:1, profile carries provider/model, local None-auth shape). Not yet wired as the factory default — that + per-provider wire parity validation (before deleting compatible*.rs) is the follow-up. Core lib green; module clean under --lib --tests. Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
…rged) tinyhumansai#47/tinyhumansai#48 merged; crate main (95fa263) now carries all three OpenAiModel host-parity features (auth styles tinyhumansai#44, temperature suppression/override tinyhumansai#47, merge_system_into_user tinyhumansai#48). Re-pin the cutover branch from the local integration branch to released main so the vendor pin references published API. Core lib green. Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
…tover) Add make_crate_openai_chat_model — the drop-in parallel to the host make_openai_compatible_provider_with_config, taking the same resolved inputs (slug, endpoint, credential, host auth style, model, temperature suppression + override, merge-system) and returning a crate ChatModel instead of a Box<dyn Provider>. This is the ready swap point for each generic OpenAI-compat construction site in the factory. Unit-tested; core lib green. Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
The bespoke-provider rewrite that gates deleting compatible*.rs: a host ChatModel (OpenHumanBackendModel) that bridges the managed backend's three non-generic needs onto the crate wire client — resolves the dynamic session JWT per call and builds a fresh crate OpenAiModel (Bearer); injects the ambient thread_id into ModelRequest.provider_options so the crate emits it as a body field (parity with with_openhuman_thread_id); and relies on the crate preserving the full response on ModelResponse.raw so the seam still recovers the openhuman.usage/billing charged-USD + cached-token envelope. resolve_bearer / base_url exposed pub(super) for reuse. Additive + unit-tested; core lib green. Not yet wired (make_openhuman_backend still returns the Provider) — that swap is the create_chat_model flip. Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
…end (Motion B) Wire the cutover: extract resolve_managed_backend (shared model/options resolution) and add make_openhuman_backend_model (crate-native OpenHumanBackendModel). create_chat_model_with_model_id now routes the managed OpenHuman backend through the crate ChatModel instead of a ProviderModel-wrapped provider — so every one-shot ChatModel caller (memory summarize, learning, meeting summaries, etc.) uses the crate wire client for the managed backend (the common case). Test-provider override still wins; temperature rides the per-call ModelRequest on the crate path. resolves_to_managed_backend mirrors the empty/cloud/openhuman dispatch. Core lib green. Claude-Session: https://claude.ai/code/session_018MnMVgnzxchtcs1DDUxTfF
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR introduces ChangesCrate-native model migration
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Caller
participant TurnModelSource
participant ChatModel
participant TurnRunner
Caller->>TurnModelSource: provide provider source
TurnModelSource->>ChatModel: build crate-native model
TurnModelSource->>TurnRunner: provide TurnModels metadata
TurnRunner->>ChatModel: invoke or stream model request
Possibly related issues
Possibly related PRs
Suggested labels: Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7e98c1b390
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if !test_override_active && resolves_to_managed_backend(role, config) { | ||
| return make_openhuman_backend_model(role, config); |
There was a problem hiding this comment.
Preserve the LocalOnly gate for managed ChatModels
When a role resolves to the managed OpenHuman backend, this early return bypasses the existing create_chat_provider_from_string path that calls enforce_local_only_inference; in LocalOnly privacy mode, callers using create_chat_model/create_chat_model_with_model_id for default chat, summarization, or subconscious roles can still construct and invoke the OpenHuman cloud model. Route the managed shortcut through the same privacy check (including the resolved cloud/empty sentinel) before returning the crate-native model.
Useful? React with 👍 / 👎.
| pub fn new(backend: OpenHumanBackendProvider, default_model: impl Into<String>) -> Self { | ||
| Self { | ||
| backend, | ||
| default_model: default_model.into(), | ||
| } |
There was a problem hiding this comment.
Apply the construction temperature on managed models
For managed-backend roles, the factory still accepts a temperature, but this model stores only the backend and default model, so callers that pass temperature at construction and do not also set ModelRequest::with_temperature lose their requested setting on cloud calls. For example automation uses create_chat_model("summarization", ..., 0.0) and meeting summaries use 0.3; those remain honored for BYOK/local through ProviderModel, but the managed shortcut falls back to the wire client's default unless the default temperature is carried here and applied when the request lacks one.
Useful? React with 👍 / 👎.
| let model = self.build_wire_model()?; | ||
| model.invoke(state, with_thread_id(request)).await |
There was a problem hiding this comment.
Preserve OpenHuman billing metadata in managed responses
Managed backend responses include openhuman.billing.charged_amount_usd, but this path returns the crate OpenAiModel response unchanged; downstream usage_info_from_response only recovers charged USD from the adapter-specific raw.openhuman_usage_meta shape produced by ProviderModel. For one-shot managed callers such as memory summarization audits, token usage may still exist but charged_amount_usd is recorded as zero, so this wrapper should translate the backend raw metadata into the seam's expected usage meta (or teach the recovery helper to parse the managed raw shape).
Useful? React with 👍 / 👎.
…gents pin (Motion B)
Bump vendor/tinyagents to 1057acf (tinyagents#49: OpenAiModel native-tool/vision
profile toggles + baked provider options) and add the crate-native local-runtime
builder that consumes them:
- crate_openai.rs: CrateOpenAiConfig gains native_tool_calling / vision /
default_provider_options; build_crate_openai_model applies them after
provider/model are set (which re-derive the profile the toggles mutate).
- make_crate_local_runtime_chat_model: the crate-native counterpart of the host
make_*_provider local builders — native tools + vision forced off, Ollama
num_ctx baked as {"options":{"num_ctx":N}}, matching the host wire shape.
Unit-tested (profile flags off, provider/model carried).
Builder is ready but NOT yet the live dispatch: create_chat_provider_from_string's
local branches run the verify_session_active gate (custom/local providers require
an active OpenHuman session), and that gate is #[cfg(not(test))] so a crate-native
short-circuit that skipped it would be a security regression no test/CI catches.
The dispatch flip is deferred to a verified-build follow-up (see drift ledger's
Motion B cutover table). Also folds in fmt drift from prior Motion B commits.
Host lib compiles clean with the pin bump (inference/provider changes error-free;
the only local --lib breakage is pre-existing voice/dictation_listener hotkey
imports fixed on upstream/main, resolved by the upstream merge that follows).
Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
…e-provider-cutover
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 034fac3385
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| .chat_with_system(Some(locate_system_prompt()), &user, model, 0.0) | ||
| let request = ModelRequest::new(vec![ | ||
| Message::system(locate_system_prompt().to_string()), | ||
| Message::user(user), |
There was a problem hiding this comment.
Preserve image content for managed vision calls
When the chat role resolves to the managed OpenHuman backend, create_chat_model now returns OpenHumanBackendModel, which forwards this ModelRequest directly to the crate OpenAiModel instead of going through the host compatible provider's MessageContent::from_chat_text marker parser. In that path this Message::user(user) is only a text block containing [IMAGE:data:...], so the screenshot is not sent as an image and locate_via_vision cannot actually inspect the UI. Build a crate message with an actual image content block here, or keep managed vision calls on the host provider path that expands [IMAGE:] markers.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/openhuman/inference/provider/factory.rs`:
- Around line 940-961: The managed backend path in
create_chat_model_with_model_id drops the constructor temperature, causing
requests without ModelRequest.temperature to differ from provider-backed
behavior. Update make_openhuman_backend_model and OpenHumanBackendModel
construction to accept and retain temperature, or consistently apply it to
managed requests, while preserving the test-provider override behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e37dc8e0-f351-4af4-a642-8195d4693e88
⛔ Files ignored due to path filters (2)
Cargo.lockis excluded by!**/*.lockapp/src-tauri/Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (48)
docs/tinyagents-drift-ledger.mddocs/tinyagents-phase3-router-registry-design.mdsrc/openhuman/accessibility/automate.rssrc/openhuman/accessibility/vision_click.rssrc/openhuman/agent/bus.rssrc/openhuman/agent/harness/agent_graph.rssrc/openhuman/agent/harness/fork_context.rssrc/openhuman/agent/harness/graph.rssrc/openhuman/agent/harness/session/builder/setters.rssrc/openhuman/agent/harness/session/runtime.rssrc/openhuman/agent/harness/session/runtime_tests.rssrc/openhuman/agent/harness/session/turn/core.rssrc/openhuman/agent/harness/session/turn/graph.rssrc/openhuman/agent/harness/session/turn/session_io.rssrc/openhuman/agent/harness/session/turn/tools.rssrc/openhuman/agent/harness/session/types.rssrc/openhuman/agent/harness/subagent_runner/extract_tool.rssrc/openhuman/agent/harness/subagent_runner/ops/checkpoint.rssrc/openhuman/agent/harness/subagent_runner/ops/graph.rssrc/openhuman/agent/harness/subagent_runner/ops/runner.rssrc/openhuman/agent/triage/evaluator.rssrc/openhuman/agent_orchestration/parent_context/builder.rssrc/openhuman/channels/runtime/dispatch/processor.rssrc/openhuman/cron/scheduler.rssrc/openhuman/inference/provider/crate_openai.rssrc/openhuman/inference/provider/factory.rssrc/openhuman/inference/provider/mod.rssrc/openhuman/inference/provider/openhuman_backend.rssrc/openhuman/inference/provider/openhuman_backend_model.rssrc/openhuman/rhai_workflows/bridge.rssrc/openhuman/skills/e2e_plumbing_tests.rssrc/openhuman/skills/e2e_run_tests.rssrc/openhuman/tinyagents/mod.rssrc/openhuman/tinyagents/payload_summarizer.rstests/agent_archivist_debug_round21_raw_coverage_e2e.rstests/agent_harness_leftovers_raw_coverage_e2e.rstests/agent_harness_public.rstests/agent_harness_raw_coverage_e2e.rstests/agent_large_round25_raw_coverage_e2e.rstests/agent_prompts_subagent_raw_coverage_e2e.rstests/agent_session_turn_raw_coverage_e2e.rstests/agent_tool_loop_raw_coverage_e2e.rstests/agent_turn_toolloop_round22_raw_coverage_e2e.rstests/calendar_grounding_e2e.rstests/composio_list_tools_stack_overflow_regression.rstests/inference_agent_raw_coverage_e2e.rstests/tools_agent_credentials_state_raw_coverage_e2e.rsvendor/tinyagents
| // Managed OpenHuman backend → crate-native host `ChatModel` | ||
| // ([`OpenHumanBackendModel`], issue #4727 Motion B) instead of a | ||
| // `ProviderModel`-wrapped provider. A test-provider override (below, inside | ||
| // `create_chat_provider`) must still win, so only take this path when no | ||
| // override is installed. Temperature rides the per-call `ModelRequest` on the | ||
| // crate path (the managed model is reused across prompts of differing temp). | ||
| let test_override_active = { | ||
| #[cfg(any(test, feature = "e2e-test-support"))] | ||
| { | ||
| test_provider_override::current().is_some() | ||
| } | ||
| #[cfg(not(any(test, feature = "e2e-test-support")))] | ||
| { | ||
| false | ||
| } | ||
| }; | ||
| if !test_override_active && resolves_to_managed_backend(role, config) { | ||
| return make_openhuman_backend_model(role, config); | ||
| } | ||
| let (provider, model) = create_chat_provider(role, config)?; | ||
| let chat = chat_model_from_provider(provider, model.clone(), temperature); | ||
| Ok((chat, model)) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find callers of create_chat_model* to see whether they later set request.temperature.
rg -nP --type=rust -C3 '\bcreate_chat_model(_with_model_id)?\s*\(' src
# Inspect whether OpenHumanBackendModel or its wire model ever pins a temperature.
rg -nP --type=rust -C3 'with_temperature_override|temperature' src/openhuman/inference/provider/openhuman_backend_model.rs
# Confirm ProviderModel's temperature fallback for comparison.
rg -nP --type=rust -C2 'request\.temperature' src/openhuman/tinyagents/model.rsRepository: tinyhumansai/openhuman
Length of output: 7524
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the managed-backend constructor and the chat model temperature fallback.
sed -n '880,1040p' src/openhuman/inference/provider/factory.rs
printf '\n---\n'
sed -n '430,590p' src/openhuman/tinyagents/model.rs
printf '\n---\n'
# Find any managed-backend-specific temperature wiring.
rg -n --type=rust 'with_temperature_override|temperature.*OpenHumanBackendModel|OpenHumanBackendModel' src/openhuman/inference/provider src/openhuman/tinyagentsRepository: tinyhumansai/openhuman
Length of output: 17812
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect OpenHumanBackendModel temperature handling and the managed-backend constructor.
sed -n '1,220p' src/openhuman/inference/provider/openhuman_backend_model.rs
printf '\n---\n'
sed -n '1280,1365p' src/openhuman/inference/provider/factory.rs
printf '\n---\n'
# Check whether the managed backend is constructed with any temperature override elsewhere.
rg -n --type=rust 'make_openhuman_backend_model\(|OpenHumanBackendModel::new\(' src/openhuman/inference/provider/factory.rs src/openhuman/inference/provider/openhuman_backend_model.rsRepository: tinyhumansai/openhuman
Length of output: 10548
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the upstream OpenAiModel temperature semantics and whether it defaults anywhere.
rg -n --type=rust -C3 'compatible_provider\(|struct OpenAiModel|temperature' src/tinyagents src/openhuman | sed -n '1,260p'Repository: tinyhumansai/openhuman
Length of output: 20408
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate the tinyagents/OpenAiModel implementation and inspect temperature handling.
git ls-files | rg '(^|/)(tinyagents|openai)(/|\.rs$)'
printf '\n---\n'
fd -a 'model.rs|openai.rs|compatible.rs' src . 2>/dev/null | sed -n '1,120p'
printf '\n---\n'
rg -n --type=rust -C4 'struct OpenAiModel|compatible_provider\(|temperature' . | sed -n '1,260p'Repository: tinyhumansai/openhuman
Length of output: 21817
Managed backend drops the constructor temperature
create_chat_model_with_model_id returns make_openhuman_backend_model(role, config) on the managed route, so the temperature argument never reaches OpenHumanBackendModel. Calls that leave ModelRequest.temperature unset will sample differently on the managed path than on the provider-backed path; thread the temp into the managed model, or set it on every managed request, to keep parity.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/openhuman/inference/provider/factory.rs` around lines 940 - 961, The
managed backend path in create_chat_model_with_model_id drops the constructor
temperature, causing requests without ModelRequest.temperature to differ from
provider-backed behavior. Update make_openhuman_backend_model and
OpenHumanBackendModel construction to accept and retain temperature, or
consistently apply it to managed requests, while preserving the test-provider
override behavior.
Add routing tests proving create_chat_model's Motion B dispatch: - resolves_to_managed_backend: true for default/cloud-tier roles, false once a role points at a local runtime (ollama:). - managed role → crate-native OpenHumanBackendModel (profile() None, serves every tier via request.model). - local role → ProviderModel wrapper (profile() Some, neutral "local" origin, native tools + vision off — the same knobs make_crate_local_runtime_chat_model will carry post-flip). profile() presence is the cheapest observable distinguishing the two construction paths without a network round-trip. cargo fmt clean; the four targeted tests pass on a warm target. Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
…nyhumansai#49 merged) The lib-test target (cargo test --lib) did not compile: Motion A renamed ParentExecutionContext.provider -> turn_model_source (and the AgentBuilder field), but ~8 agent_orchestration/harness test modules still built the struct with the old field. No PR existed before tinyhumansai#4769, so this was never CI-tested; CI rust-core-coverage compiles the full lib-test target and would fail here. Wrap each stale site in TurnModelSource::new(provider) and fix the AgentBuilder default-test field access. Sites: subagent_runner/ops_tests, agent_orchestration {ops_tests, agent_teams/runtime_tests, workflow_runs/engine_tests, tools/ (close_subagent, spawn_parallel_agents_tests, spawn_worker_thread, tools_e2e_tests)}. Also bump vendor/tinyagents to 7c6e81a (tinyagents#49 merged onto v1.8.0 main: OpenAiModel native-tool/vision toggles + baked provider options; carries v1.8.0's tinyhumansai#45 tool-call-arg recovery + tinyhumansai#46 microcompact gate). Cargo.lock 1.7.1 -> 1.8.0; the `version = "1.7"` requirement admits 1.8. Verified: lib-test target type-checks with 0 errors (reaches codegen); full compile/run delegated to CI (contended dev box can't link the full test binary in-budget). Crate: 61 openai unit tests pass on 7c6e81a. Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/tinyagents-drift-ledger.md`:
- Around line 30-31: The drift ledger entries for the current host pin and
verification PR reference stale commit 7c6e81a; update them to match
vendor/tinyagents commit 85f7c4e796167f6b06a5baaf88896949952c2a63, or clearly
label the existing entries as historical context.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f095c8ff-7252-428c-8e87-f09845bf4776
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (12)
docs/tinyagents-drift-ledger.mdsrc/openhuman/agent/harness/session/types.rssrc/openhuman/agent/harness/subagent_runner/ops_tests.rssrc/openhuman/agent_orchestration/agent_teams/runtime_tests.rssrc/openhuman/agent_orchestration/ops_tests.rssrc/openhuman/agent_orchestration/tools/close_subagent.rssrc/openhuman/agent_orchestration/tools/spawn_parallel_agents_tests.rssrc/openhuman/agent_orchestration/tools/spawn_worker_thread.rssrc/openhuman/agent_orchestration/tools/tools_e2e_tests.rssrc/openhuman/agent_orchestration/workflow_runs/engine_tests.rssrc/openhuman/inference/provider/factory_tests.rsvendor/tinyagents
✅ Files skipped from review due to trivial changes (1)
- src/openhuman/agent_orchestration/tools/spawn_worker_thread.rs
🚧 Files skipped from review as they are similar to previous changes (1)
- src/openhuman/agent/harness/session/types.rs
| | Current host pin | `v1.8.0-1-g7c6e81a` ([tinyagents#49](https://github.com/tinyhumansai/tinyagents/pull/49) **merged** onto v1.8.0 main) | | ||
| | Verification PR | [openhuman#4769](https://github.com/tinyhumansai/openhuman/pull/4769) — Motion A + Motion B checkpoint | |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check the actual pinned commit for vendor/tinyagents submodule
git -C vendor/tinyagents rev-parse HEAD 2>/dev/null
cat .gitmodules 2>/dev/null | grep -A2 tinyagents
rg -n 'tinyagents' Cargo.toml Cargo.lock 2>/dev/null | head -20Repository: tinyhumansai/openhuman
Length of output: 1148
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== docs/tinyagents-drift-ledger.md (relevant lines) =="
sed -n '20,40p;85,100p' docs/tinyagents-drift-ledger.md | cat -n
echo
echo "== submodule status =="
git submodule status -- vendor/tinyagents vendor/tinyflows || true
echo
echo "== search for SHAs mentioned in review =="
rg -n '1057acf|7c6e81a|85f7c4e' -S . || true
echo
echo "== vendor/tinyagents HEAD and commit details =="
git -C vendor/tinyagents rev-parse HEAD
git -C vendor/tinyagents show -s --format='%H %s' HEADRepository: tinyhumansai/openhuman
Length of output: 3405
Update the ledger pin to match vendor/tinyagents. vendor/tinyagents currently points at 85f7c4e796167f6b06a5baaf88896949952c2a63, so the 7c6e81a entries here are stale; either refresh these lines or mark them as historical context.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/tinyagents-drift-ledger.md` around lines 30 - 31, The drift ledger
entries for the current host pin and verification PR reference stale commit
7c6e81a; update them to match vendor/tinyagents commit
85f7c4e796167f6b06a5baaf88896949952c2a63, or clearly label the existing entries
as historical context.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 85f7c4e796
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| async fn invoke(&self, state: &(), request: ModelRequest) -> TaResult<ModelResponse> { | ||
| let model = self.build_wire_model()?; | ||
| model.invoke(state, with_thread_id(request)).await |
There was a problem hiding this comment.
Publish SessionExpired for backend auth failures
When a managed OpenHuman call returns HTTP 401/403 from this direct crate path, the error now bubbles out of OpenAiModel without running the legacy backend-auth branch (publish_backend_session_expired in the provider HTTP layer). In non-RPC/background callers that use create_chat_model (for example memory or meeting summarization), that means an expired app-session JWT no longer flips the scheduler gate or clears the session, so the same background work can keep retrying against a permanently invalid token until some separate RPC path happens to classify it. Please translate managed-backend auth failures here into the same SessionExpired publish before returning the error.
Useful? React with 👍 / 👎.
…ck CI) tests/orchestration_effect_executor_e2e.rs (added by tinyhumansai#4738) still called dispatch_device_tool/handle_tool_call with the old sync 2-arg signatures after tinyhumansai#4753 made them async/3-arg — broken identically on upstream/main. It only surfaced in this PR because the Motion A test-debt fix touched agent_orchestration files, pulling the orchestration domain into CI rust-core-coverage's scope. Convert the two affected tests to #[tokio::test] + .await, and pass the cycle_id arg (the exec gate is bypassed for non-local-exec tools like device_status). Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
… error chain The full test suite compiles now (Motion A compile debt fixed), which surfaced 5 runtime failures. Deep root-cause: 4 are stale tests written against pre-migration internals (never CI-run), 1 is a real minor error-surfacing gap. No Motion A/B runtime-behavior regression — the error/retry/model-resolution contracts hold. Stale tests (fixed): - agent_tool_loop / agent_prompts_subagent *surfaces_provider_error*: the crate-owned retry (RunPolicy.retry, max 3, mirroring the old ReliableProvider) rides a single-shot failing mock through to its empty-queue default Ok. Add an field so the mock fails persistently (all attempts) — a genuinely unreachable provider still surfaces its error. - agent_large_round25: extract_from_result now runs per-chunk extraction through the crate ChatModel (build_summarizer().invoke() → chat), not the legacy chat_with_system; 6 chunk calls drained the agent-turn queue. Route extraction calls (detected by the extraction system prompt) to the fixed result in the mock. - inference_agent…user_state_edges: expected an unknown model to collapse to reasoning-v1; the managed backend forwards it verbatim (tinyhumansai#4598). Update the assertion. Code fix: - cron run_agent_job surfaced as e.to_string() (outermost message only), dropping the cause the halt-guard classifier needs to detect an offline local provider. Surface the full anyhow chain (), matching the comment's stated intent that raw carry provider-URL/stack detail. Locally verified (RUST_MIN_STACK=128M): the 4 integration-test fixes pass; the cron lib test is delegated to CI (the full lib-test target won't link in-budget on the contended dev box). Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/openhuman/cron/scheduler.rs (1)
958-976: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winScrub the Sentry-facing error string
src/core/observability.rs:1830-1838forwards the message directly tosentry::capture_message(...), so the new full{e:#}chain will reach Sentry unchanged. Use a scrubbed capture string, or split the classifier input from the reported message.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/openhuman/cron/scheduler.rs` around lines 958 - 976, The full anyhow chain stored in `last_agent_error` is forwarded by `report_error` to Sentry via `sentry::capture_message`, exposing provider URLs and other sensitive details. Update `report_error` in `src/core/observability.rs` to scrub the message before Sentry capture, while preserving the raw error string for local-provider classification and other non-user-facing observability needs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/openhuman/cron/scheduler.rs`:
- Around line 958-976: The full anyhow chain stored in `last_agent_error` is
forwarded by `report_error` to Sentry via `sentry::capture_message`, exposing
provider URLs and other sensitive details. Update `report_error` in
`src/core/observability.rs` to scrub the message before Sentry capture, while
preserving the raw error string for local-provider classification and other
non-user-facing observability needs.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e288d933-7dd5-40e4-b09f-3fcafed9773f
📒 Files selected for processing (7)
docs/tinyagents-drift-ledger.mdsrc/openhuman/cron/scheduler.rstests/agent_large_round25_raw_coverage_e2e.rstests/agent_prompts_subagent_raw_coverage_e2e.rstests/agent_tool_loop_raw_coverage_e2e.rstests/inference_agent_raw_coverage_e2e.rstests/orchestration_effect_executor_e2e.rs
✅ Files skipped from review due to trivial changes (1)
- docs/tinyagents-drift-ledger.md
…on fast-fail) The full suite now runs (14,433 pass); these were the last 4 failures. 3 are pre-existing branch/merge debt (zero migration commits), surfaced only because the inference-migration changes broadened the coverage job's scope; 1 is a migration-adjacent fast-fail fix. - subconscious tinyplace: tinyhumansai#4738 (hosted-brain migration) retired the tinyplace local-world subconscious (SubconsciousKind::ALL = [Memory]), but the trigger RPC error message still listed it and json_rpc_e2e still triggered it. Point the test at "memory" and correct the error message to "expected memory|all". - memory_threads schema count: the threads controller surface exposes 19 schemas, not 17; the schema/controller parity assert (the real invariant) already held at 19. Update the tracked count. - approval decide message: an approve_always_for_flow decision now sits between approve_always_for_tool and deny, so the test's stale substring no longer matched. Update it to the full current option list. - cron loopback fast-fail: is_non_retryable now classifies a refused loopback connection (offline local LLM server) as non-retryable, so the crate-owned retry does not burn ~1.5s of pointless backoff before the identical connect-refused. This lets execute_job_with_retry halt within its 5s bound once the classification (fixed via the {e:#} cause-chain) trips on the first attempt. Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9e3f748cda
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "serde", | ||
| "serde_json", | ||
| "sha2 0.10.9", | ||
| "sha2 0.11.0", |
There was a problem hiding this comment.
Regenerate the Tauri lockfile for tinyagents 1.8
The root lockfile in this same change resolves the patched vendor/tinyagents package as 1.8.0, but the Tauri lockfile's tinyagents stanza is still 1.7.1 while only its dependency list changed here. Because app/src-tauri/Cargo.toml patches the same ../../vendor/tinyagents path and embeds openhuman_core, a locked Tauri build/metadata run will require the lockfile to be updated before compiling the new 1.8 APIs added in this commit. Please regenerate app/src-tauri/Cargo.lock so the tinyagents package version matches the vendored crate.
Useful? React with 👍 / 👎.
… override create_chat_provider returns the sentinel model mock-model whenever a process-global test_provider_override is installed (factory.rs). The create_chat_model seam test installs one while holding inference_test_guard, but nine create_chat_provider/create_chat_model routing tests read the global without the guard, so cargo's parallel runner could run them during the override window and observe mock-model instead of the resolved id. Adding the new create_chat_model routing tests shifted scheduling enough to surface the latent race (create_chat_provider_subconscious_honours_byok_route flaked). Hold inference_test_guard in every create_chat_provider/model routing test so they serialize with the override-installing tests. Isolation-only; no behavior change. Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
create_chat_model_with_model_id now routes local OpenAI-compatible runtimes
(Ollama / LM Studio / MLX / OMLX / local-openai) through a crate-native
tinyagents OpenAiModel instead of a ProviderModel-wrapped host provider, via the
new try_create_local_runtime_chat_model. Cloud / BYOK / bespoke providers return
None there and fall through to the existing Provider path.
Safety:
- The flip re-runs the SAME access gate the Provider path applies to
custom/local providers: enforce_local_only_inference (privacy mode) +
verify_session_active (session requirement, cfg(not(test))). Routing here
cannot bypass either.
- Endpoint / auth / num_ctx resolution mirrors each make_*_provider exactly
(same ollama_base_url_from_config / lm_studio_base_url / profile helpers);
native tools + vision forced off; Ollama num_ctx baked as
{"options":{"num_ctx":N}}. Temperature rides the per-call ModelRequest
(managed-path parity; the @<temp> suffix still bakes a fixed override).
- Bumps vendor/tinyagents to b580f1a (tinyagents#50): the crate wire client now
surfaces the full transport error source chain, so the crate-native local path
still exposes the connection-refused errno the cron loopback halt guard needs.
Without it, flipping lmstudio to crate-native would re-break
cron_agent_job_local_provider_offline_trips_halt_guard.
Tests: the ollama routing test now asserts crate-native (profile provider
"ollama", tools/vision off) instead of the ProviderModel adapter's neutral
"local"; add a None-path test (managed + cloud fall through); guard the memory
build_chat_runtime local tests against the global override. Lib compiles clean;
full verification on CI.
Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e226aba875
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if let Some(result) = try_create_local_runtime_chat_model(role, config) { | ||
| return result; |
There was a problem hiding this comment.
Preserve construction temperature for local runtimes
When chat_provider/memory_provider resolves to a local runtime without an @temperature suffix, this new shortcut returns a crate OpenAiModel before the fallback chat_model_from_provider(..., temperature) path can bake in the caller-supplied temperature; try_create_local_runtime_chat_model only forwards the parsed provider-string suffix (temp) and has no access to this temperature argument. One-shot callers such as meeting summaries (create_chat_model("summarization", ..., 0.3)) and automation decisions (..., 0.0) do not set ModelRequest::with_temperature, so local Ollama/LM Studio/etc. calls now fall back to the wire client's default sampling instead of the requested deterministic/low-temperature behavior.
Useful? React with 👍 / 👎.
…e-provider-cutover # Conflicts: # src/openhuman/subconscious/schemas.rs # tests/orchestration_effect_executor_e2e.rs # tests/raw_coverage/agent_prompts_subagent_raw_coverage_e2e.rs # tests/raw_coverage/agent_tool_loop_raw_coverage_e2e.rs # tests/raw_coverage/memory_threads_raw_coverage_e2e.rs
…avior
The upstream merge replaced the old cron_agent_job_local_provider_offline_trips_
halt_guard test with cron_agent_job_short_loopback_send_error_stays_retryable —
i.e. upstream decided an offline local provider STAYS RETRYABLE (it may be
transiently starting up), rather than tripping the halt guard.
My earlier cron loopback work went the opposite way (surface the connection-
refused errno so the offline signal trips the halt guard). With the local-runtime
flip routing lmstudio crate-native and tinyagents#50 (error_source_chain) surfacing
the errno, run_agent_job's raw now carried "connection refused (os error N)", so
is_local_provider_unreachable_failure returned true and the new upstream test
failed.
Defer to upstream:
- run_agent_job raw back to e.to_string() (drop the {e:#} cause-chain surfacing).
- Remove the is_non_retryable loopback fast-fail branch.
- Re-pin vendor/tinyagents to 7c6e81a (before tinyhumansai#50), so the crate-native local
error does not surface the errno the classifier trips on. tinyhumansai#50 stays a good crate
improvement but is deliberately not consumed here.
The local-runtime crate cutover itself (which needs tinyhumansai#49's toggles, not tinyhumansai#50) is
unchanged. Resolves the sole failure after the upstream merge.
Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 36c1dca43b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| Ok(OpenAiModel::compatible_provider( | ||
| PROVIDER_LABEL, | ||
| token, | ||
| base_url, | ||
| &self.default_model, |
There was a problem hiding this comment.
Preserve configured proxy for managed backend calls
When users configure OpenHuman's runtime proxy with the default openhuman scope or a provider.*/provider.compatible service scope, the legacy managed backend path built its reqwest client through compatible_request.rs, which applies apply_runtime_proxy_to_builder. This direct OpenAiModel::compatible_provider construction has no hook for that host client/proxy config, so managed one-shot calls now cut over here (memory/meeting summaries, automation) will try a direct connection and fail in proxied environments unless the proxy was exported as process env. Please keep the managed backend on the host client path or thread the configured client/proxy into the crate model before dispatch.
Useful? React with 👍 / 👎.
…tream The upstream merge moved the raw_coverage tests to tests/raw_coverage/ and, for agent_tool_loop + agent_prompts_subagent, I took upstream's version (which had the same always_fail fix). But upstream/main does not carry Motion A's AgentTurnRequest.provider -> turn_model_source / ParentExecutionContext.provider -> turn_model_source rename, so those two upstream files construct the old field and don't compile against this branch. (Latent until the submodule-pin change triggered CI's full-suite fallback, which compiles raw_coverage_all.) Re-wrap both sites in TurnModelSource::new(provider). A full tests/ scan confirms no other old-provider construction sites remain. Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
Summary
Agent,AgentBuilder,ParentExecutionContext,ChatTurnGraph, bothAgentTurnRequests) holdsArc<dyn Provider>— they hold the seam-ownedTurnModelSource. AllProvider-trait handling is confined to the seam + factory, making the Phase-3 router→ModelRegistryswap seam-local. Zero behavior change.ChatModel(OpenHumanBackendModelbridging the dynamic session JWT +thread_id+ billing envelope onto the vendored tinyagentsOpenAiModel) instead of aProviderModel-wrapped host provider.make_crate_local_runtime_chat_model+ crateOpenAiModelcapability toggles (tinyagents#49:with_native_tool_calling/with_vision/with_default_provider_options) so local runtimes (Ollama et al.) can move crate-native without a capability regression. The live dispatch flip is deferred (see Impact).docs/tinyagents-drift-ledger.md) with a full Motion B cutover table; pinsvendor/tinyagentsto1057acf.Problem
The TinyAgents inference migration (#4249) needs the OpenHuman host to stop naming
Box<dyn Provider>end-to-end and target the crate'sChatModel, so the provider stack can be dismantled and the router replaced by the crateModelRegistryin Phase 3. Doing that in one atomic change across the live turn paths (~30 files) is too risky to review or land safely.Solution
Two structural motions, each zero-behavior-change and landed incrementally:
Providerbehind a seam newtype (TurnModelSource); turn paths read capabilities off the built crate models rather thanProvidermethods, with aprovider()escape hatch only at seam-boundary resolution sites.resolves_to_managed_backendso a test-provider override still wins). The generic OpenAI-compat and local-runtime builders are in place; the local-runtime dispatch flip is held for a follow-up because it must re-run thecfg(not(test))verify_session_activegate (see Impact).Submission Checklist
merge_provider_options(non-object override passthrough is the failure case). Host: managed-vs-local routing tests (create_chat_modelmanaged →profile()None, local →ProviderModelSome) + local-runtime builder profile test + existingOpenHumanBackendModeltests.rust-core-coveragejob on the changedinference/provider/*lines; changed lines are exercised by the tests above.## Related— N/A: no matrix feature rows affected.## Related(Improve agent harness with LangGraph-style state machine or Polaris-like architecture #4249 tracker; Complete tinyagents inference migration (Motion B): crate-native provider clients, delete duplicated provider stack #4727 Motion B).Impact
OpenAiCompatibleProvider→ crateOpenAiModel) while preserving JWT resolution,thread_idinjection, and theopenhuman.usagebilling/charged-USD + cached-token envelope. BYOK/local providers are unchanged (still on the hostProviderpath) until the deferred dispatch flip.create_chat_modelwould jump ahead of theverify_session_activegate (custom/local providers require an active OpenHuman session). That gate is#[cfg(not(test))], so no unit test or CI compile-check covers a regression — the flip lands as its own tightly-scoped, verified change. Documented in the drift ledger's Motion B table.Providertrait deletion.Related
1057acf/responsesport);compatible*.rsdeletion once every construction site is crate-backed.AI Authored PR Metadata
Linear Issue
Commit & Branch
feat/inference-crate-provider-cutover034fac338(merge current with upstream/main)Validation Run
pnpm --filter openhuman-app format:check— N/A: noapp/changes.pnpm typecheck— N/A: noapp/changes.cargo test --libmanaged/local routing +crate_openai+openhuman_backend_model; cratecargo test --lib openai::(55 pass).cargo fmtclean; host libcargo check --libgreen on the merged tree (0 errors); CI Rust Quality (fmt, clippy) passed.app/src-taurichanges.Validation Blocked
command:fullcargo test --lib/cargo llvm-covlocallyerror:dev box is shared/contended (concurrent sibling builds, cold target, OOM history) — full local suites unreliable; targeted tests + merged-treecargo check --librun cleanimpact:full-suite + coverage verification delegated to this PR's CIBehavior Changes
Parity Contract
thread_idbody field, billing envelope recovery, temperature semantics, test-provider override precedenceresolves_to_managed_backendmirrors theempty/cloud/openhumandispatch; test override short-circuits before the crate path; the deferred local flip must preserveverify_session_activeDuplicate / Superseded PR Handling
https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
Summary by CodeRabbit