Skip to content

feat(inference): Phase 3 P3-B — crate-native turn path + delete compatible*.rs [WIP]#4784

Merged
senamakel merged 74 commits into
tinyhumansai:mainfrom
senamakel:feat/inference-phase3b-turnpath-cutover
Jul 13, 2026
Merged

feat(inference): Phase 3 P3-B — crate-native turn path + delete compatible*.rs [WIP]#4784
senamakel merged 74 commits into
tinyhumansai:mainfrom
senamakel:feat/inference-phase3b-turnpath-cutover

Conversation

@senamakel

@senamakel senamakel commented Jul 11, 2026

Copy link
Copy Markdown
Member

DRAFT — WIP. This is the single Phase 3 P3-B PR, built incrementally with CI
as the verification loop (the shared dev box OOMs on local builds). It is not
ready
until the hot turn path is crate-native and compatible*.rs is deleted;
I'll mark it ready then. Reviewing now is welcome but the diff will grow.

Goal (issue #4249, Phase 3 P3-B)

Route the agent turn path off the host OpenAiCompatibleProvider
(compatible*.rs, a Box<dyn Provider> wire client) onto the vendored
tinyagents crate's native ChatModels, then delete compatible*.rs (~430KB).
create_chat_model_with_model_id already returns crate-native models (managed →
OpenHumanBackendModel, local/cloud → crate OpenAiModel); the turn path is the
last big consumer still on the Provider path.

Landed so far

  • Step 1 — managed charged-USD parity (billing bug fix). The crate-native
    managed model left the openhuman.{billing,usage} envelope only on
    ModelResponse.raw, so the seam's usage_info_from_response recovered $0
    charged
    + dropped backend cached tokens — a latent underbilling bug already
    live for one-shot managed callers (memory/chat.rs, meeting/checkpoint
    summaries). OpenHumanBackendModel::project_managed_usage now re-projects
    charged-USD + context window into the openhuman_usage_meta shape the cost
    bridge reads, and backfills crate Usage.cache_read_tokens. Verified:
    cargo check --lib clean; unit tests added.

Planned increments (each pushed for CI)

  1. Crate-native TurnModelSource/build_turn_models (per-tier models, caps
    derived without a Provider).
  2. Flip producers lowest-blast-radius first (sub-agent extract → triage →
    sub-agent runner → channels → root session builder).
  3. Migrate remaining direct OpenAiCompatibleProvider::new sites + one-shot
    create_chat_provider callers.
  4. Delete compatible*.rs; mark ready.

Known parity notes (deferred to the dedicated live-test run)

  • Streaming billing: the crate SSE parser sets raw: None on the terminal
    chunk, so streaming managed turns fall back to the catalog cost estimate
    (token counts survive; authoritative charged-USD needs an upstream crate change
    to preserve the final chunk raw). Non-streaming invoke is fully correct.
  • Error kind tags: crate-native models surface TinyAgentsError, so the
    DomainEvent::AgentError kind tag softens for provider failures. Sentry
    suppression is unaffected (both skips_sentry cases —
    MaxIterationsExceeded, EmptyProviderResponse — are raised in the host turn
    loop, not via the model). A lightweight ProviderErrorAgentError classifier
    can restore kind tags if wanted.

https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB

Summary by CodeRabbit

  • New Features

    • Improved support for native tool calling across supported models.
    • Enhanced streaming responses, including text, reasoning, tool-call updates, and usage details.
    • Expanded support for local and cloud model routes, including custom inference endpoints.
    • Added more consistent model and provider selection for agents, sub-agents, triage, and summaries.
  • Bug Fixes

    • Improved error propagation and clearer, safer inference error messages.
    • Fixed usage and billing metadata handling for managed backend responses.
    • Improved handling of streamed summaries and incomplete model responses.

…e path (P3-B step 1)

The crate-native managed model (OpenHumanBackendModel) delegates to a crate
OpenAiModel whose parse_response leaves the `openhuman.{billing,usage}` envelope
only on ModelResponse.raw — it has no field for charged USD — so the seam's
usage_info_from_response (which reads the `openhuman_usage_meta` key ProviderModel
writes) recovered $0 charged + dropped backend cached tokens. This is a latent
underbilling bug already live for one-shot managed callers (memory/chat.rs,
meeting/checkpoint summaries) and would extend to every interactive turn once the
turn path goes crate-native.

- model.rs: add merge_openhuman_usage_meta — the symmetric writer for
  usage_info_from_response, stashing charged-USD + context window under
  OPENHUMAN_USAGE_META_KEY on the response raw (no-op when both are zero).
- openhuman_backend_model.rs: project_managed_usage reads the openhuman envelope
  off raw, re-projects charged-USD + context window into openhuman_usage_meta, and
  backfills crate Usage.cache_read_tokens from the (authoritative) envelope count
  when the standard parse produced none. Applied on the invoke path.
- Streaming: documented parity gap — the crate SSE parser sets raw:None on the
  terminal Completed, so streaming managed turns fall back to the catalog cost
  estimate (token counts survive); restoring authoritative charged USD for
  streaming needs the crate to preserve the final chunk raw (tracked upstream).
- Tests: project_managed_usage recovers charged/cached/window; no-op without envelope.

Part of Phase 3 P3-B (turn-path crate-native cutover, tinyhumansai#4249). Local full builds
OOM on the shared box; verification defers to CI.

Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 01762f50-71d6-49e6-9d7d-275a77bd00f7

📥 Commits

Reviewing files that changed from the base of the PR and between a67d6a5 and bdad55c.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • app/src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (85)
  • src/bin/inference_probe.rs
  • src/openhuman/agent/harness/graph.rs
  • src/openhuman/agent/harness/session/builder/factory.rs
  • src/openhuman/agent/harness/session/builder/setters.rs
  • src/openhuman/agent/harness/session/turn/core.rs
  • src/openhuman/agent/harness/session/turn/session_io.rs
  • src/openhuman/agent/harness/subagent_runner/extract_tool.rs
  • src/openhuman/agent/harness/subagent_runner/mod.rs
  • src/openhuman/agent/harness/subagent_runner/ops/graph.rs
  • src/openhuman/agent/harness/subagent_runner/ops/mod.rs
  • src/openhuman/agent/harness/subagent_runner/ops/provider.rs
  • src/openhuman/agent/harness/subagent_runner/ops/runner.rs
  • src/openhuman/agent/tools/delegate.rs
  • src/openhuman/agent/triage/evaluator.rs
  • src/openhuman/agent/triage/evaluator_tests.rs
  • src/openhuman/agent/triage/routing.rs
  • src/openhuman/channels/context.rs
  • src/openhuman/channels/routes.rs
  • src/openhuman/channels/routes_tests.rs
  • src/openhuman/channels/runtime/dispatch/processor.rs
  • src/openhuman/channels/runtime/startup.rs
  • src/openhuman/channels/runtime/test_support.rs
  • src/openhuman/channels/tests/context.rs
  • src/openhuman/channels/tests/discord_integration.rs
  • src/openhuman/channels/tests/memory.rs
  • src/openhuman/channels/tests/runtime_dispatch.rs
  • src/openhuman/channels/tests/runtime_tool_calls.rs
  • src/openhuman/channels/tests/telegram_integration.rs
  • src/openhuman/inference/http/server.rs
  • src/openhuman/inference/local/lm_studio.rs
  • src/openhuman/inference/local/mod.rs
  • src/openhuman/inference/local/ollama.rs
  • src/openhuman/inference/local/ops.rs
  • src/openhuman/inference/ops.rs
  • src/openhuman/inference/provider/auth.rs
  • src/openhuman/inference/provider/compatible.rs
  • src/openhuman/inference/provider/compatible_dump.rs
  • src/openhuman/inference/provider/compatible_helpers.rs
  • src/openhuman/inference/provider/compatible_parse.rs
  • src/openhuman/inference/provider/compatible_provider_impl.rs
  • src/openhuman/inference/provider/compatible_repeat.rs
  • src/openhuman/inference/provider/compatible_request.rs
  • src/openhuman/inference/provider/compatible_stream.rs
  • src/openhuman/inference/provider/compatible_stream_native.rs
  • src/openhuman/inference/provider/compatible_tests.rs
  • src/openhuman/inference/provider/compatible_timeout.rs
  • src/openhuman/inference/provider/compatible_types.rs
  • src/openhuman/inference/provider/crate_openai.rs
  • src/openhuman/inference/provider/crate_provider.rs
  • src/openhuman/inference/provider/factory.rs
  • src/openhuman/inference/provider/factory_tests.rs
  • src/openhuman/inference/provider/legacy_provider.rs
  • src/openhuman/inference/provider/mod.rs
  • src/openhuman/inference/provider/openhuman_backend.rs
  • src/openhuman/inference/provider/openhuman_backend_model.rs
  • src/openhuman/inference/provider/ops/provider_factory.rs
  • src/openhuman/inference/provider/ops_tests.rs
  • src/openhuman/learning/linkedin_enrichment.rs
  • src/openhuman/memory_tree/tree_runtime/ops.rs
  • src/openhuman/rhai_workflows/bridge.rs
  • src/openhuman/rhai_workflows/ops.rs
  • src/openhuman/routing/factory.rs
  • src/openhuman/threads/ops.rs
  • src/openhuman/tinyagents/convert.rs
  • src/openhuman/tinyagents/embeddings.rs
  • src/openhuman/tinyagents/middleware.rs
  • src/openhuman/tinyagents/mod.rs
  • src/openhuman/tinyagents/model.rs
  • src/openhuman/tinyagents/payload_summarizer.rs
  • src/openhuman/tinyagents/tests.rs
  • src/openhuman/tinyagents/tools.rs
  • src/openhuman/tinyflows/caps.rs
  • tests/agent_harness_e2e.rs
  • tests/inference_provider_e2e.rs
  • tests/raw_coverage/inference_agent_raw_coverage_e2e.rs
  • tests/raw_coverage/inference_compatible_admin_leftovers_raw_coverage_e2e.rs
  • tests/raw_coverage/inference_compatible_admin_round25_raw_coverage_e2e.rs
  • tests/raw_coverage/inference_compatible_matrix_raw_coverage_e2e.rs
  • tests/raw_coverage/inference_local_admin_raw_coverage_e2e.rs
  • tests/raw_coverage/inference_provider_admin_round22_raw_coverage_e2e.rs
  • tests/raw_coverage/inference_provider_raw_coverage_e2e.rs
  • tests/raw_coverage/inference_round26_raw_coverage_e2e.rs
  • tests/raw_coverage/memory_threads_raw_coverage_e2e.rs
  • tests/raw_coverage/owned_domain_raw_coverage_e2e.rs
  • vendor/tinyagents

📝 Walkthrough

Walkthrough

This PR migrates inference and agent execution toward TinyAgents crate-native chat models, adds provider compatibility adapters, defers production provider construction, updates channel and triage routing, and revises streaming, tool-call, usage, and error handling across consumers and tests.

Changes

Crate-native inference foundation

Layer / File(s) Summary
Model factories and provider adapters
src/openhuman/inference/provider/*
Adds crate-backed model construction, managed usage projection, native tool configuration, and a legacy OpenAI-compatible facade delegating to crate-native models.
Turn model source migration
src/openhuman/tinyagents/*, src/openhuman/agent/harness/*
Allows turn and summarizer models to be crate-native, makes model construction fallible, and updates sub-agent and session wiring.
Channel and triage routing
src/openhuman/channels/*, src/openhuman/agent/triage/*
Defers production provider construction, carries runtime configuration, and routes turns through TurnModelSource.
Inference consumers
src/openhuman/inference/http/*, src/openhuman/tinyflows/*, src/openhuman/threads/*, src/openhuman/agent/tools/*
Uses ModelRequest, ChatModel::invoke, and streaming model APIs for inference, delegation, titles, and workflow completions.
Regression coverage
tests/*, src/openhuman/inference/provider/factory_tests.rs
Updates streaming, tool-call, usage, routing, fallback, and error expectations for the new model paths.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ChannelRuntime
  participant TurnModelSource
  participant ChatModel
  participant ProviderAdapter
  ChannelRuntime->>TurnModelSource: build turn models
  TurnModelSource->>ChatModel: create crate-native model
  ChatModel->>ProviderAdapter: invoke or stream ModelRequest
  ProviderAdapter-->>ChatModel: response and usage
  ChatModel-->>ChannelRuntime: text, tool calls, and metadata
Loading

Possibly related PRs

Suggested labels: feature, rust-core, agent, working

Suggested reviewers: m3ga-mind, sanil-23

Poem

I’m a rabbit with models in tow,
Through native turn paths they now flow.
Tools hop through the stream,
Usage shines like a dream,
While old provider bridges still glow.


Comment @coderabbitai help to get the list of available commands.

senamakel added 28 commits July 11, 2026 05:59
…native turn builder (P3-B step 2 foundation)

The per-(role, explicit-model) analogue of create_chat_model_with_model_id, for
the crate-native TurnModelSource to build the primary + each workload-tier route
without a host Provider. Managed -> OpenHumanBackendModel pinned to the model
(backend resolves the tier from request.model); local/cloud -> crate builders;
bespoke (claude-code) -> ProviderModel over the resolved Provider. Respects the
test-provider override. Additive (allow(dead_code)) — wired into
TurnModelSource::build in the next increment.

Part of Phase 3 P3-B (tinyhumansai#4249). Draft PR tinyhumansai#4784.

Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
…e opt-in (P3-B step 2)

TurnModelSource gains an optional crate_native (role, Arc<Config>): when set,
build()/build_summarizer() construct the tiered TurnModels crate-natively via
build_turn_models_crate (per-tier factory::create_turn_chat_model) instead of
wrapping one host Provider in ProviderModels. The source still holds the resolved
provider, used as (a) the escape-hatch for sub-agent inheritance / rhai and (b) a
graceful fallback if crate-native construction fails — so producers can flip to
new_crate_native one at a time without regressing behavior.

build_turn_models_crate derives the harness-visible caps without a Provider:
native_tools/supports_vision from the primary ModelProfile (managed backend,
profile None, falls back to true / oh_tier_supports_vision(model)); provider_id
from the resolved slug (managed for the backend); error_slot empty (crate-native
surfaces TinyAgentsError directly — Sentry suppression is unaffected since both
skips_sentry cases are host-loop-raised). Unbuildable tiers are skipped, not fatal.

No producer flipped yet (new_crate_native is allow(dead_code)); the build/summarizer
dispatch + fallback land first so the next increment can flip producers behind a
verified path. cargo check --lib clean. Draft PR tinyhumansai#4784.

Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
…3-B step 3, producer 1/7)

First producer cutover: the sub-agent extract summarizer now builds its
TurnModelSource via new_crate_native("summarization", cfg) when config loads, so
build_summarizer constructs a crate-native ChatModel (managed -> OpenHumanBackendModel)
instead of a ProviderModel. The resolved provider is retained for the escape-hatch
+ crate-native-failure fallback; a config-load failure degrades to the parent
provider on the Provider path (unchanged). Lowest-blast-radius producer (internal
extraction, no interactive Sentry path). new_crate_native is now live (allow(dead_code)
removed). cargo check --lib clean. Draft PR tinyhumansai#4784.

Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
…serving tinyhumansai#1257 (P3-B step 3, producer 2/7)

The triage turn now builds crate-native models for the remote/managed arm via
TurnModelSource::new_crate_native_from_string, preserving the tinyhumansai#1257 "triage never
goes local" invariant: build_remote_provider's effective provider string (openhuman
when force-managed) rides through a new primary override so build() resolves the
managed backend rather than re-deriving from the role (which could go local).

- factory::create_turn_chat_model_from_string(role, provider_string, config, model,
  temp): managed when the string is openhuman/empty/cloud (-> OpenHumanBackendModel
  pinned to model); else delegates to create_turn_chat_model. Respects test override.
- CrateNativeSource gains primary_override: Option<String>; new_crate_native_from_string;
  build_turn_models_crate uses it for the primary + summarizer (routes unchanged).
- ResolvedProvider gains crate_native: Option<(effective_string, Arc<Config>)> — Some
  for the remote/managed arm, None for the local arm (kept on the Provider path so it
  doesn't silently route to the managed backend and defeat the local fallback).
- Evaluator flips on resolved.crate_native; resolved provider retained as escape-hatch
  + crate-native-failure fallback.

cargo check --lib clean. Draft PR tinyhumansai#4784.

Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
…sai#55 prompt-guided tools)

Pulls in tinyagents#55 (prompt-guided/text-mode tool calling for non-native
models) + the v1.9.0 release. Unblocks flipping LOCAL runtimes to crate-native on
the turn path: they force native_tools=false and now get prompt-guided tools from
the crate instead of losing tool calls. Host lib compiles clean against 1.9.0.

Part of Phase 3 P3-B (tinyhumansai#4249). Draft PR tinyhumansai#4784.

Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
…age e2e (P3-B fix)

The triage flip added ResolvedProvider.crate_native; cargo check --lib doesn't
compile tests/ integration targets, so the 4 mock ResolvedProvider constructors in
tests/raw_coverage/inference_agent_raw_coverage_e2e.rs (globbed into the
raw_coverage_all target) were missed and broke the full-suite CI on the pin-bump
push. Added crate_native: None (mocks stay on the Provider path). Verified via
cargo check --test raw_coverage_all.

Draft PR tinyhumansai#4784.

Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
…r (P3-B)

The extract flip (producer 1/7) re-resolved "summarization" from config via
create_turn_chat_model, bypassing the extract's already-resolved provider — incl.
a test-injected mock the raw_coverage e2e observes (extraction_prompts()). Full
suite went red: integrations_text_mode_handoffs_oversized_result_and_extracts_from_cache
"got 0 prompts". Production stays managed either way, but a producer that injects/
resolves a SPECIFIC provider must keep it on the Provider path (or pass an effective
string via new_crate_native_from_string, like triage) — plain new_crate_native
role-resolves and drops the injected provider.

Extract now stays TurnModelSource::new(extract_provider). new_crate_native (plain)
is allow(dead_code) until the session-builder flip. Verified: the exact failing
test now passes (cargo test --test raw_coverage_all --features e2e-test-support).

Draft PR tinyhumansai#4784.

Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
…P3-B, producer 3)

The production main-turn agent now builds crate-native ChatModels from
(provider_role, config) via create_turn_chat_model instead of a ProviderModel-
wrapped provider (managed -> OpenHumanBackendModel, local -> crate OpenAiModel w/
prompt-guided tools, cloud -> crate OpenAiModel native).

- setters.rs: AgentBuilder::crate_native_provider(provider, role, Arc<Config>) —
  new_crate_native source; the plain .provider() setter (Provider path) stays for
  tests that inject a mock they observe.
- factory.rs:1144: .provider(provider) -> .crate_native_provider(provider,
  provider_role, Arc::new(config.clone())).
- EXACT metadata parity: build_turn_models_crate now takes provider_id/native_tools/
  supports_vision as params, derived in TurnModelSource::build from the RETAINED
  provider (self.provider.telemetry_provider_id/supports_native_tools/supports_vision)
  — the SAME source build_turn_models uses — so these fields are byte-identical to
  the Provider path (fixes the supports_vision divergence); only the MODELS go
  crate-native. Sub-agents inherit the retained provider via the escape-hatch
  (Provider path, unaffected). Crate-native-build failure falls back to the Provider
  path.

Safe for tests: e2e/raw_coverage tests build agents via Agent::builder().provider(mock)
directly (Provider path) or TurnModelSource::new(provider); NONE drive the production
factory, so the flip is not reachable from them. Live per-provider validation deferred
to the dedicated tinyagents run. Compiles clean (lib + raw_coverage_all).

Draft PR tinyhumansai#4784.

Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
…rness_e2e (P3-B)

The session-builder flip (2528fa0) broke ~14 tests/agent_harness_e2e.rs turn
tests: they drive the production factory (factory.rs:1144) via the harness/SSE
flow and inject a ScriptedProvider NOT through test_provider_override, so
create_turn_chat_model's override guard doesn't catch it — the crate-native
re-resolution builds a real managed model (no backend) -> no SSE events -> timeout.
Reverted factory.rs:1144 to .provider(provider). Kept (allow(dead_code)): the
metadata-parity refactor, crate_native_provider setter, new_crate_native. Restores
tinyhumansai#4784 to green (triage flip + infrastructure intact).

Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
…2e mock (P3-B, producer 3)

Adds SSE streaming to the agent_harness_e2e scripted upstream mock (serves
text/event-stream data: choices[].delta chunks + [DONE] when stream:true, matching
the crate OpenAiModel::stream parser; both old + crate paths parse real SSE), which
was the blocker: the crate streaming path needs real SSE but the mock only returned
JSON. Re-flips factory.rs:1144 to .crate_native_provider so the main interactive
turn builds crate-native models (managed->OpenHumanBackendModel etc.) with metadata
parity from the retained provider.

Verifying at the end per the full-cutover plan.

Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
ChannelRuntimeContext gains config: Option<Arc<Config>> (Some in production via
start_channels; None in tests keeps the Provider path). The channel turn builds
crate-native models via new_crate_native_from_string("chat", route.provider, config)
when config is present; the cached provider is retained for the escape-hatch +
fallback + metadata parity. cargo check --lib clean (all 24 ChannelRuntimeContext
sites carry the new field).

Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
Pins tinyagents#56 (OpenAiModel::stream falls back to parsing a non-SSE JSON body
as one completion) so the crate-native turn cutover works against OpenHuman's
JSON-only e2e mocks. Pinned to the branch commit (the vendored [patch] path build
resolves it directly; no crates.io release needed).

Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
…roducer 5)

Both sub-agent graph paths (default + custom) build a crate-native subagent_source:
a workload Hint -> that role; any other spec (Inherit/Exact/override) reuses the
parent's role via TurnModelSource::crate_native_role() when the parent is
crate-native. Resolved provider retained for fallback + metadata parity; falls back
to the Provider path when no role is derivable / config load fails. Completes the
turn-producer cutover (session, channels, triage, sub-agent all crate-native).
cargo check --lib clean.

Claude-Session: https://claude.ai/code/session_01U8NDGbt9tKj443VquzycLB
@senamakel senamakel marked this pull request as ready for review July 13, 2026 04:24
@senamakel senamakel requested a review from a team July 13, 2026 04:24
@senamakel senamakel merged commit c58fe10 into tinyhumansai:main Jul 13, 2026
15 of 16 checks passed
@coderabbitai coderabbitai Bot added agent Built-in agents, prompts, orchestration, and agent runtime in src/openhuman/agent/. feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. working A PR that is being worked on by the team. labels Jul 13, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bdad55cf70

ℹ️ 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".

}
// A concrete non-managed string equals the role's resolution (triage only
// honours a BYOK **cloud** route as-is), so the role-based builder matches.
create_turn_chat_model_with_native_tools(role, config, model, temperature, native_tool_calling)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Honor explicit turn provider overrides

When new_crate_native_from_string is used with a concrete non-managed provider string, this branch discards that string and rebuilds from provider_for_role(role, config) instead. That breaks callers whose effective provider intentionally differs from the role default: for example build_local_provider_with_config passes ollama:<local_ai.chat_model_id> for the triage local-fallback arm, but the actual turn is built from the subconscious route again, so cloud budget/unhealthy fallback can hit the same remote provider instead of the configured local model.

Useful? React with 👍 / 👎.

tinyagents::harness::model::ModelRequest::new(vec![
tinyagents::harness::message::Message::user(message.to_string()),
])
.with_model(default_model.clone())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use the resolved provider model for simple chat

For openhuman.agent_chat_simple with a BYOK/local chat_provider such as ollama:llama3 or openai:gpt-4o, create_chat_model_with_model_id returns that concrete resolved_model, but this request overrides the model with default_model (often a managed tier like reasoning-v1). Since ModelRequest.model overrides the model baked into the crate OpenAI client, these calls can send an invalid managed-tier id to the user's selected provider instead of the configured provider model.

Useful? React with 👍 / 👎.

oxoxDev added a commit to oxoxDev/openhuman that referenced this pull request Jul 13, 2026
…sai#4436)

The S2 egress emit was wired only into the legacy Provider path
(create_chat_provider_from_string). Post-tinyhumansai#4784 real agent turns build via the
crate-native ChatModel/turn path (create_chat_model_with_model_id and the
create_turn_chat_model* family), whose managed / local-runtime / BYOK-cloud
sub-paths return early WITHOUT touching the Provider path — so the default
managed chat turn disclosed no egress (confirmed by an inference-probe smoke on
staging firing zero events).

Emit at the three universal construction chokepoints shared by every ChatModel
and turn entry, guaranteeing exactly one descriptor per construction:
- managed backend  -> resolve_managed_backend (external); the sole funnel for
  the Provider AND ChatModel/turn managed builds. emit_inference_egress now
  skips PROVIDER_OPENHUMAN so the Provider path doesn't double-emit.
- local runtime    -> try_create_local_runtime_chat_model_from_string, past the
  non-local return + gates (disclosed as NON-external, no pending event).
- BYOK cloud slug  -> try_create_cloud_slug_chat_model_from_string_with_native_tools,
  past the managed/bespoke/OpenhumanJwt returns + gates (external).

The Provider path's top-level emit still covers its direct callers and the
bespoke fallthrough; the two paths are mutually exclusive per construction.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent Built-in agents, prompts, orchestration, and agent runtime in src/openhuman/agent/. feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant