Skip to content

perf(agent): orchestrator prompt diet, lead-in before tool calls, plan review off the chat belt - #6436

Merged
senamakel merged 304 commits into
tinyhumansai:mainfrom
senamakel:hermes-prompt-diet
Sep 22, 2026
Merged

senamakel merged 304 commits into
tinyhumansai:mainfrom
senamakel:hermes-prompt-diet

Conversation

@senamakel

@senamakel senamakel commented Sep 22, 2026

Copy link
Copy Markdown
Member

Why

Time-to-first-visible on a plain research question ("help me find a trip to Kashmir") was 43 s, and what appeared was a plan-review card. Same model (openrouter/deepseek/deepseek-v4-flash), same backend, Hermes shows a streamed lead-in in 5–7 s and an answer in ~40 s. Per-call model latency is identical (5–8 s median, 20 s+ tail on OpenRouter's default provider routing); the whole gap was prompt design and flow:

Hermes OpenHuman before OpenHuman after (hermetic)
system prompt 24.2k chars 29.9k hermetic / 34.4k signed-in 8.8k (8.2k without the model-gated block)
tools on the wire 7 · 14.8k chars 31 · 29.4k chars 25 · 21.5k chars
first model response text lead-in + web_search in one message tool calls only lead-in + tool calls allowed
second round trip answer request_plan_review → parked answer

Wire capture: https://claude.ai/artifact/DN2N9229DJ2GHr6c1zeKed

Our own prompt caused it: STYLE.md banned any lead-in ("the user only sees your reply once it is finished", false for streaming chat), prompt.md mandated request_plan_review before any 3+ step work, and ~25k of the 30k was routing prose duplicated in tool descriptions or already enforced by middleware.

What changed

Flow

  • request_plan_review leaves the chat orchestrator's belt (planner/cron agents keep it; agent/plan_review/* untouched). Destructive shell/file actions were already gated by the approval layer.
  • STYLE.md and the tinytools native tool protocol (fix(render): let the native tool protocol allow a lead-in line before tool calls tinytools#15) now allow a one-line lead-in in the same message as the tool calls; never without the call, never as the end of a turn. The web-chat rail already renders it.

Prompt (≤ 8k hermetic, was 29.9k)

  • orchestrator/prompt.md rewritten: ## How you work (five branches), ## Sub-agents, ## Plans, ## Grounding and tool use (merged with evidence-aware synthesis), ## Scheduling and workflows. Deleted everything the middleware/loader enforces (memory-index nag, spawn hierarchy, use_skill authoring refusal) and every "IMPORTANT/MUST" restatement of a tool description.
  • SOUL.md / IDENTITY.md / ROLE.md / STYLE.md shrunk to ~2k combined (brand-voice guardrail kept). Note: render_helpers/workspace_files.rs only re-seeds unmodified workspace copies, so hand-edited installs keep their old text.
  • Generated sections compacted: installed skills, ## Capabilities not in your tool list (grouped per pack), connected integrations + capability questions, MCP servers, date/time, workspace, memory access/remembering; ## Tool Policy Boundary prints a tool count instead of re-listing the belt.
  • ## Remembering no longer names save_preference on the orchestrator (it was pack-stripped from the wire); the memory sections are gated on the post-pack-strip visible set.

Tiering / prompt cache

  • Dynamic builders can declare tiers with PROMPT_TIER_CONTEXT_MARKER / PROMPT_TIER_VOLATILE_MARKER (split_prompt_tiers, PromptSection::build_parts); the orchestrator does, so identity and rules lead the stable tier instead of trailing the factory-added memory sections (which defaulted to Stable; LearnedContext/UserProfile are now Volatile). Grounding and style close the stable tier.
  • TieredPrompt::system_messages() sends two system messages (stable+context, volatile); runtime_session::prepare freezes them as the prefix, resume takes every leading system message, and PromptCacheSegmentMiddleware declares one segment per message. tinyagents (feat(prompt): per-tier system segments and model-family execution guidance tinyagents#183) gives each its own cacheable segment.
  • Model-gated ## Execution discipline (tinyagents prompt::model_guidance) renders only for deepseek/glm/qwen/gpt/grok/… families, not Claude/Gemini.

Tool belt (31 → 25)

  • Removed: request_plan_review, plan_exit (its marker had no consumer; also off planner/code_executor/skill_creator), read_workspace_state (shell does it), update_task (was todo with another default board), retrieve_tool_output (legacy alias of tinyjuice_retrieve; RECOVERY_TOOL_VISIBLE now advertises only the live tool), tinyjuice_retrieve itself when compaction is off.
  • Fixed: todowritetodo on planner/code_executor/task_manager/skill_creator (it resolved to no tool); composio_connect unpacked so the prompt's connect-card route is actually reachable (the composio pack is closed to the orchestrator via planner); spawn_async_subagent's agent_id enum narrowed per session to the parent's [subagents] allowlist; the "use spawn_async_subagent with blocking: true" claim removed (no such argument).
  • Shrunk: todo (1,853 → 1,098 B), spawn_async_subagent, memory_store, resolve_time, shell.category, continue_subagent, use_skill pack summaries, delegate_to_integrations_agent (per-toolkit blurbs capped at 80 chars), every delegate when_to_use (run_code no longer says "Route ANY repo-scoped work here").

tokenjuice compaction off by default (context.compaction_enabled = false, tokenjuice.router_enabled = false; OPENHUMAN_COMPACTION=1 re-enables). The compacted view cost a retrieval round trip more often than it saved context, and every curated belt paid for the retrieve tool's schema. Per-tool caps and the file_read-backed byte backstop stay on.

Instrumentation

  • web_chat/turn_timing.rs: [web_channel][bridge] time-to-first-visible logs first text delta, first tool call, and a turn summary.
  • turn_run_finalize.rs: [tinyagents] turn prompt summary logs system-segment bytes beside input_tokens/cached_input_tokens.
  • scripts/prompt-eval/cases.json: orchestrator-research-trip (must call web_search_tool; must not call request_plan_review/todo/spawn).
  • scripts/prompt-budget.limits ratcheted: orchestrator 30213/30818 → 8821/21523, plus every agent that shares the trimmed sections.

Verification

  • cargo test -p openhuman --lib (RUST_MIN_STACK=16777216): 10467 passed, 77 failed = exactly the 77 that fail on main locally (diffed by name; zero new).
  • cargo test -p openhuman-cli --test agent_prompt_comprehension_e2e: same 5 pre-existing local failures as main (delegation requires a live harness run context); orchestrator_presentation_wiring, orchestrator_parallel_fanout_routing pass.
  • scripts/check-prompt-budget.sh OK after --write; pnpm rust:layout OK (new helpers live in web_chat/turn_timing.rs, session_host/prefix_snapshot.rs, builder/helpers.rs).
  • tinyagents: 1239 harness tests; tinytools: 228 tests.
  • Hermetic openhuman-core agent dump-prompt --agent orchestrator --with-tools: 8,821 B prompt, 25 tools; the wire shows two system messages.

Follow-ups (not in this PR)

  • Backend: forward OpenRouter provider: {sort: "latency"} for openrouter/* to cut the 20 s+ tail.
  • Promote the lead-in from the insights rail to a persistent bubble (ChatRuntimeProvider.tsx onInterim).
  • harness/memory_protocol.rs has no arm for the collapsed memory tool used by wildcard agents.

Depends on tinyhumansai/tinytools#15 and tinyhumansai/tinyagents#183 (gitlinks point at their branch heads).

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

Summary by CodeRabbit

  • New Features

    • Added embedding-based tool search with improved semantic matching and Jev ranking support.
    • Improved sub-agent delegation, continuation, cancellation, and parent-context handling.
    • Added clearer prompt caching and tiered prompt behavior for more efficient sessions.
    • Added web-chat turn timing and performance metrics.
  • Improvements

    • Tool descriptions and agent guidance are shorter and more focused.
    • Conversation history is bounded while preserving essential context.
    • Tool failures now return actionable results instead of stopping the session.
  • Changed Defaults

    • Compaction and routing are now opt-in.
    • Python-style tool calls are now the default format.
  • Removed

    • Retired Rewards screens and functionality.

Round two: merged upstream/main + #6367, vendor bumped to main, defaults flipped

Wire report (capture proxy, same Kashmir question, deepseek-v4-flash via the backend): https://claude.ai/artifact/6c5KAmg6JT1jXe7o1BZv8G

Measured (3 fresh two-turn conversations per dialect)

prompt tok, call 1 tools on wire cache keys / thread cached input turns that called a tool turn 1 called a tool
native (auto) 8,391 25 1 63% 6/6 3/3
python (default) 5,158 0 1 89% 2/6 0/3

Python is 38% cheaper per call and caches better; DeepSeek is more hesitant in it (asks first, sometimes ends a turn on "let me search" with no block — a text dialect has no finish_reason=tool_calls to nudge on). n=3, so a signal, not a measurement. If time-to-useful-answer on the managed DeepSeek route is what matters, tool_dispatcher = "auto" is the one-line revert; python still wins on small local models (#6433 bench).

Tests

  • RUST_MIN_STACK=16777216 cargo test -p openhuman --lib: 10,543 passed; 5 failed, of which fleet_prompt_tests::every_prompt_names_at_least_one_tool_it_can_call, spawn_async_subagent…no_parent_thread and the_withheld_block_renders… fail identically on upstream/main in this environment (verified), composio…no_baked_client is order-dependent (passes in isolation on both), and the fifth was the re-pinned doubled-tag test.
  • pnpm rust:layout reports the same four over-limit files as upstream/main (779/796/752 lines and runtime_session.rs 1992 > 1943); none are from this branch.
  • Prompt budget ratcheted: orchestrator:8858:21523 (+37 B for the tool_search branch).

Depends on tinyhumansai/tinyagents#190 (which bumps tinyhumansai/tinytools#20); the vendor/tinyagents gitlink must move to the merge commit before this merges.

Round three: every progress event was delivered twice

Found while chasing a "the agent forgot the previous turn" report. The wire request was fine (history replayed in full, verified through the capture proxy across a cold-boot resume); what was actually wrong was the progress stream: two producers wrote the turn's AgentProgress channel.

  • OpenhumanEventBridge (subscribed to the run's EventSink on every turn_runner run) projects AgentEvent::ModelDeltaTextDelta, ToolStarted/ToolCompleted → tool rows, etc.
  • OpenHumanProgressSink (the host ProgressSink capability) projected the harness's coarse mirror of the same loop (Token, ToolCall, ToolCallFinished, Finished) onto the same channel. tinyagents started emitting that mirror for every model delta in 977763a4 / 9ce02dc5 (2026-09-19), which is already in upstream's gitlink, so main has this too.

Observable on the client event stream: every text_delta twice with distinct seqs, every tool_call/tool_result twice, two turn_done lines per request, and the interim bubble interleaving the copies ("TheThe resolver couldn't parse that exact phrase, so let resolver couldn't…"). The final bubble looked right only because chat_done carries full_response.

Fix: OpenHumanHostBundleFactory::build no longer hands the turn's live channel to the host sink (crates/openhuman-core/src/agent/tinyagents/host/bundle.rs); the sink stays registered as the capability with an unconsumed channel, the bridge is the single producer. Regression test turn_runner_tests::a_streamed_delta_reaches_the_progress_channel_exactly_once (failed with ["one delta", "one delta"] before). Re-checked on the wire: one event per delta, one row per tool call, one turn_done.

The "forgot the previous turn" itself was not a code path: the desktop process under test had been started at 12:09 from a pre-diet binary (36 KB prompt, 31 tools) and was never relaunched after the 12:14 rebuild, and the user config.toml had tool_dispatcher = "auto" / ranker = "auto" persisted from the old defaults, which override the new ones.

Round four: dependencies landed, #6438 merged in

senamakel and others added 30 commits September 20, 2026 21:21
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…lowup-next

# Conflicts:
#	scripts/ci/agent-runtime-boundary-baseline.json
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…followup-next

# Conflicts:
#	.github/workflows/ci-lite.yml
#	scripts/__tests__/coverage-runner-status.test.mjs
#	scripts/ci/assert-coverage-presence.sh
#	scripts/ci/rust-coverage-changed.sh
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
senamakel and others added 27 commits September 22, 2026 14:12
…tool

Replace the granular per-operation todo tools (TodoListTool, TodoAddTool, etc.) and the separate UpdateTaskTool with a single TodoTool that manages the entire session todo list as a whole-list write, scoped to the conversation thread. This simplifies the tool surface and aligns with the Claude/Codex todo model, removing the cross-thread task update capability that was redundant with the thread-scoped approach.

Auto-committed-on: macbook
…spatch

The update_task tool dispatch registration was removed because the tool is no longer supported or has been replaced by other functionality. This eliminates the unused code path from the tool registration flow.

Auto-committed-on: macbook
Removed a stale doc comment referencing `UpdateTaskTool`, which no longer exists in the codebase. The comment was left over from a previous refactor and would confuse readers by pointing to a nonexistent tool.

Auto-committed-on: macbook
…ledger

The task-sources thread board that mirrored every ingested task as a card has been removed because it was never rendered anywhere and the todo tool now serves as the session's own list. The ingestion ledger in store.rs is now the sole surface for collected tasks, and route_enriched only dispatches a triage turn for proactive sources while collect-only sources stop at the ledger.

Auto-committed-on: macbook
…dger

Remove the card_id column from the ingested_tasks table and all associated logic that tracked board card UUIDs. Tasks are no longer mirrored onto a todo board, so the pipeline no longer needs to look up stale card ids for removal when re-routing edited upstream tasks. The reconciliation path also no longer removes board cards for tasks that have disappeared from the upstream source. The card_id column is left in the schema as NULL to keep older databases open without migration.

Auto-committed-on: macbook
The `card_id` field on `IngestedTaskRef` was never read by any consumer and only added unnecessary memory overhead during task ingestion. Removing it simplifies the struct and eliminates a dead code path.

Auto-committed-on: macbook
…ed export

Renamed the `is_ingested` function to `was_ingested` in the task sources store module to better reflect that it checks whether a task has been ingested at any point in the past, and updated all call sites accordingly. Also removed the unused `TASK_SOURCES_THREAD_ID` re-export from the module's public API to keep the surface clean.

Auto-committed-on: macbook
Removed the `route` module from the import in the task sources ops file, as it was no longer used in that module.

Auto-committed-on: macbook
Updated the test assertion to properly validate the expected routing behavior for task sources, ensuring the test correctly reflects the intended logic and prevents false positives in the test suite.

Auto-committed-on: macbook
Remove the now-unused card identifier argument from the mark_ingested function and update all call sites in the test suite. The card id was previously used to track which board card corresponded to an ingested task, but this association is no longer needed for the deduplication and pruning logic.

Auto-committed-on: macbook
Updated the test assertion to expect the correct boolean value for the completed status of a todo item, ensuring the test accurately reflects the expected behavior of the todo tool.

Auto-committed-on: macbook
The task manager agent no longer owns per-thread todo boards, so all todo-related tools, the associated destructive tool family, and the triage escalation tests that verified card status mutation have been removed. The agent's scope is narrowed to task sources, workflow bundles, and artifacts, with updated descriptions and prompts reflecting this focus.

Auto-committed-on: macbook
…r tool comments

Updated the task_manager_agent archetype description in the registry README to reflect its broader role covering task sources, workflows, and artifacts. Refined the orchestrator agent.toml comments to clarify that the `todo` tool now follows a Claude/Codex-style session todo list model and removed the stale reference to `update_task` from the comment. Also removed an outdated cross-reference to `crate::agent::todos` from the task_sources README, as that module no longer exists.

Auto-committed-on: macbook
…rd card tracking

Update the task sources README to clarify that the pipeline no longer creates todo board cards for ingested tasks, and that the `card_id` column in the database is a leftover from the previous approach. Also remove `update_task` from the agent tools list in the agent README, as it has been removed from the agent-loop control tools.

Auto-committed-on: macbook
The todo tools have been removed from the codebase, so this change cleans up all associated test code and test data. It removes the todo tool entries from the productivity tools lists, the representative tool mapping, and the capability gating tests, as well as deleting the dedicated integration test for todo_add and todo_list through the registry.

Auto-committed-on: macbook
Add the goal_get operation to the representative test mapping, associating it with the Threads domain group to ensure proper test coverage for this operation.

Auto-committed-on: macbook
The durable per-thread task board store and its associated file migration have been removed since nothing rendered the board data and the board tools were already deleted. The module now provides only an in-memory session store keyed by session id, replacing the previous workspace-backed store and scratch thread concept.

Auto-committed-on: macbook
vendor/tinyagents is pinned at 0bc4ec44 (tinyagents main tip, PR tinyhumansai#190
merged), while the merge-base pin (eefef72b) was an ad hoc merge commit
made while resolving PR tinyhumansai#6435 locally and was never pushed to
tinyagents main. It sits on a sibling branch, so the monotonicity gate
sees the two as diverged ("sideways") rather than a clean fast-forward.

Diffing eefef72b against 0bc4ec44 confirms no work is lost: content
unique to eefef72b (ToolRanker/BM25 discovery, the claude_code input
builder, dialect docs) is present in 0bc4ec44 too, just reshaped by
later commits on tinyagents main (net +1617/-151 lines across the
submodule, almost entirely superseding rewrites of the same files).
0bc4ec44 is the correct pin to build against; keep it.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
The todo list scope has been changed from conversation threads to agent sessions, consolidating the per-thread file-backed stores into a single in-memory store keyed by session ID. This simplifies the storage model and ensures the orchestrator's list is correctly scoped to its own session rather than being invisible to the user's thread.

Auto-committed-on: macbook
…ates

Reformat long lines that exceeded the project's line length limit across 15 files, including tool search benchmarks, discovery rankers, tests, and the composio action tool. Also fix import ordering in the jev ranker module. These are purely cosmetic changes with no behavioural impact.

Auto-committed-on: macbook
Updated the subtitle and description strings for task sources across all 14 locales to remove references to the "agent todo board" and instead describe tasks being pulled directly to the agent for triage, making the feature's purpose clearer to users.

Auto-committed-on: macbook
…ariant

Renames the `TodoOnly` variant's doc comment from "append a todo card" to "collect into the ingestion ledger" to accurately reflect that the variant never auto-starts an agent turn. Updates the goals-and-todos documentation to describe the session-scoped todo list and thread goals, removing outdated references to TinyAgents internals and clarifying that neither feature exposes a kanban board or task board RPC endpoints.

Auto-committed-on: macbook
…on key

The translation key `conversations.threadTodo.title` was removed from all 14 locale files because it is no longer referenced in the application code, keeping the translation files clean and up to date.

Auto-committed-on: macbook
The test for capturing the first inference was failing because it was checking for the wrong output format. Updated the expected value to match the actual inference result format returned by the model.

Auto-committed-on: macbook
The test for capturing the first inference was incorrectly asserting the expected output, causing it to fail when run against the actual implementation. The assertion now matches the correct behavior of the capture function.

Auto-committed-on: macbook
The prompt budget limits for morning_briefing, tools_agent, orchestrator, code_executor, task_manager_agent, planner, skill_creator, and the todo tool have been lowered to reflect updated cost measurements, while the use_skill tool limit has been slightly increased.

Auto-committed-on: macbook
Removed the ambiguous phrase "workflow bundles" from the tasks tool pack summary and simplified the description to "workflows" for clarity and accuracy.

Auto-committed-on: macbook
@senamakel
senamakel merged commit a63c2b8 into tinyhumansai:main Sep 22, 2026
16 of 19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant