Skip to content

feat(kernel): host capability adapters, config seam, and the Phase 2 transcript soak - #5396

Merged
senamakel merged 114 commits into
tinyhumansai:mainfrom
senamakel:oh-kernel-tinyagents
Aug 5, 2026
Merged

feat(kernel): host capability adapters, config seam, and the Phase 2 transcript soak#5396
senamakel merged 114 commits into
tinyhumansai:mainfrom
senamakel:oh-kernel-tinyagents

Conversation

@senamakel

@senamakel senamakel commented Aug 4, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds the ten host capability adapters (agent/tinyagents/host/) wiring OpenHuman's domains to the TinyAgents traits landed in feat(harness): host capability traits + crate-owned session config tinyagents#87. Nothing calls them yet — this is the seam, not the switchover.
  • Introduces the crate-owned session config seam: tinyagents::harness::config structs plus a host mapper, so the agent runtime can stop reading Config directly.
  • Threads host config into the sub-agent runner instead of loading it ambiently — Config::load_or_init() is not cached, and run_typed_mode was calling it six times per spawn.
  • Starts the Phase 2 transcript parity soak (session_shadow_reads now defaults ON) and closes the two legacy-shape coverage gaps its exit criteria name.
  • Advances tinyflows to v0.5.1 and tinyagents to main.
  • Fixes a flaky tinyplace test and hardens the archivist ingest tests' isolation.

Problem

src/openhuman/agent/ reaches 45 domains, which blocks making the agent runtime generic (docs/specs/plan-agents.md). The runtime also loaded host config ambiently and in places bypassed guards it should have asked about.

Two latent defects surfaced while building the adapters, both of which compile cleanly and fail silently:

  • A channel RequireApproval verdict resolved to Allow. The mapping returned "no verdict" assuming the call would fall through to the approval park — but the park is only reached from the shell and external-effect branches, so any ordinary tool was authorized with nobody asked. tools::agent_policy::engine files RequireApproval under blocked_tool_names alongside Deny, so this inverted the host's own semantics. Latent only because build_session does not currently emit it.
  • Cross-agent experience records collided. stable_experience_id_for_profile hashes task + tool sequence + outcome + profile and deliberately excludes agent_id; the native capture hook is protected only incidentally by always supplying a real tool sequence. This adapter has none, so two agents recording the same task with the same outcome collided on one id and put upserted — the second writer silently destroying the first's record.

Solution

Adapters live in agent/tinyagents/host/, one per capability, with policy enforced adapter-side (taint, scope, redaction, approval, budget) because the crate deliberately knows nothing about it. Optionality is modelled as absence, never an erroring default — a stub that errors teaches the loop the capability exists and invites a retry.

RequireApproval now routes to the approval park, and denies when no gate is installed. That is the one place this set is stricter than the legacy middleware; the reasoning is argued in the module header rather than left as a surprise. The experience id now folds the agent into the hashed tool-sequence slot.

The sub-agent runner takes one config snapshot per spawn (Result<Arc<Config>, String>, so each site keeps its original failure behaviour) after tier_gate_decision, since load_or_init can initialize config on first run and a rejected spawn should not have that side effect.

session_shadow_reads defaults ON to start the parity soak. It is observation-only: legacy stays authoritative, the probe runs on a background task once per resume, a store-read failure degrades to Unavailable, and OPENHUMAN_SESSION_SHADOW_READS=0 kills it.

Submission Checklist

  • Tests added or updated — 142 adapter tests, 23 config-mapper tests, plus regressions for both defects above (require_approval_never_silently_allows_a_plain_tool) and the two legacy transcript shapes (DDMMYYYY/ and legacy .md)
  • Diff coverage ≥ 80% — confirmed green by the CI gate (Rust Core Coverage (cargo-llvm-cov) + PR CI Gate) rather than measured locally.
  • Coverage matrix updated — N/A: no user-facing feature rows added or removed; this is an internal seam plus a default-flag flip
  • All affected feature IDs listed — N/A: no matrix rows touched
  • No new external network dependencies — and this PR removes two accidental ones: the archivist tree-ingest tests were reaching the managed embedding service and building their own chat provider, ignoring the stub wired into the hook
  • Manual smoke checklist — N/A: no release-cut surface touched
  • Linked issue — N/A: tracked by docs/specs/plan-agents.md, no GitHub issue

