fix(honcho): dialectic lifecycle — defaults, retry, prewarm consumption#12160
Closed
erosika wants to merge 7 commits into
Closed
fix(honcho): dialectic lifecycle — defaults, retry, prewarm consumption#12160erosika wants to merge 7 commits into
erosika wants to merge 7 commits into
Conversation
Several correctness and cost-safety fixes to the Honcho dialectic path after a multi-turn investigation surfaced a chain of silent failures: - dialecticCadence default flipped 3 → 1. PR NousResearch#10619 changed this from 1 to 3 for cost, but existing installs with no explicit config silently went from per-turn dialectic to every-3-turns on upgrade. Restores pre-NousResearch#10619 behavior; 3+ remains available for cost-conscious setups. Docs + wizard + status output updated to match. - Session-start prewarm now consumed. Previously fired a .chat() on init whose result landed in HonchoSessionManager._dialectic_cache and was never read — pop_dialectic_result had zero call sites. Turn 1 paid for a duplicate synchronous dialectic. Prewarm now writes directly to the plugin's _prefetch_result via _prefetch_lock so turn 1 consumes it with no extra call. - Prewarm is now dialecticDepth-aware. A single-pass prewarm can return weak output on cold peers; the multi-pass audit/reconcile cycle is exactly the case dialecticDepth was built for. Prewarm now runs the full configured depth in the background. - Silent dialectic failure no longer burns the cadence window. _last_dialectic_turn now advances only when the result is non-empty. Empty result → next eligible turn retries immediately instead of waiting the full cadence gap. - Thread pile-up guard. queue_prefetch skips when a prior dialectic thread is still in-flight, preventing stacked races on _prefetch_result. - First-turn sync timeout is recoverable. Previously on timeout the background thread's result was stored in a dead local list. Now the thread writes into _prefetch_result under lock so the next turn picks it up. - Cadence gate applies uniformly. At cadence=1 the old "cadence > 1" guard let first-turn sync + same-turn queue_prefetch both fire. Gate now always applies. - Restored query-length reasoning-level scaling, dropped in 9a0ab34c. Scales dialecticReasoningLevel up on longer queries (+1 at ≥120 chars, +2 at ≥400), clamped at reasoningLevelCap. Two new config keys: `reasoningHeuristic` (bool, default true) and `reasoningLevelCap` (string, default "high"; previously parsed but never enforced). Respects dialecticDepthLevels and proportional lighter-early passes. - Restored short-prompt skip, dropped in ef7f315. One-word acknowledgements ("ok", "y", "thanks") and slash commands bypass both injection and dialectic fire. - Purged dead code in session.py: prefetch_dialectic, _dialectic_cache, set_dialectic_result, pop_dialectic_result — all unused after prewarm refactor. Tests: 542 passed across honcho_plugin/, agent/test_memory_provider.py, and run_agent/test_run_agent.py. New coverage: - TestTrivialPromptHeuristic (classifier + prefetch/queue skip) - TestDialecticCadenceAdvancesOnSuccess (empty-result retry, pile-up guard) - TestSessionStartDialecticPrewarm (prewarm consumed, sync fallback) - TestReasoningHeuristic (length bumps, cap clamp, interaction with depth) - TestDialecticLifecycleSmoke (end-to-end 8-turn session walk)
- Revert website/docs and SKILL.md changes; docs unification handled separately - Scrub commit/PR refs and process narration from code comments and test docstrings (no behavior change)
… multi-peer - cli: setup wizard pre-fills dialecticCadence=2 (code default stays 1 so unset → every turn) - honcho.md: fix stale dialecticCadence default in tables, add Session-Start Prewarm subsection (depth runs at init), add Query-Adaptive Reasoning Level subsection, expand Observation section with directional vs unified semantics and per-peer patterns - memory-providers.md: fix stale default, rename Multi-agent/Profiles to Multi-peer setup, add concrete walkthrough for new profiles and sync, document observation toggles + presets, link to honcho.md - SKILL.md: fix stale defaults, add Depth at session start callout
…t discard, empty-streak backoff Hardens the dialectic lifecycle against three failure modes that could leave the prefetch pipeline stuck or injecting stale content: - Stale-thread watchdog: _thread_is_live() treats any prefetch thread older than timeout × 2.0 as dead. A hung Honcho call can no longer block subsequent fires indefinitely. - Stale-result discard: pending _prefetch_result is tagged with its fire turn. prefetch() discards the result if more than cadence × 2 turns passed before a consumer read it (e.g. a run of trivial-prompt turns between fire and read). - Empty-streak backoff: consecutive empty dialectic returns widen the effective cadence (dialectic_cadence + streak, capped at cadence × 8). A healthy fire resets the streak. Prevents the plugin from hammering the backend every turn when the peer graph is cold. - liveness_snapshot() on the provider exposes current turn, last fire, pending fire-at, empty streak, effective cadence, and thread status for in-process diagnostics. - system_prompt_block: nudge the model that honcho_reasoning accepts reasoning_level minimal/low/medium/high/max per call. - hermes honcho status: surface base reasoning level, cap, and heuristic toggle so config drift is visible at a glance. Tests: 550 passed. - TestDialecticLiveness (8 tests): stale-thread recovery, stale-result discard, fresh-result retention, backoff widening, backoff ceiling, streak reset on success, streak increment on empty, snapshot shape. - Existing TestDialecticCadenceAdvancesOnSuccess::test_in_flight_thread_is_not_stacked updated to set _prefetch_thread_started_at so it tests the fresh-thread-blocks branch (stale path covered separately). - test_cli TestCmdStatus fake updated with the new config attrs surfaced in the status block.
…overage - TestDialecticDepth::test_first_turn_runs_dialectic_synchronously: covered by TestSessionStartDialecticPrewarm::test_turn1_falls_back_to_sync_when_prewarm_missing (more realistic — exercises the empty-prewarm → sync-fallback path) - TestDialecticDepth::test_first_turn_dialectic_does_not_double_fire: covered by TestDialecticLifecycleSmoke (turn 1 flow) and TestDialecticCadenceAdvancesOnSuccess::test_empty_dialectic_result_does_not_advance_cadence Both predate the prewarm refactor and test paths that are now fallback behaviors already covered elsewhere.
This was referenced Apr 18, 2026
…wards-compat fallback
Setup wizard now always writes dialecticCadence=2 on new configs and
surfaces the reasoning level as an explicit step with all five options
(minimal / low / medium / high / max), always writing
dialecticReasoningLevel.
Code keeps a backwards-compat fallback of 1 when dialecticCadence is
unset so existing honcho.json configs that predate the setting keep
firing every turn on upgrade. New setups via the wizard get 2
explicitly; docs show 2 as the default.
Also scrubs editorial lines from code and docs ("max is reserved for
explicit tool-path selection", "Unset → every turn; wizard pre-fills 2",
and similar process-exposing phrasing) and adds an inline link to
app.honcho.dev where the server-side observation sync is mentioned in
honcho.md. Recommended cadence range updated to 1-5 across docs and
wizard copy.
ad78217 to
8b477ef
Compare
Collaborator
|
Merged via PR #12419. Your commits were cherry-picked onto current main with authorship preserved in git log. @LeonSGP43's #11434 gateway user_id scoping fix was also included. Thanks for the thorough lifecycle fixes, @erosika! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Chain of correctness and reliability fixes on the Honcho dialectic path. Replaces #9884's lingering gaps and follows up on #10619. Also incorporates @LeonSGP43's #11434 fix for gateway per-user memory scoping.
Closes
user_idignored whenpeer_nameconfigured)Cadence & defaults
dialecticCadencewizard default is2. Setup wizard always writes it; status display and docs show2. Code keeps a backwards-compat fallback of1when the key is unset so existinghoncho.jsonconfigs that predate the setting keep firing every turn on upgrade.if dialectic_cadence > 1:guard letcadence=1fire twice on turn 0 (sync first-turn + same-turn queue).Correctness
prefetch_dialecticwrote toHonchoSessionManager._dialectic_cachebutpop_dialectic_resulthad zero call sites. Turn 1 paid for a duplicate sync.chat(). Prewarm now writes directly toHonchoMemoryProvider._prefetch_resultunder lock; turn 1 consumes without another call.dialecticDepth-aware. Single-pass prewarm on a cold peer often returns thin output; multi-pass audit/reconcile runs at init instead._last_dialectic_turnadvances only when the result is non-empty.queue_prefetchskips when a prior dialectic thread is still in-flight._prefetch_resultunder lock on completion, so the next turn picks it up even when the sync wait timed out.Liveness + observability
timeout × 2is treated as dead so a hung Honcho call can't block future fires._prefetch_resultis tagged with fire-turn; discarded on read if older thandialecticCadence × 2turns.cadence + streak, capped atcadence × 8). Healthy fire resets streak.liveness_snapshot()method. In-process diagnostic with 7 runtime fields.hermes honcho statussurfaces base reasoning level, cap, and heuristic toggle.system_prompt_blocktells the modelhoncho_reasoningacceptsreasoning_levelminimal/low/medium/high/max per call.Restored behavior
9a0ab34c). ScalesdialecticReasoningLevelup on longer queries (+1 at ≥120 chars, +2 at ≥400), clamped atreasoningLevelCap. New config:reasoningHeuristic: bool(defaulttrue) andreasoningLevelCap: string(default"high"; previously parsed but never enforced).ef7f3156).ok/y/thanks/ slash commands short-circuit both injection and dialectic.Setup wizard
minimal,low,medium,high,max). Always writesdialecticReasoningLevel.Multi-peer + observation (@LeonSGP43, cherry-picked #11434)
user_idno longer mutatescfg.peer_name. Threaded throughHonchoSessionManagerasruntime_user_peer_nameand preferred when resolving the user peer. Per-user memory scoping works even when a staticpeerNameis configured.Dead-code purge
HonchoSessionManager.prefetch_dialectic,_dialectic_cache,set_dialectic_result,pop_dialectic_result— all orphaned after the prewarm refactor.Config surface additions
{ "reasoningHeuristic": true, "reasoningLevelCap": "high" }Both optional; defaults preserve behavior.
Test plan
pytest tests/honcho_plugin/ tests/agent/test_memory_provider.py tests/agent/test_memory_user_id.py tests/run_agent/test_run_agent.py— 561 passedTestTrivialPromptHeuristic— short-prompt skipTestDialecticCadenceAdvancesOnSuccess— empty-result retry, thread pile-upTestSessionStartDialecticPrewarm— prewarm consumed, sync fallbackTestReasoningHeuristic— length bumps, cap clampTestDialecticLiveness— stale-thread recovery, stale-result discard, empty-streak backoff, snapshot shapeTestDialecticLifecycleSmoke— end-to-end 8-turn session walkTestHonchoUserIdScoping(@LeonSGP43) — runtime user peer scopingFiles
Plugin code, wizard, docs, 20+ new tests. See commits for per-commit diffs.