hermes-agent/tests
brooklyn! e59dcf46f1
fix(desktop): end the #67603 model-switch dup, cross-profile session bleed, and [System:] bubble (#69861)
* fix(desktop): stop model-switch dup + route recovery resumes to the owning profile

Fixes two Desktop session-reconciliation symptoms from #67603.

Symptom 1 — duplicated user bubble after a model switch. The gateway
persists model-switch / personality notices as role=user `[System: …]`
rows (tui_gateway/server.py) so strict OpenAI-compatible providers don't
reject a non-leading system message (#48338). `preserveLocalPendingTurnMessages`
paired local optimistic rows with the stored transcript by user-role
ordinal, so a marker between two real user turns shifted every later
ordinal and the optimistic row was re-appended at the bottom. The single
trailing-marker case is already covered by the compression-era
`latestAuthoritativeUser` guard, but two switches around one turn (marker
before AND after the committed prompt) still duplicated it. Exclude
`[System:` bookkeeping markers from ordinal pairing on both sides.

Symptom 2 — a session appearing under two profiles. The main resume path
already resolves a session's owning profile via `resolveStoredSession`
(cache → active backend → cross-profile probe), but the recovery
`session.resume` calls (stale runtime id, session-not-found, wedged loop,
redirect) omitted `profile`, so the gateway fell back to the launch-profile
DB and forked the conversation into the wrong profile. Route every recovery
resume — and an uncached right-click branch — through the same resolver so
the profile is carried even for sessions outside the paginated sidebar
window (the cache-miss gap).

Tests: discriminating two-switch marker test (fails before, passes after);
cache-hit + cross-profile cache-miss coverage for the recovery resume and
for branching an uncached session.

Supersedes #68665 and #63590.
Closes #67603.

Co-authored-by: Dolverin <5910064+Dolverin@users.noreply.github.com>
Co-authored-by: oliviaaaa7788 <274182427+oliviaaaa7788@users.noreply.github.com>

* fix(desktop): scope the remembered session id per profile

A single global `hermes.desktop.lastSessionId` key remembered ONE session
across every profile, so a relaunch or cold start under profile B would try
to restore a session owned by profile A — reinforcing the impression that a
conversation had bled between profiles (#67603, second symptom).

Key the remembered id by the session's owning profile (resolved from the
session row's `profile`, falling back to the active gateway profile), read it
back for the active profile on restore, and clear an exhausted session under
its owner. The default profile keeps the original unsuffixed key so existing
installs' remembered session survives the upgrade.

Co-authored-by: oliviaaaa7788 <oliviaaaa7788@users.noreply.github.com>

* fix(gateway): hide [System:] bookkeeping markers from every transcript

Model-switch and personality notices are persisted as role=user `[System: …]`
rows so strict providers accept them mid-history, but they are model-facing
runtime metadata, not user turns. `_history_to_messages` — the single display
projection every client reads — passed them straight through, so on resume or
reload they rendered as a fake user bubble in the desktop, TUI, CLI, and web
transcripts.

Drop them in that projection. The raw marker stays in `session["history"]`
for the model, so nothing changes for inference; only the display loses a row
that never belonged to the user. This also removes the stored marker from the
payload the desktop reconciles against, killing the ordinal shift that
duplicated the optimistic prompt (#67603) at its source — the desktop-side
marker exclusion remains as a fallback for older backends.

Co-authored-by: Dolverin <Dolverin@users.noreply.github.com>

---------

Co-authored-by: Dolverin <5910064+Dolverin@users.noreply.github.com>
Co-authored-by: oliviaaaa7788 <274182427+oliviaaaa7788@users.noreply.github.com>
Co-authored-by: oliviaaaa7788 <oliviaaaa7788@users.noreply.github.com>
Co-authored-by: Dolverin <Dolverin@users.noreply.github.com>
2026-07-23 00:05:25 -05:00
..
acp fix(acp): align salvaged /compact wording and test with current /compress command name 2026-07-22 16:59:29 -07:00
acp_adapter feat(surfaces): route busy-input corrections through active-turn redirect 2026-07-22 12:10:58 -05:00
agent fix(vision): resolve namespaced custom provider overrides 2026-07-22 21:18:45 -07:00
ci fix(ci): publish inline E2E evidence (#69699) 2026-07-23 02:15:23 +00:00
cli fix(compress): allow manual /compress when auto-compaction is disabled [overflow error directs users there] 2026-07-22 16:59:29 -07:00
computer_use fix(computer-use): sanitize env on the 4 remaining cua-driver spawn sites (#59165) 2026-07-05 14:48:20 -07:00
cron Preserve Slack cron thread origin 2026-07-22 20:57:25 -07:00
dashboard fix(dashboard): use loopback host for in-container WebSocket client (#58993) [salvage #59682] (#60092) 2026-07-07 18:33:28 +10:00
docker test(docker): cover tini -g legacy entrypoint boot path 2026-07-18 01:11:03 -07:00
e2e fix(slack): handle leading-space text commands 2026-07-22 20:55:51 -07:00
fakes
fixtures/plugins/example-dashboard/dashboard
gateway fix(slack): unify DM-resolution caches and bound wave-2 caches (C16 policy) 2026-07-22 21:58:13 -07:00
hermes_cli fix(cli): persist provider on global model switch 2026-07-22 21:18:50 -07:00
hermes_state fix(state): heal alternation at the ACP / CLI-resume / TUI-resume restore sites too 2026-07-17 06:53:38 -07:00
honcho_plugin fix(ci): make tests, workflows, and attribution reliable under load (#66373) 2026-07-17 20:55:24 +00:00
integration fix: remove dead f-string prefixes via ruff F541 (216 sites) (#52336) 2026-07-05 13:42:46 -07:00
manual docs(cron): scope in_channel to channels; document DM continuation knob 2026-07-01 03:16:13 -07:00
openviking_plugin fix(openviking): align session context with shared profile contract 2026-07-22 14:12:50 +05:30
plugins fix(memory): preserve genuine pre-delimiter content in merged compaction rows 2026-07-22 06:59:14 -07:00
providers feat(nous): send top-level session_id for provider sticky routing (#69253) 2026-07-22 04:39:20 -07:00
run_agent test: cover api_key_hint in strict pool doubles + real-pool routing regression 2026-07-22 20:54:29 -07:00
scripts rip out brew + pip/PyPI wheel support (#68217) 2026-07-22 16:51:01 -04:00
secret_sources feat(secrets): orchestrator-level preserve_existing + profile aliasing (#69058) 2026-07-22 03:20:45 -07:00
skills feat(skills): bundle docx, xlsx, and pdf office skills; refresh powerpoint (#68595) 2026-07-21 05:39:23 -07:00
state fix(state): extend search-path FTS self-heal to the CJK/trigram branch 2026-07-21 12:40:48 -07:00
stress fix: remove dead f-string prefixes via ruff F541 (216 sites) (#52336) 2026-07-05 13:42:46 -07:00
tools fix(slack): unify DM-resolution caches and bound wave-2 caches (C16 policy) 2026-07-22 21:58:13 -07:00
tui_gateway fix(tui_gateway): tolerate late clarify + terminal.read replies after timeout (#69773) 2026-07-22 23:24:42 -05:00
website
__init__.py
conftest.py test/docs(slack): force-clear new gating env vars; document new options 2026-07-22 21:14:44 -07:00
run_interrupt_test.py
test_account_usage.py
test_atomic_replace_symlinks.py fix(config): preserve owner on atomic writes (#56644) 2026-07-03 14:27:34 +10:00
test_background_review_list_shapes.py fix(background-review): guard summarize against list-shaped tool responses (#59437) 2026-07-06 03:28:30 -07:00
test_background_review_session_isolation.py test(review): add integration guards for the two isolation wirings (review) 2026-07-01 16:21:39 +05:30
test_base_url_hostname.py
test_batch_runner_checkpoint.py
test_bitwarden_secrets.py fix(secrets): unify encrypted-cache fallback with the merged stale-cache path 2026-07-22 04:40:07 -07:00
test_cli_file_drop.py
test_cli_manual_compress.py fix(compression): notify context engine after commit 2026-07-22 06:58:16 -07:00
test_cli_skin_integration.py
test_code_skew.py fix(gateway): refuse model switch on stale checkout to avoid env_float ImportError 2026-06-24 04:16:54 +05:30
test_command_secret_source.py feat(secrets): rework command source as a registered SecretSource — no provider selector 2026-07-22 04:39:28 -07:00
test_copilot_initiator.py fix(copilot): set x-initiator per turn so user prompts bill as premium requests (salvage #4097) (#58544) 2026-07-05 00:44:15 -07:00
test_ctx_halving_fix.py chore: restore test_ctx_halving_fix.py to main 2026-07-14 03:58:54 +05:30
test_delegate_cascade_49148.py fix(agent): stop delegate cascade from deleting the parent session 2026-06-21 12:09:16 -07:00
test_dispatch_session_id.py
test_empty_model_fallback.py feat(models): catalog-labeled silent default — GLM-5.2 marked "default": true in the model catalog 2026-07-15 00:10:31 -07:00
test_empty_session_hygiene.py
test_env_loader_applied_homes.py fix(secrets): mark _APPLIED_HOMES only after a real fetch attempt (#40597) (#69056) 2026-07-22 03:20:25 -07:00
test_env_loader_op_bootstrap.py fix(secrets): make 1Password bootstrap token reliable outside systemd 2026-07-06 04:58:07 -07:00
test_env_loader_secret_sources.py test(secrets): match real ApplyReport shape in isolation test 2026-07-22 04:39:17 -07:00
test_evidence_store.py
test_fast_safe_load.py perf(startup): parse config + plugin manifests with libyaml CSafeLoader (#54486) 2026-06-28 15:38:39 -07:00
test_fts_cjk_bigram.py test(state): cover pure-Latin embedded-in-CJK recovery via the cjk index 2026-07-22 10:35:04 -07:00
test_gateway_streaming_nested_config.py fix(gateway): normalize YAML boolean streaming mode and keep enabled a mode-only alias 2026-07-20 05:39:09 -07:00
test_get_tool_definitions_cache_isolation.py
test_hermes_bootstrap.py revert(windows): roll back terminal-popup PRs #53791 #53810 #53829 (#53853) 2026-06-27 15:59:00 -07:00
test_hermes_constants.py fix(dashboard): keep custom themes visible after embedded chat starts (#60601) 2026-07-18 00:34:54 -04:00
test_hermes_home_profile_warning.py
test_hermes_logging.py fix(logging): drive rotating file handlers through an async QueueListener 2026-07-05 11:44:53 +05:30
test_hermes_state.py fix(cron): finalize compressed session tips (86e2darn2) 2026-07-22 16:58:47 -07:00
test_hermes_state_compression_locks.py fix(ci): make tests, workflows, and attribution reliable under load (#66373) 2026-07-17 20:55:24 +00:00
test_hermes_state_wal_fallback.py
test_honcho_client_concurrency.py
test_honcho_client_config.py feat(honcho): make latency-adding paths configurable 2026-07-16 12:48:48 -07:00
test_honcho_session_context.py
test_honcho_startup_fail_open.py fix(ci): make tests, workflows, and attribution reliable under load (#66373) 2026-07-17 20:55:24 +00:00
test_install_autostash_conflict_recovery.py test: add happy-path + no-markers coverage for autostash recovery 2026-07-18 19:18:03 +05:30
test_install_diverged_update.py test(installer): cover diverged managed-clone recovery in install scripts 2026-06-30 20:11:01 +07:00
test_install_lockfile_churn.py fix(install): discard managed lockfile churn before stashing 2026-06-25 23:49:11 -07:00
test_install_no_initial_commit.py
test_install_ps1_ascii_only.py fix(install): keep install.ps1 pure ASCII so Windows PowerShell 5.1 doesn't misparse it 2026-07-18 18:40:59 -04:00
test_install_ps1_native_stderr_eap.py
test_install_ps1_node_path_for_npm.py test(installer): guard Ensure-NodeExeOnPath wiring in install.ps1 2026-07-07 21:17:34 +07:00
test_install_ps1_python_fallback_venv.py test(installer): lock Python-fallback propagation into the venv stage (#50769) 2026-06-23 21:33:08 -07:00
test_install_ps1_uv_powershell_host.py
test_install_ps1_web_server_syntax_probe.py fix(install): guard Windows desktop installs against broken web_server 2026-07-05 19:35:30 -07:00
test_install_sh_browser_install.py test(install): track run_with_timeout extraction after #39219 refactor (#54185) 2026-06-28 03:58:01 -07:00
test_install_sh_install_method_stamp.py
test_install_sh_node_global_prefix.py fix(hermes): heal broken managed Node tree instead of PATH fallback 2026-06-26 20:10:20 +05:30
test_install_sh_pythonpath_sanitization.py
test_install_sh_root_fhs_uv_python_path.py
test_install_sh_setup_wizard_tty_probe.py
test_install_sh_symlink_stomp.py
test_install_sh_termux_network_prereqs.py
test_install_unmerged_index.py fix(install): discard managed lockfile churn before stashing 2026-06-25 23:49:11 -07:00
test_ipv4_preference.py
test_lazy_session_regressions.py fix(gateway): surface retry hint instead of silently dropping turn after /stop (#31884) 2026-06-24 23:51:31 +05:30
test_lint_config.py
test_live_system_guard_self_test.py fix(tests): make the live-system-guard canary fail closed 2026-07-21 12:15:46 +05:30
test_mcp_serve.py refactor: consolidate gateway session metadata into state.db (#58899) 2026-07-05 14:01:03 -07:00
test_mini_swe_runner.py
test_minimax_model_validation.py
test_minimax_oauth.py
test_minisweagent_path.py
test_model_forces_max_completion_tokens.py
test_model_picker_scroll.py
test_model_tools.py fix(toolsets): preserve core tools when a posture toolset is in disabled_toolsets (#57315) 2026-07-05 14:51:49 -07:00
test_model_tools_async_bridge.py
test_ollama_num_ctx.py test(vision): cover Ollama /api/show vision capability routing (#54511) 2026-06-28 22:52:59 -07:00
test_onepassword_secrets.py fix(secrets): pass OP_LOAD_DESKTOP_APP_SETTINGS through to the op child env 2026-07-22 03:19:32 -07:00
test_output_cap_parsing.py fix(context): parse vLLM's token-based output-cap error format 2026-07-01 03:17:48 -07:00
test_packaging_build_guard.py rip out brew + pip/PyPI wheel support (#68217) 2026-07-22 16:51:01 -04:00
test_packaging_metadata.py rip out brew + pip/PyPI wheel support (#68217) 2026-07-22 16:51:01 -04:00
test_plugin_skills.py
test_plugin_utils.py
test_process_loop_event_loop_warning.py
test_profile_isolation_runtime.py test(profile): two-profile regression suite + preserve skills_hub monkeypatch seam 2026-06-30 15:30:06 -07:00
test_project_metadata.py rip out brew + pip/PyPI wheel support (#68217) 2026-07-22 16:51:01 -04:00
test_pty_keepalive_ws.py fix(dashboard): scope chat attach tokens by session (#60745) 2026-07-16 19:48:47 -04:00
test_pty_session.py feat(pty): periodic reaper wired into dashboard lifespan 2026-07-07 15:15:37 -07:00
test_retry_utils.py refactor(retry): single-source Z.AI overload short-attempts + drop change-detector assert 2026-07-07 11:57:01 +05:30
test_run_tests_parallel.py fix(ci): make tests, workflows, and attribution reliable under load (#66373) 2026-07-17 20:55:24 +00:00
test_sanitize_tool_error.py
test_search_slow_query_log.py feat(state): messages_fts_cjk — CJK-bigram index on the v23 external-content layout 2026-07-22 07:56:47 -07:00
test_session_workspace_binding.py feat(sessions): workspace_key grouping helper + tests 2026-07-12 05:07:52 -04:00
test_slack_thread_require_mention.py Add Slack thread mention gating 2026-07-22 21:14:44 -07:00
test_slash_worker_watchdog.py test(tui): keep watchdog checks behavior-focused 2026-07-18 04:15:13 -07:00
test_sql_injection.py
test_stale_utils_module_import.py fix(gateway): refuse model switch on stale checkout to avoid env_float ImportError 2026-06-24 04:16:54 +05:30
test_state_db_malformed_repair.py perf(state): external-content FTS + tool-row-free trigram index (schema v23) (#65798) 2026-07-22 04:42:50 -07:00
test_subprocess_home_isolation.py
test_telegram_polling_progress_ptb.py test(telegram): gate slots premise assert on runtimes without instance __dict__ 2026-07-14 21:25:44 -07:00
test_termux_all_extra_compat.py
test_timezone.py
test_tini_shim.py test(docker): cover tini -g legacy entrypoint boot path 2026-07-18 01:11:03 -07:00
test_toolset_distributions.py
test_toolsets.py feat(mcp): adopt mcp__server__tool naming convention 2026-07-05 13:40:21 -07:00
test_trajectory_compressor.py
test_trajectory_compressor_async.py
test_transform_llm_output_hook.py
test_transform_tool_result_hook.py
test_tui_entry_mcp_owner.py fix(tui): gate the shared-owner MCP discovery wait on the stdio TUI flag 2026-07-21 12:43:27 -07:00
test_tui_gateway_loop_noise.py fix(tui_gateway): suppress WS peer-hangup teardown error flood (#50005) (#54126) 2026-06-28 02:35:01 -07:00
test_tui_gateway_queue_on_busy.py fix(desktop): preserve active correction on warm resume (#69725) 2026-07-22 21:53:56 -04:00
test_tui_gateway_server.py fix(gateway): hide [System:] bookkeeping markers from every transcript 2026-07-22 23:54:05 -05:00
test_tui_gateway_ws.py fix(tui_gateway): preserve websocket batch order (#69684) 2026-07-23 05:02:45 +00:00
test_tui_mcp_late_refresh.py
test_utils_truthy_values.py
test_wal_checkpoint_strategy.py fix(state): use PASSIVE checkpoint for periodic WAL flush to prevent B-tree corruption 2026-07-15 04:55:46 -07:00
test_web_server.py feat(serve): add secure Desktop SSH bootstrap contract 2026-07-16 14:43:14 +02:00
test_web_server_sessiondb_eventloop.py Merge pull request #65893 from NousResearch/bb/salvage-63082-sessiondb-offload 2026-07-16 15:23:32 -04:00
test_windows_subprocess_no_window_flags.py fix(windows): share one bounded, tree-killing git probe across both call sites (#68997) 2026-07-21 20:18:43 -05:00
test_yaml_indent_consistency_31999.py fix(utils): unify YAML list indent across all config writers (#31999) 2026-06-25 23:27:44 +05:30
test_yuanbao_integration.py
test_yuanbao_markdown.py
test_yuanbao_pipeline.py perf(yuanbao): bounded-concurrency inbound media resolve 2026-07-08 08:05:45 -07:00
test_yuanbao_proto.py
test_yuanbao_reconnect_set_active.py fix(yuanbao): restore active singleton after WS reconnect 2026-07-05 00:41:34 -07:00
test_yuanbao_shutdown.py