Impact

Behaviour change: session_shadow_reads defaults ON. Observation-only and kill-switchable, per above.

Security: the RequireApproval fix is a tightening. If anything begins emitting RequireApproval, tools that previously ran unasked will now prompt, and deny where no approval flow exists.

Desktop/CLI/headless all affected equally (core-side). No migration, no schema change. The ten adapters are additive and currently uncalled, so runtime behaviour is unchanged by them.

Follow-up, recorded in docs/specs/plan-agents.md: repointing agent/ to call these adapters is blocked — four of them need Arc<Config>, which is the Phase 3 blocker, which waits on Phase 2's reader flip, which needs soak data from a shipped release. The plan's Phase 4 exit criterion was also corrected: it read "~2,000 refs" where the measured figure is 295, two-thirds of which is assembly code that becomes the trait impls rather than disappearing.

Related

Depends on tinyhumansai/tinyagents#87 (merged; this PR pins tinyagents main).

Note for reviewers on the test suite

cargo test needs real temp space. This repo's suite plus rustdoc fill a small tmpfs /tmp, and the failures that produces look like unrelated flaky tests (archivist, tinyplace, memory::*, subconscious::monitors) rather than a full disk. With TMPDIR on a real filesystem the suite is 12770 pass / 0 fail across repeated runs.

Summary by CodeRabbit

  • New Features

    • Added TinyAgents integration for agent configuration, model selection, memory, experience recall, security checks, budgeting, progress reporting, and learning.
    • Improved session handling with shared runtime configuration and host capability access.
    • Required-output validation now uses the shared TinyAgents contract.
    • Legacy session shadow reads are enabled by default for compatibility monitoring.
  • Documentation

    • Added design specifications for agent migration, memory architecture, kernel drivers, and transcript handling.
  • Tests

    • Expanded coverage for adapters, session capabilities, configuration mapping, legacy transcript reads, and deterministic offline tree ingestion.

senamakel and others added 14 commits August 2, 2026 16:23
tinyflows main moved 5 commits ahead of the pinned gitlink (declared
workflow inputs, per-item fan-out, and the new memory + dedup node kinds).
Three breakages fixed:

- Capabilities gained a required memory field. Left None: a flow reaching
  user memory is policy-bearing (taint, source_scope, redaction on read;
  writes on remember/forget) and those guarantees live inside the memory
  domain today, so a raw adapter here would route flow traffic around
  them. Wiring waits on the kernel-side guard (docs/specs/kernel.md 3.4).
- WorkflowGraph gained inputs; n8n import has no equivalent, so empty.
- NodeKind match in flows::tools was non-exhaustive.

Withhold memory and dedup from the advertised catalog rather than letting
propose_workflow build graphs that cannot run here. dedup is the subtler
one: the node only stages tentative keys and the crate leaves
commit-on-success to the host, which OpenHuman does not yet do — so it
would dedup within a run but never across runs, silently republishing.
Absence beats a surface that returns a wrong answer.

The count assertion in node_contracts is now derived from the crate
catalog instead of hard-coded, so the next bump surfaces a new kind
rather than failing on a stale 12.

Also lands the Phase 0 trait-catalogue RFC gitlink for tinyagents and the
kernel/agent-move specs.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Host half of plan-agents Phase 3. session_config_from(&Config) plus
apply_team_models / apply_delegate, following the
tinycortex::config::memory_config_from precedent.

Split three ways rather than one flat mapper because OpenHuman's model
pins are not global: Config::teams is keyed by team and Config::agents by
delegate, so 'the model for this session' is only knowable once you know
which agent runs. A single function would have to invent it.

Reads memory limits through resolved_memory_limits() rather than the
legacy max_memory_context_chars scalar — that helper is what applies the
memory_window preset and the hard ceiling, and bypassing it drops both.

Nothing in agent/ is repointed yet; this is the foundation. Measured
surface still to cover: 71 distinct config accesses across 37 production
files.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Phase 3 repointing. harness/required_output.rs is pure logic with no host
domains, so it moves onto tinyagents' RequiredOutput outright; session_io's
enforce_required_output follows, converting at the read site in turn/core.rs.
The 12 existing tests pass unchanged, which is the proof the swap preserves
behaviour.

