fix(honcho): don't let auto-generated session titles override sessionStrategy

Auto-generated display titles (LLM or derived) were passed to Honcho's
resolve_session_name() as authoritative, so a titled per-repo,
per-directory, or global session silently remapped onto a second Honcho
session named after the generated title. Only explicit /title commands
(user provenance) should act as an intentional session-name override.

Thread session_title_source from the session DB through
agent_init into the Honcho provider, and skip title-based remapping
when the source is 'derived' or 'llm'. Missing provenance keeps the
legacy explicit-title behavior for callers that predate source
threading. Gateway per-chat keys and per-session identity safeguards
are unchanged.

Adds regressions for titled per-repo, per-directory, and global
sessions at both the resolver and provider level.

Fixes #24740

(cherry picked from commit e7ba26ee15821baa382a397ce9ce9cd57a260188)
This commit is contained in:
outpoints
2026-08-23 19:04:30 -07:00
committed by Teknium
parent 3abeca16e6
commit 3cbdc32565
7 changed files with 188 additions and 14 deletions
+14 -8
View File
@@ -273,15 +273,21 @@ The Honcho session name determines which conversation bucket memory lands in. Re
| Priority | Source | Example session name |
|----------|--------|---------------------|
| 1 | Manual map (`sessions` config) | `"myproject-main"` |
| 2 | `/title` command (mid-session rename) | `"refactor-auth"` |
| 3 | Gateway session key (Telegram, Discord, etc.) | `"agent-main-telegram-dm-8439114563"` |
| 4 | `per-session` strategy | Hermes session ID (`20260415_a3f2b1`) |
| 1 | Gateway session key (Telegram, Discord, etc.) | `"agent-main-telegram-dm-8439114563"` |
| 2 | `per-session` strategy | Hermes session ID (`20260415_a3f2b1`) |
| 3 | Manual map (`sessions` config) | `"myproject-main"` |
| 4 | Explicit `/title` command (non-automatic title) | `"refactor-auth"` |
| 5 | `per-repo` strategy | Git root directory name (`hermes-agent`) |
| 6 | `per-directory` strategy | Current directory basename (`src`) |
| 7 | `global` strategy | Workspace name (`hermes`) |
| 6 | `per-directory` strategy | Directory basename (`my-project`) |
| 7 | `global` strategy | Workspace name |
Gateway platforms always resolve via priority 3 (per-chat isolation) regardless of `sessionStrategy`. The strategy setting only affects CLI sessions.
Messaging gateway platforms always resolve via priority 1 (per-chat isolation) regardless of `sessionStrategy`. The strategy setting controls non-gateway sessions such as CLI and Desktop.
Directory strategies and manual mappings use the logical session workspace, not the backend process's launch directory. Desktop/TUI and ACP pass the workspace during agent construction; deferred Desktop/TUI builds use the same session cwd. With no non-empty construction cwd, Honcho uses the runtime resolver: session cwd context, scoped `terminal.cwd`, then the launch directory. No process-wide `chdir` is needed.
Automatically generated Hermes titles (`derived` or `llm`) are display metadata and do not override `sessionStrategy`. An explicit user title remains an intentional session-name override for non-gateway, non-`per-session` sessions.
Sessions created before title provenance was recorded retain legacy behavior: because an old automatic title cannot be distinguished from an old user title, a title with no source is treated as an explicit override.
If `sessionPeerPrefix` is `true`, the user peer name is prepended: `alice-hermes-agent`.
@@ -293,7 +299,7 @@ In bot mode another Hermes profile can DM this agent. The relay marks that turn
#### What each strategy produces
- **`per-directory`** — basename of `$PWD`. Opening hermes in `~/code/myapp` and `~/code/other` gives two separate sessions. Same directory = same session across runs.
- **`per-directory`** — basename of the logical session working directory. Opening Hermes in `~/code/myapp` and `~/code/other` gives two separate sessions. Same directory = same session across runs.
- **`per-repo`** — git root directory name. All subdirectories within a repo share one session. Falls back to `per-directory` if not inside a git repo.
- **`per-session`** — Hermes session ID (timestamp + hex). Every `hermes` invocation starts a fresh Honcho session. Falls back to `per-directory` if no session ID is available.
- **`global`** — workspace name. One session for everything. Memory accumulates across all directories and runs.
+1
View File
@@ -277,6 +277,7 @@ class HonchoMemoryProvider(DialecticMixin, MemoryProvider):
"""Resolve the Honcho session key without touching the network."""
return cfg.resolve_session_name(
session_title=kwargs.get("session_title"), session_id=session_id,
session_title_source=kwargs.get("session_title_source"),
gateway_session_key=kwargs.get("gateway_session_key"),
) or session_id or "hermes-default"
+4 -1
View File
@@ -488,6 +488,7 @@ class HonchoClientConfig:
def resolve_session_name(
self, cwd: str | None = None, session_title: str | None = None,
session_id: str | None = None, gateway_session_key: str | None = None,
session_title_source: str | None = None,
) -> str | None:
"""Resolve the Honcho session name; with ``session_ai_peer_prefix`` the result is prefixed
``{ai_peer}-`` on every path, including the AI-peer-agnostic gateway session key."""
@@ -523,7 +524,9 @@ class HonchoClientConfig:
manual = self.sessions.get(cwd)
if manual:
return manual
if session_title and _slug(session_title):
# Absent provenance retains the legacy explicit-title override. Generated
# display titles must not change a strategy-selected memory identity.
if session_title and session_title_source not in {"derived", "llm"} and _slug(session_title):
return self._with_peer_prefix(_slug(session_title))
if self.session_strategy == "per-repo":
return self._with_peer_prefix(self._git_repo_name(cwd) or Path(cwd).name)