Skip to content

fix(honcho): dialectic lifecycle, gateway scoping, provider opt-in#12419

Merged
kshitijk4poor merged 9 commits into
mainfrom
salvage/honcho-dialectic-lifecycle
Apr 19, 2026
Merged

fix(honcho): dialectic lifecycle, gateway scoping, provider opt-in#12419
kshitijk4poor merged 9 commits into
mainfrom
salvage/honcho-dialectic-lifecycle

Conversation

@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Summary

Salvage of #12160 (Erosika) + #12318 (helix4u) + cherry-picked #11434 (LeonSGP43) onto current main.

What this PR does

Honcho dialectic lifecycle fixes (PR #12160 by @erosika, cherry-picked #11434 by @LeonSGP43):

Chain of correctness and reliability fixes on the Honcho dialectic path:

  • Prewarm consumption fix — session-start prefetch_dialectic() wrote to _dialectic_cache but pop_dialectic_result() had zero call sites. Prewarm now writes directly to _prefetch_result so turn 1 consumes it without a duplicate .chat() call. Dead code purged (prefetch_dialectic, _dialectic_cache, set_dialectic_result, pop_dialectic_result).
  • Cadence advances only on success_last_dialectic_turn now moves only when the result is non-empty, so empty returns (transient API error, sparse representation) retry on the next eligible turn instead of burning the cadence window.
  • Gateway user_id scoping (@LeonSGP43, fix(honcho): scope gateway sessions by runtime user id #11434) — gateway user_id no longer mutates cfg.peer_name. Threaded as runtime_user_peer_name through HonchoSessionManager, preferred in get_or_create(). Fixes [Bug]: Honcho memory scoping ignores gateway user_id when peer_name is configured #11199.
  • Stale-thread watchdog — prefetch thread older than timeout × 2 treated as dead so a hung Honcho call can't block future fires.
  • Stale-result discard — pending result older than cadence × 2 turns is dropped on read.
  • Empty-streak backoff — consecutive empty returns widen effective cadence (cadence + streak, capped at cadence × 8).
  • Trivial prompt skip — "ok", "y", "thanks", slash commands short-circuit both injection and dialectic.
  • Query-length reasoning heuristic (restored) — scales dialecticReasoningLevel by query length (+1 at ≥120 chars, +2 at ≥400), clamped at reasoningLevelCap.
  • Setup wizard — adds reasoning-level step, cadence default updated to 2.
  • Docs — session-start prewarm, observation reference, multi-peer setup, query-adaptive reasoning.

Honcho provider opt-in fix (PR #12318 by @helix4u):

Removes the Honcho auto-migration block from AIAgent.__init__(). A blank memory.provider now stays opt-in — stale HONCHO_API_KEY / HONCHO_BASE_URL in .env no longer rewrites memory.provider: honcho back into config after the user has removed it. The migration served its purpose (March 2026 plugin transition) and is no longer needed.

Follow-up commit

  • chore: add LeonSGP43 numeric noreply email to AUTHOR_MAP — the cherry-picked commit uses 154585401+LeonSGP43@users.noreply.github.com which wasn't in the map.

Test results

298 passed, 3 skipped (tests/honcho_plugin/ + tests/agent/test_memory_*.py + tests/run_agent/test_memory_provider_init.py)

Credits

Supersedes #12160, #12318, #11434.

erosika and others added 9 commits April 19, 2026 11:01
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 #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-#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.
…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.
The cherry-picked commit from #11434 uses the 154585401+ prefixed
noreply format. Add it alongside the existing bare entry so the
contributor audit passes.
@kshitijk4poor kshitijk4poor merged commit 7b1a11b into main Apr 19, 2026
6 of 8 checks passed
@kshitijk4poor kshitijk4poor deleted the salvage/honcho-dialectic-lifecycle branch April 19, 2026 05:50
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.

[Bug]: Honcho memory scoping ignores gateway user_id when peer_name is configured

4 participants