Splits the mapper into per-section functions (turn_config_from,
tool_config_from, memory_limits_from, apply_agent_config). The session
builder takes a per-agent AgentConfig override, so mapping only from the
global Config would have discarded it and run every agent on the global
limits.

Records what the rest of Phase 3 actually requires. The '37 files' figure
counts host-adapter files that should keep reading Config; the moving set is
~19 files / 41 refs, and 11 of those are Config::load_or_init() — ambient
loads that need config threaded through signatures, not repointed. The
session cannot drop AgentConfig until Phase 2 rehomes session_dual_write /
session_shadow_reads, and a parallel crate config was rejected because
runtime.rs mutates max_tool_iterations after build.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Phase 3 ambient-load threading. Config::load_or_init() is NOT cached — it
re-resolves the config dirs and re-reads config.toml on every call — and
run_typed_mode called it six times, so a single sub-agent spawn hit the disk
six times and could observe six different configs if the file changed
mid-spawn. run_subagent now takes one snapshot and hands it down.

The snapshot is Result<Arc<Config>, String> rather than Option because the
integrations_agent path reports the load error to its caller while the other
five degrade silently; keeping both shapes lets every site preserve its
original failure behaviour exactly. It is taken after tier_gate_decision, since
load_or_init can initialize config on first run and a spawn the tier gate
rejects should not have that side effect.

The sub-agent graph gets the same treatment: build_subagent_context_mw takes
Option<&Config> (and is no longer async), plumbed through run_subagent_via_graph
and a new AgentTurnRequest::config field so the custom-graph path keeps its
[context] knobs instead of silently falling back to defaults. The four graph
tests now pass None, which makes them hermetic — they previously read whatever
config.toml happened to be on the developer's machine.

Scope correction: task_dispatcher/ is NOT in the moving set. plan-agents §3
lists it beside dispatcher.rs mapping to harness::{tool_calling, hooks}, but
that conflates two different modules. dispatcher.rs parses tool calls and is
generic; task_dispatcher/ is a task-CARD board dispatcher reaching task_sources,
threads, web_chat, todos, profiles and scheduler_gate. It stays host-side, so
its three load_or_init calls are correct as they are.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
…tcher split

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Phase 1 landed in the crate; no OpenHuman code consumes them yet (that is
Phase 4). Gitlink bump only.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Phase 2 turned out to be mis-specified and mostly already built.

The plan said 'transcript to crate JsonlChatHistory (transcript spec Option
B)'. No such convergence is in progress. The real target, chosen and
half-shipped under tinyhumansai#4249, is the crate's Store/AppendStore journal at
{workspace}/tinyagents_store/. Building a JsonlChatHistory would have added a
THIRD store beside the legacy JSONL and the one being migrated to.

session_import/ (2452 LOC) already had the importer, the live dual-write
(default ON), and the shadow-read comparison. Only the reader flip (04.2) is
outstanding. Legacy session_raw/*.jsonl stays authoritative for both read and
write; the store is mirror-only. That sequencing was already correct.

Closed the two legacy-shape gaps this phase's own exit criteria name, neither
of which had a test:

- date-grouped session_raw/DDMMYYYY/ must resolve the same store stream as a
  flat transcript. The key is the file stem, so the enclosing directory must
  not change it — if it ever did, every pre-migration session would read as
  Unavailable and the soak would look clean while covering nothing.
- a legacy .md session must read Unavailable, never Divergence. Those predate
  the store so no stream exists; reporting divergence would flood the soak with
  false positives from every old transcript on disk, and the point of a soak is
  that a warning means something.

session_shadow_reads now defaults ON to start the soak. Observation-only:
legacy stays authoritative, the probe runs on a background task once per resume
rather than per turn, a store-read failure degrades to Unavailable, and
OPENHUMAN_SESSION_SHADOW_READS=0 kills it. Worst case is log noise, not a
broken resume.

Deliberately NOT flipping readers. That is bought with soak evidence, and no
evidence exists until a release ships with the probe on.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Phase 4, first half. src/openhuman/tinyagents/host/ implements each crate host
trait against the real OpenHuman domains (~6000 LOC, 140 tests). This is where
policy lives: taint, scope, redaction, approval and egress budget are enforced
on the way in and out of the trait, because the crate deliberately knows
nothing about them.

agent/ does NOT call these yet, so the exit criterion is unmoved at 295 prod
refs in session/. Writing the adapters and repointing the callers are separate
pieces of work; only the first is done.

Two defects fixed at integration, both compiling cleanly and failing silently:

- security_gate: a channel RequireApproval verdict resolved to Allow. The
  mapping returned 'no verdict' assuming the call would fall through to the
  approval park, but the park is only reached from the shell and
  external-effect branches — so any ordinary tool was authorized with nobody
  asked. agent_tool_policy::engine files RequireApproval under
  blocked_tool_names alongside Deny, so this inverted the host's own semantics.
  Latent only because build_session does not currently emit RequireApproval,
  i.e. a trap armed for whoever turns it on. Now parks, and denies when no gate
  exists — the one place this set denies where the legacy middleware allows,
  argued in the module header.
- experience_store: stable_experience_id_for_profile hashes task + tool
  sequence + outcome + profile and excludes agent_id. The native capture hook
  is protected only incidentally by always supplying a real tool sequence; this
  adapter has none, so two agents recording the same task with the same outcome
  collided on one id and put upserted, the second writer destroying the first's
  record. Agent id now folded into the hashed tool-sequence slot.

Also corrected the plan's exit-criterion baseline: it read ~2000 refs, measured
295 in session/ production code.

21 TODO(phase4) markers remain, each naming an unreachable domain surface —
honest gaps rather than stubs pretending to work.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
86 upstream commits, including a large module reorganization. Resolutions:

Flows / tinyflows — took upstream wholesale. Upstream independently did the
same tinyflows bump I had done and then went further: it wires the memory
capability for real (caps/ops.rs `memory: Some(..)`) and adds the dedup
commit-on-success subscriber in flows/bus.rs. My HOST_UNSUPPORTED_NODE_KINDS
gating was a correct interim measure for code where neither was wired; keeping
it now would hide working functionality, so it is gone and all 14 node kinds
are advertised. tinyflows/caps.rs was also split into flows/tinyflows/caps/*
upstream, superseding my one-line edit there.

vendor/tinyflows — took upstream's 548dbe38 over my a918a7a. Same feature line:
"declared workflow inputs" was re-landed unsquashed as five commits plus one
follow-up, so upstream's pin strictly contains mine. I only ever moved that
gitlink, never authored in it, so nothing of mine is lost.

vendor/tinyagents — genuine merge, both sides had work. Mine sat on 4358efe
(RFC, config structs, all_keys, the ten host traits); upstream had advanced 16
commits (providers, embeddings, todos, message, harness fixes). Merged cleanly
because my work is in new modules. 1356 crate tests pass.

Module reorganization — my Phase 4 adapters moved with the tree to
agent/tinyagents/host/ and their imports were remapped: agent_memory ->
memory::agent, memory_store -> memory::store, agent_experience ->
agent::experience, agent_registry -> agent::registry, agent_tool_policy ->
tools::agent_policy, tool_status -> tools::status, cost -> platform::cost,
scheduler_gate -> cron::scheduler_gate, tokenjuice -> inference::tokenjuice,
profiles/context/learning -> agent::*, composio -> integrations::composio,
approval/prompt_injection -> security::*, app_state -> desktop::app_state.

Kept mine, rebased onto upstream's paths: the AgentTurnRequest::config field,
the spawn-wide config snapshot threading in the sub-agent runner, and the
context-middleware config parameter. Upstream had reintroduced
Config::load_or_init() at two of those sites via its own edits; the threaded
snapshot is retained.

One test expectation updated: secrets_are_redacted_before_they_reach_the_store
asserted the lowercase "[redacted]" marker. Upstream's stronger memory-store
scrubber replaces the whole key=value with "[REDACTED]", so the assertion is
now case-insensitive. The security property it guards — the secret must not
survive — was passing throughout and is unchanged.

Also initialized the new vendor/tinyhumans-sdk submodule.

Agent suite: 2363 pass / 0 fail (the previously flaky
profile_allowed_tools_restrict_shared_session_builder is fixed upstream).
Flows 832, adapters 142, session_import 25.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
…bilities

Phase 4 second half. Investigated the repointing and found it blocked rather
than merely hard; landed the one piece that is not.

Four findings, each measured, recorded in docs/specs/plan-agents.md:

1. The exit criterion counts the wrong code. Of 118 non-adapter refs in
   session/, 46 are in builder/ (assembly, which becomes the trait impls),
   16 are field type annotations, 13 are state management. Only turn/'s ~40
   is genuine runtime consumption, so "drive session/ down to the adapter
   layer" cannot happen by repointing — most of those refs ARE that layer.

2. The session distributes handles more than it consumes them. All 11 uses of
   self.memory hand the Arc<dyn Memory> to a collaborator that needs the full
   domain interface, so swapping the field to Arc<dyn AgentMemory> breaks them.

3. No capability trait fits an existing call shape 1:1. ContextComposer returns
   String where the turn needs structured LearnedContextData for its own
   SystemPromptBuilder; ToolOutcomeClassifier's only consumer is
   progress_tracing/, which the plan deletes rather than moves.

4. Four adapters (BudgetGate, ContextComposer, ModelResolver, and the policy
   half of SecurityGate) need Arc<Config>, which the session did not hold — it
   holds AgentConfig plus an optional, misleadingly-named
   integration_runtime_config. That is the Phase 3 blocker, which is blocked on
   Phase 2's reader flip, which is blocked on the parity soak needing a shipped
   release. The program is now gated on elapsed time, not effort.

Unblocked and done here: integration_runtime_config becomes
runtime_config: Option<Arc<Config>> — a first-class shared handle rather than
an integrations-specific one — so those four adapters become constructible
without waiting on Phase 2. Adds runtime_config() and
host_capabilities_available(), plus host_agent_memory() and
host_experience_store() for the two adapters that need only Arc<dyn Memory> and
therefore work on the bare-builder path too.

host_capabilities_available() keeps "this session cannot answer that" distinct
from "the capability failed" — the same absence-versus-failure rule the traits
are built on. Adapters are built on demand rather than stored: a stored handle
could drift from self.memory if the backend were swapped.

Full suite 12770 pass / 0 fail.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
tinyplace — FIXED, root cause understood.

signal_register_encryption_key_fails_at_store_not_params asserted "does not
fail on missing params" by calling unwrap_err(), which assumes the call ALWAYS
fails. That holds only while the process-global signal store is uninitialized;
once any other test in the binary initializes it the call succeeds and
unwrap_err() panics. The property under test is about param validation, which
an Ok satisfies as well as a non-param error, so the assertion now only runs
when there is an error.

Two siblings carried the same latent bug and are fixed too —
signal_register_encryption_key_does_not_leak_key_material calls the very same
handler, and directory_find_by_encryption_key_with_valid_param_fails_at_client
has the identical shape against the directory handler.

archivist — NOT FIXED. Two real isolation defects corrected, but the flake
remains, so this is hardening rather than a fix.

Both defects are genuine: these tests document themselves as hermetic and are
not.

1. test_config_with_tree() claimed to "disable embedding so ingest doesn't fail
   trying to contact Ollama" but set memory_tree.embedding_*, while the tree
   ingest reads memory.embedding_model via
   memory::tinycortex::config::memory_config_from — which defaults to the CLOUD
   model "embedding-v1". So ingest really was calling the managed embedding
   service. Now sets embeddings_provider = "none", which
   memory::tree_e2e_tests::pipeline_works_with_embeddings_disabled pins as the
   route to InertEmbedder.

2. ingest_chat builds its OWN chat provider from Config
   (tinycortex::ingest::context -> scoring_config -> build_chat_provider), so
   it ignored the StubChatProvider wired into the hook. The five tree-ingest
   tests now run inside chat::test_override::with_provider, a task-local hook
   that build_chat_runtime already checks and that nothing was using.

What was ruled out for the archivist flake, so the next attempt does not repeat
it: instrumenting tree_ingest.rs with panics showed that on failing runs the
ingest never returns Err, never sees empty messages, and never reports
chunks_written == 0. The tests fail with "got 0 chunks" while none of those
probes fire, which points at pipe_segment_to_tree not being reached at all —
i.e. the segment boundary not firing — rather than at the ingest itself.

Separately, the suite has a broader population of load-sensitive tests
(memory::chat, memory::ops::documents, subconscious::monitors) that fail
intermittently. An A/B with these changes stashed failed too, so that
population is pre-existing and not caused here.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
…aits

Rebased onto tinyagents main so the PR carried only this work — the previous
pin sat on an unsquashed copy of the provider/embeddings chain that main has
since landed squashed (tinyhumansai#81, tinyhumansai#85, tinyhumansai#86).

tinyhumansai/tinyagents#87 is merged; this pins main (3e1dbea).

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Four needless borrows created by the spawn-wide config snapshot (the bindings
are now &Arc<Config>, so &config re-borrows), and a manual case-insensitive
compare in the experience adapter.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
@senamakel
senamakel requested a review from a team August 4, 2026 12:43

@greptile-apps greptile-apps 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.

senamakel has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 23 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e2b47c7f-12f5-430f-b81a-c008a48919e3

📥 Commits

Reviewing files that changed from the base of the PR and between 9ba475f and 7bf2450.

📒 Files selected for processing (14)
  • src/openhuman/agent/harness/session/runtime.rs
  • src/openhuman/agent/tinyagents/host/agent_memory.rs
  • src/openhuman/agent/tinyagents/host/budget_gate.rs
  • src/openhuman/agent/tinyagents/host/context_composer.rs
  • src/openhuman/agent/tinyagents/host/definition_registry.rs
  • src/openhuman/agent/tinyagents/host/experience_store.rs
  • src/openhuman/agent/tinyagents/host/model_resolver.rs
  • src/openhuman/agent/tinyagents/host/progress_sink.rs
  • src/openhuman/agent/tinyagents/host/security_gate.rs
  • src/openhuman/agent/tinyagents/host/tool_outcome_classifier.rs
  • src/openhuman/config/migrations/enable_session_shadow_reads.rs
  • src/openhuman/config/migrations/mod.rs
  • src/openhuman/config/migrations/mod_tests.rs
  • src/openhuman/config/schema/agent.rs
📝 Walkthrough

Walkthrough

This PR adds four design specification documents for TinyAgents migration planning, implements ten TinyAgents host capability adapters (memory, budget gate, context composer, definition registry, experience store, learning sink, model resolver, progress sink, security gate, tool outcome classifier), a configuration-mapping module, renames session config storage to a shared runtime_config, changes session shadow-read defaults to enabled, and adjusts several tests.

Changes

Architecture Design Specifications

Layer / File(s) Summary
Session transcript migration design
docs/specs/2026-07-28-agent-session-transcript-to-tinyagents-design.md
Documents transcript semantics, comparison with TinyAgents ChatHistory, migration options, execution plan, and risks.
Kernel/driver architecture design
docs/specs/kernel.md
Defines subsystem/driver contracts, capability negotiation, guard enforcement, configuration shape, and rollout roadmap.
Agent runtime migration plan
docs/specs/plan-agents.md
Plans moving agent/ into vendor/tinyagents, covering coupling, phases, adapters, and risks.
Memory subsystem architecture plan
docs/specs/plan-memory.md
Proposes tinycortex-api, capability-based providers, MemoryGuard, and migration workstreams.

Estimated code review effort: 3 (Moderate) | ~25 minutes

TinyAgents Host Adapter Implementation

Layer / File(s) Summary
Required-output contract migration
src/openhuman/agent/harness/required_output.rs, .../session/turn/session_io.rs
Replaces the local RequiredOutputContract with tinyagents' RequiredOutput type across validation, enforcement, and tests.
TinyAgents configuration mapping
src/openhuman/agent/tinyagents/config.rs
Adds functions mapping OpenHuman config into crate-owned SessionConfig, TurnConfig, ToolConfig, MemoryLimits, and RequiredOutput.
Host capability adapters
src/openhuman/agent/tinyagents/host/*.rs
Adds ten adapters implementing TinyAgents host traits: memory, budget, context, definitions, experience, learning, model resolution, progress, security, and tool outcome classification.
Session runtime_config rename and accessors
.../session/types.rs, .../builder/factory.rs, .../builder/setters.rs, .../session/runtime.rs, .../session/runtime_tests.rs, .../session/turn/core.rs, .../session/turn/tools.rs, .../harness/agent_graph.rs
Renames integration_runtime_config to shared runtime_config, adds host capability accessors, and threads config through turn execution.
Subagent graph/runner config sharing
.../subagent_runner/ops/graph.rs, .../subagent_runner/ops/runner.rs
Threads a single loaded Arc<Config> through subagent spawn, memory retrieval, provider resolution, and graph execution.
Session shadow-read default enabled
.../session_import/live.rs, .../session_import/live_tests.rs, src/openhuman/config/schema/agent.rs
Flips session_shadow_reads default to true and adds legacy transcript parity tests.
Test stabilization
.../harness/archivist_tests.rs, src/openhuman/tinyplace/manifest.rs
Adds a deterministic chat-provider stub for tree-ingest tests and relaxes manifest tests to tolerate success.
Vendor submodule bump
vendor/tinyagents
Updates the vendored commit pointer.

Estimated code review effort: 4 (Complex) | ~75 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Session as Agent Session
  participant Resolver as OpenHumanModelResolver
  participant Memory as OpenHumanAgentMemory
  participant SecurityGate as OpenHumanSecurityGate
  participant ProgressSink as OpenHumanProgressSink

  Session->>Resolver: resolve(ModelResolveRequest)
  Resolver-->>Session: ChatModel via StatelessModel
  Session->>Memory: recall(namespace, limit)
  Memory-->>Session: sanitized MemoryEntry list
  Session->>SecurityGate: authorize_tool(ToolCallRequest)
  SecurityGate-->>Session: GateDecision
  Session->>ProgressSink: emit(ProgressEvent)
Loading

Possibly related issues

Possibly related PRs

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

Suggested reviewers: sanil-23

Poem

A rabbit hops through crates anew,
Ten adapters bind the host and crew,
Config now shared in one bright Arc,
Shadow reads glow, no longer dark.
Specs laid out for kernels to grow,
Hop, hop, hooray — watch TinyAgents flow! 🐇✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the host capability adapters, configuration seam, and Phase 2 transcript soak covered by the changes.

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

@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: c7688e6f66

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

Comment thread src/openhuman/config/schema/agent.rs
Comment thread src/openhuman/agent/harness/session/runtime.rs Outdated
api.md was a byte-identical copy of plan-memory.md; delete it and retarget the
three cross-links that still named the pre-rename filenames. The tinyagents RFC
link becomes a URL because the link-check lane checks out without submodules,
so a relative path into vendor/ can never resolve there.

@greptile-apps greptile-apps 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.

senamakel has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

senamakel and others added 10 commits August 4, 2026 18:11
…retrieval

The experience store now imports `retrieve_across_stores` from the experience store module, enabling the host to query experiences across multiple stores rather than being limited to a single store. This change prepares the codebase for broader experience retrieval capabilities.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
The experience store now consults an additional read-only store during recall, matching the live turn path that queries both profile-local and shared workspace stores. This ensures dedicated-profile sessions can still recall records written before profiles existed, while writes remain confined to the profile-local store.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds an optional second store that recall reads from but record never writes to, enabling a shared pre-profile workspace store behind dedicated-profile sessions. The new builder method accepts None as a no-op, preserving single-store behaviour for profile-less sessions.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
…tore.rs

Checkpoint of work in progress, touching src/openhuman/agent/tinyagents/host/experience_store.rs.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
…urn path

The host experience store now writes exclusively to the session's own memory while recall additionally consults the shared experience memory when provided. This mirrors the behavior in the live turn path, ensuring new records stay within the profile-local subtree while old unstamped records from pre-profile builds remain reachable through shared recall.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds a new migration that enables shadow reads for session data, allowing reads to be served from a secondary replica while writes continue to the primary. This improves read scalability without changing the application's write path.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds the new enable_session_shadow_reads migration module to the migrations registry so it is included in the migration set.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
The schema version constant is incremented to reflect the addition of a new migration, ensuring the migration runner processes the newly added migration step.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
…-read parity soak

Adds a schema version 8 to 9 migration that enables `agent.session_shadow_reads` for existing workspaces, since the serde default flipped to `true` but saved configs still carry an explicit `false`. The migration guards on `== 8` to avoid skipping an earlier failed step, and rolls back both the version and the flag if saving fails so the next launch retries cleanly.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Replace hardcoded schema version 8 in migration tests with the CURRENT_SCHEMA_VERSION constant so assertions stay correct as the schema evolves.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
senamakel and others added 2 commits August 5, 2026 01:56
The store now pulls up to five times the configured max hits from the domain before applying the agent filter, so a shared store with several active agents no longer loses quieter agents' experiences. The multiplier is a heuristic rather than a guarantee, and a max_hits of zero still returns nothing to preserve the existing feed-none-back behaviour.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds a regression test ensuring that a busy agent's records cannot crowd out another agent's matching attempts when truncation happens before the agent filter. The test verifies that recall still returns the correct agent's attempts and respects the max_hits bound.

Co-authored-by: Medulla <medulla@tinyhumans.ai>

@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: 409d11b1f2

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

Comment thread src/openhuman/agent/tinyagents/host/definition_registry.rs
senamakel and others added 5 commits August 5, 2026 02:02
Reformatted the test code in the experience store to improve readability by wrapping long function calls and method chains across multiple lines. No behavioral changes were made.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
The module documentation now explains that the ownership filter must run before truncation to `max_hits`, since the domain truncates before the adapter sees the rows. This ensures the limit applies to the current agent's attempts rather than a mixed page.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
…mposer

The context composer now respects the `include_profile` and `include_memory_md` flags supplied through the `with_omissions` wiring, instead of hardcoding both to true. This aligns the seam with the subagent runner's behavior, which derives these from the resolved agent definition's omit flags, allowing per-agent customization of user file inclusion.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
The context composer now accepts explicit flags for whether the user's PROFILE.md and MEMORY.md layers are injected, defaulting to including both. This lets the wiring site apply a specialist definition's omit_profile and omit_memory_md settings, matching the live subagent runner behavior instead of always composing with the main agent's files.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds a regression test verifying that `omit_profile` and `omit_memory_md` definitions are honoured when composing system prompts, ensuring opted-out files are not injected into the context.

Co-authored-by: Medulla <medulla@tinyhumans.ai>

@greptile-apps greptile-apps 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.

senamakel has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

senamakel and others added 10 commits August 5, 2026 02:15
Replace the single shared counter with per-run state keyed by run ID, so concurrent sub-runs no longer corrupt the parent's iteration count or prematurely complete the top-level turn. The first observed run is treated as the root, and only its lifecycle drives the turn-level events.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
The progress sink now maintains per-run state instead of a single global counter, so concurrent runs each get their own iteration count. Tool calls emitted in a parallel batch are grouped into one iteration, preventing overcounting when a model requests multiple tools at once.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
The progress sink previously used a single atomic counter for all runs, which caused incorrect iteration counts and premature turn completion when sub-runs emitted events. It now maintains per-run state in a map, tracking the root run separately so that only the top-level run triggers TurnStarted and TurnCompleted lifecycle events.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Added a RunState struct to track model iteration rounds and tool-call batching, enabling the progress sink to distinguish between consecutive tool calls within a single model response and separate iterations.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
The module documentation now explains that iteration counts are derived per run, with a batch of consecutive tool calls forming one iteration and model output closing the batch. It also documents that a single sink may serve multiple concurrent runs, with counters keyed by run ID, and clarifies why no tool completion events are emitted.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
The documentation comment contained a corrupted phrase where "每 call" appeared instead of "every call". This fixes the typo to restore clarity in the explanation of iteration counting behavior.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Reformats two chained method calls in the progress sink to use multi-line formatting for improved readability, with no behavioral changes.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
The round counter was incremented per tool call, so two tools requested in a single model response were reported as separate iterations. Now all tool calls within one LLM iteration share the same iteration number, and a new iteration only begins after model output.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
The comment in the test was updated to use English instead of Russian, clarifying the iteration numbering for the model's reply.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add tests ensuring a child run's finish does not surface as the request's completion and that child tool calls do not advance the parent's iteration counter, preserving correct turn and iteration semantics on shared sinks.

Co-authored-by: Medulla <medulla@tinyhumans.ai>

@greptile-apps greptile-apps 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.

senamakel has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@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: 7bf24506e3

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

Comment thread src/openhuman/agent/tinyagents/host/experience_store.rs
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. memory Memory store, memory tree, recall, summarization, and embeddings in src/openhuman/memory/. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant