perf(state): add compact_rows to skip system_prompt blob in session list queries - #47437
Closed
CodeForgeNet wants to merge 28 commits into
Closed
perf(state): add compact_rows to skip system_prompt blob in session list queries#47437CodeForgeNet wants to merge 28 commits into
CodeForgeNet wants to merge 28 commits into
Conversation
…tree writes on Windows
…age NousResearch#43945) (NousResearch#46764) * fix(teams): package Microsoft Teams SDK as an installable extra The Teams adapter imports the microsoft-teams-apps SDK, but it was never declared as a dependency, so source/local installs hit ImportError and the adapter silently reported the SDK as unavailable. Add a 'teams' extra (microsoft-teams-apps==2.0.13.4 + aiohttp) and document 'uv sync --extra teams'. Per the 2026-05-12 [all] policy, opt-in messaging-platform SDKs are NOT added to [all] (they would break every fresh install on a quarantined release); the teams extra is installed on demand like the other platform backends. Co-authored-by: rio-jeong <rio.jeong@thebytesize.ai> * chore: map rio-jeong contributor email for attribution (NousResearch#43945) * feat(teams): lazy-install the Teams SDK on demand (parity with other channels) The teams extra alone left Teams as the only messaging platform that wouldn't auto-install its SDK — every other channel (telegram, discord, slack, matrix, dingtalk, feishu) lazy-installs via tools.lazy_deps on first connect. Bring Teams to parity: - Add 'platform.teams' to LAZY_DEPS (microsoft-teams-apps + aiohttp). - Replace the passive 'check_teams_requirements = check_requirements' alias with a real lazy-installer that calls ensure_and_bind('platform.teams', ...), rebinding all Teams SDK globals on success (mirrors check_slack_requirements). - Call check_teams_requirements() at the top of TeamsAdapter.connect() so enabling Teams installs the SDK on demand. - Keep the passive check_requirements() as the registry check_fn so 'gateway status' probes never trigger a pip install. The 'teams' extra remains for packagers / explicit 'uv sync --extra teams'. Tests: rework the alias test into shortcircuit + lazy-install assertions, and update test_connect_fails_without_sdk to simulate an uninstallable SDK. --------- Co-authored-by: rio-jeong <rio.jeong@thebytesize.ai> Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com>
…ousResearch#46795) The /desktop page is deprecated and redirects to the home page. The landing page for the desktop app is now simply https://hermes-agent.nousresearch.com/. Update all docs and the Docusaurus nav/footer links accordingly. Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com>
NousResearch#38673) electron-builder 26.8.x can stage an Electron.app without its Contents/MacOS/Electron binary, then fail renaming it to Hermes: ENOENT: no such file or directory, rename .../MacOS/Electron -> .../MacOS/Hermes This breaks `npm run pack` and the installer desktop stage before a launchable Hermes.app exists. - Point build.electronDist at the already-installed Electron dist so electron-builder reuses it instead of re-unpacking from cache. - Add a darwin-only prebuilder patch that restores the missing main binary from the runtime dist before the rename. Idempotent (marker guard), soft-fails on shape mismatch, survives node_modules reinstall. Co-authored-by: ChasLui <chaslui@outlook.com>
NVIDIA NIM API uses vendor-prefixed model IDs (e.g. qwen/qwen3.5-122b-a10b, nvidia/nemotron-3-super-120b-a12b). The doctor command incorrectly warns that vendor-prefixed slugs belong to aggregators like openrouter when nvidia is the configured provider. Add 'nvidia' to the providers_accepting_vendor_slugs set so doctor no longer raises false-positive warnings for valid NVIDIA NIM configurations. Fixes NousResearch#35425
…r providers When a user-defined provider (e.g. litellm-proxy) and an aggregator (e.g. openrouter) both advertise the same model name, the Desktop/TUI model picker would show the model under both groups. Selecting it from the aggregator row silently set model.provider to the aggregator, breaking calls because the aggregator doesn't actually serve that model ID. Fix: after list_authenticated_providers() returns, collect all models from user-defined provider rows and filter them out of aggregator rows. Uses is_aggregator() from hermes_cli/providers.py to identify aggregators. Case-insensitive matching. Fixes NousResearch#45954
`terminal.backend` in config.yaml is bridged to the TERMINAL_ENV env var, but a TERMINAL_ENV set in .env / the shell overrides config and is what terminal_tool actually uses. The dump printed only the config value, so a user whose agent was jailed in a docker/podman sandbox via a stale TERMINAL_ENV still saw `terminal: local` — hiding the real cause. Report the effective backend and flag when TERMINAL_ENV overrides config.yaml.
Verifies `hermes debug` surfaces a TERMINAL_ENV override of terminal.backend, reports the config value when no override is present, and emits no spurious note when env and config agree.
…ers (NousResearch#42241) (NousResearch#46796) When a desktop/dashboard session had no agent built yet and the user explicitly picked a provider in the model picker, config.set('model', ...) would first try to initialize the agent from the (possibly broken) config default provider — failing before the user's explicit switch could take effect, trapping them on a misconfigured default. config.set now pre-parses the model flags: if an explicit --provider is present and no agent exists yet, it skips the default-provider agent build and routes straight through _apply_model_switch with the explicit provider. _apply_model_switch gained a parsed_flags passthrough (avoids double-parsing) and only falls back to resolve_runtime_provider(requested=None) when no explicit provider was given. The desktop hook now sends config.set instead of slash.exec for active-session model changes, so errors from the selected provider surface to the user instead of being swallowed. Co-authored-by: rodboev <rod.boev@gmail.com>
When the installer falls back to a bundled Node under $HERMES_HOME/node, npm's default global prefix is that Node dir, so `npm install -g <pkg>` drops the package binary in $HERMES_HOME/node/bin. Only node/npm/npx are symlinked into the command link dir (~/.local/bin, /usr/local/bin, or $PREFIX/bin) — so user-installed global package binaries are NOT on PATH and can't be run, even though `npm i -g` reports success. They also get wiped on every Node upgrade (the dir is rm -rf'd and re-extracted). Redirect the bundled Node's npm global prefix to the command link dir's parent, so global bins land in the link dir (already on PATH, alongside node/npm/npx) and survive Node upgrades. Scoped to the bundled Node via its prefix-local global npmrc ($HERMES_HOME/node/etc/npmrc), so the user's other Node installs and their ~/.npmrc are untouched. Hermes's own global installs (agent-browser) pass an explicit --prefix and are unaffected.
Guards that install.sh and node-bootstrap.sh redirect the bundled Node's npm global prefix to the command link dir's parent via a prefix-local global npmrc, so `npm install -g` binaries land on PATH instead of the off-PATH $HERMES_HOME/node/bin.
The initial fix only wrote the prefix npmrc on a fresh Node install, so pre-existing bundled-Node installs (Node already present) were not repaired by re-running the installer — install_node/ensure_node skip when Node is already up to date. Extract the redirect into an idempotent helper (configure_managed_node_npm_prefix / _nb_configure_npm_prefix) that no-ops when there's no Hermes-managed npm, and call it unconditionally from check_node (install.sh) and at the top of ensure_node (node-bootstrap.sh). Re-running the install command now repairs an affected install in place, not just brand-new ones.
…stale (NousResearch#46772) A GUI app launched from Explorer inherits the environment block captured at login, so a HERMES_HOME set via 'setx' AFTER login is invisible in process.env even though the CLI (a fresh shell) sees it. The desktop then silently fell back to %LOCALAPPDATA%\hermes and reported 'No inference provider configured' despite a valid configured home (NousResearch#45471). resolveHermesHome() now consults the live HKCU\Environment registry value on Windows before the LOCALAPPDATA default. New windows-user-env.cjs helper parses 'reg query' output, expands %VAR% refs, and fails safe (returns null off-Windows, on spawn error, or empty value). The registry value is normalized through the same normalizeHermesHomeRoot() path as the env var for consistency. Co-authored-by: jeffrobodie-glitch <jeffrobodie@gmail.com>
…ound=true) (NousResearch#40946) * feat(delegation): async background subagents via delegate_task(background=true) delegate_task(background=true) dispatches a subagent that runs in the background and returns a handle immediately, so the user and model keep working while it runs. The full result — plus the original task source — re-enters the conversation as a new turn when the subagent finishes, riding the same completion-queue rail as terminal background processes. - tools/async_delegation.py: daemon-executor registry, capacity cap, rich self-contained completion event pushed onto the shared process_registry.completion_queue (type='async_delegation'). - delegate_tool.py: background param + single-task dispatch branch; batch async rejected (v1). - process_registry.py: format_process_notification renders the rich task-source block (goal/context/toolsets/model/status/result). - gateway/run.py: dedicated _async_delegation_watcher drains + injects results into the originating session (idle + post-turn), session_key routing enrichment, shutdown interrupt of dangling delegations. - config: delegation.max_async_children (default 3). Reuses the existing idle-drain wiring rather than mutating a running agent loop, preserving message-role alternation and prompt-cache invariants. 13 targeted tests; CLI + gateway paths E2E-verified. * test(delegation): make async non-blocking tests environment-independent CI 'test (5)' flaked on a cold, 8-worker runner: the first delegate_task(background=true) call measured 2.27s of one-time setup (config load + child-agent construction + imports), tripping the elapsed < 1.0 wall-clock assertion. That assertion was testing setup overhead, not blocking. Replace the wall-clock thresholds with the real invariant: dispatch returns while the child is still gated (active_count == 1, completion queue empty), which a synchronous impl could not do. Keep only a loose 4s sanity backstop well under the runner's 5s gate. * fix(delegation): harden async background delegation Follow-up review fixes: - Detach background child from parent._active_children at dispatch — otherwise parent-turn interrupts (Ctrl+C, mid-turn steering), cache evicts (release_clients), and session close (/new) kill/close the detached subagent mid-run, defeating the point of background mode. Lifecycle is owned by the async registry's interrupt_fn. - Make the capacity check atomic with the record insert (TOCTOU: two concurrent dispatches could both pass active_count() and exceed the cap). - TUI dedup: key async_delegation events by delegation_id — the fallthrough keyed them all as ("", type), suppressing every completion after the first in the desktop/TUI status feed. - CLI /stop now interrupts running background delegations and /agents lists them (they live outside the process registry and were invisible). - Drop stray unbalanced ']' line from the re-injection block and the unused _ASYNC_DEFAULT import. Tests: detach-at-dispatch + concurrent-capacity race added (15 total in test_async_delegation.py); 137 delegate + 140 process-registry/notify/watch + 7 TUI dedup tests pass. * fix(delegation): harden async background completion drains
Discord enforces a hard cap of 100 global application commands per app.
The adapter registers ~27 native commands plus every gateway-available
entry in COMMAND_REGISTRY plus all plugin commands plus the consolidated
/skill group. On a loaded install (many plugins/quick commands) the
desired set exceeds 100, so tree.sync() / _safe_sync_slash_commands()
hits error 30032 ("Maximum number of application commands reached") and
Discord rejects the ENTIRE batch — silently breaking every slash command,
not just the overflow.
Cap registration at the 100-command limit: native commands (registered
first, highest priority) and the /skill group are always kept; lower-
priority auto-registered COMMAND_REGISTRY and plugin commands are added
only until the cap is reached, with a single concise warning telling the
user how to surface the rest. Since both sync paths read from
tree.get_commands(), bounding the tree fixes the root cause for both.
Registers 200 plugin commands on top of the native + COMMAND_REGISTRY set
and asserts the tree never exceeds Discord's 100-command limit, that native
high-priority commands survive the cap, and that overflow is actually
dropped. Regression guard for the recurring error 30032
("Maximum number of application commands reached") sync failures.
no waiting for pending forever!
…te legacy key The setup wizard wrote the legacy pinPeerName even though pinUserPeer is the canonical key that outranks it in the resolver — so it had to scrub the canonical key afterward to stop it winning. Write pinUserPeer directly and migrate any legacy pinPeerName onto it on touch (setup load + clone), which removes the precedence-fighting entirely. Resolver still reads pinPeerName as a back-compat alias; that's deferred.
…d identity tree The single/multi/hybrid 'deployment shape' was a misnomer: these keys only affect the gateway (the one entrypoint supplying a runtime user ID), and the three preset names stamped a lossy taxonomy onto three orthogonal knobs while hiding which keys got written. Replace it with an intent-led tree gated on gateway detection: - _gateway_platforms() lazily inspects the gateway config (best-effort, no hard dependency); the step auto-skips when no platform is connected. - 'who talks to this?' → just me / me+others (pooled?) / only others, deriving pinUserPeer + userPeerAliases + runtimePeerPrefix and echoing the result. - [e] drops to a raw-knob editor for power users. - The single→multi orphan guard survives as a pooling steer.
…y identity tree Drop pinPeerName from the key table (now a deprecated-alias note), and replace the single/multi/hybrid 'deployment shapes' section with the gateway-gated intent tree the wizard actually presents, including the [e] raw-edit hatch and the un-pin pooling steer.
The identity-mapping keys never made it to the site docs. Add the three keys to the config reference and a Gateway Identity Mapping section: when it applies (gateway only, setup-gated), the intent tree, resolver order, the un-pin orphan warning, and the deprecated pinPeerName alias.
'everyone collapses to your peer' read as a promise about all traffic. pinUserPeer pins the user-side peer and is checked before userPeerAliases (session.py:335), so a pin overrides every alias — including agent peers. For a multi-agent operator that silently pools distinct agents onto one peer, the opposite of intent. Scopes the wording to 'every non-agent gateway user', notes the pin overrides aliases, and points agent-mesh operators at pinUserPeer:false + userPeerAliases instead. Same correction in the wizard menu/echo text, the plugin README, and the website Honcho page.
The Honcho provider page documented the per-profile peer model (user peer / AI peer / observation) but never the gateway axis — how platform runtime IDs map to peers. Adds the three keys to the config table and a short Gateway identity mapping subsection that points at the Honcho page for the resolver ladder. Uses the corrected pinUserPeer wording (pins non-agent users, overrides aliases) so the provider-comparison reader gets the same accurate framing as the dedicated page.
Salvage the valid thread-routing pieces from NousResearch#41640: - route Mattermost progress/status sends through metadata thread IDs - treat top-level Mattermost channel posts as thread roots for progress - preserve thread metadata through media/file sends - allow flat fallback only for final notify-worthy replies on confirmed broken roots Co-authored-by: Wolfram Ravenwolf <github.com@wolfram.ravenwolf.de>
…ist queries list_sessions_rich and _get_session_rich_row previously used SELECT s.*, pulling the system_prompt TEXT blob on every row even for dashboard and picker callers that never display it. On large databases this blob routinely runs to tens of kilobytes per session, causing unnecessary B-tree I/O. Add compact_rows=False param to both functions. When True, an explicit column list omitting system_prompt is substituted for s.* in both the simple and the recursive-CTE (order_by_last_active) query paths. Default is False so all existing callers are unaffected. Update dashboard and session-picker callers in web_server.py and tui_gateway/server.py to pass compact_rows=True. Add seven regression tests covering: omission of system_prompt, presence of all metadata fields, both query paths, _get_session_rich_row, and backward-compat default.
kshitijk4poor
added a commit
to kshitijk4poor/hermes-agent
that referenced
this pull request
Jul 8, 2026
Rebase reconciliation with NousResearch#60884: _count_status_active_sessions (from NousResearch#58238) now passes compact_rows=True (this branch's NousResearch#47437 projection), so the fake asserts both.
kshitijk4poor
added a commit
that referenced
this pull request
Jul 8, 2026
- derive the compact_rows projection from SCHEMA_SQL (parse once, cache) instead of a hardcoded column list: the original #47437 list was cut against a June schema and silently dropped session_key/chat_id/chat_type/ thread_id/display_name/origin_json/expiry_finalized/git_branch/ git_repo_root/compression_failure_* — including desktop sidebar fields. Schema-derived means declaratively reconciled new columns are included automatically; only system_prompt is excluded. - guard test pinning the schema<->projection contract (mutation-verified: dropping a column from the projection fails it) - wire compact_rows=(not full) into /api/sessions and /api/profiles/sessions so the SQL projection pairs with the API-level field strip (?full=1 still returns complete rows end-to-end) - pass compact_rows at the remaining hot list callers: /api/status active count, _session_latest_descendant fallback, /api/sessions/stats by-source - thread compact_rows through the compression-tip projection (_get_session_rich_row) so projected tips can't reintroduce the blob - add pagination tests for get_messages (#60347 shipped none): paging order, offset-past-end, active-flag interaction; add tip-projection compact test - AUTHOR_MAP entries for mahdiwafy + CodeForgeNet (plain emails)
kshitijk4poor
added a commit
that referenced
this pull request
Jul 8, 2026
tui_gateway session.list/most_recent now pass compact_rows=True (#47437 salvage); the keyword-only fake signatures in test_tui_gateway_server.py rejected the new kwarg and CI slice 6/8 failed with TypeError. Other list_sessions_rich fakes use **kwargs and are unaffected.
Collaborator
|
Merged via #60883 (rebase) — your compact_rows commit landed on main as 22eb1af with your authorship preserved. The substantive hermes_state/web_server/tui_gateway hunks were extracted from this branch (the unrelated stale-base files were dropped), and a follow-up commit derives the column list from SCHEMA_SQL so newly added session columns are included automatically. Thanks for the SQL-level fix — it's the layer the API strip couldn't reach. |
This was referenced Jul 8, 2026
santhreal
pushed a commit
to santhreal/hermes-agent
that referenced
this pull request
Jul 13, 2026
…sResearch#47437 - derive the compact_rows projection from SCHEMA_SQL (parse once, cache) instead of a hardcoded column list: the original NousResearch#47437 list was cut against a June schema and silently dropped session_key/chat_id/chat_type/ thread_id/display_name/origin_json/expiry_finalized/git_branch/ git_repo_root/compression_failure_* — including desktop sidebar fields. Schema-derived means declaratively reconciled new columns are included automatically; only system_prompt is excluded. - guard test pinning the schema<->projection contract (mutation-verified: dropping a column from the projection fails it) - wire compact_rows=(not full) into /api/sessions and /api/profiles/sessions so the SQL projection pairs with the API-level field strip (?full=1 still returns complete rows end-to-end) - pass compact_rows at the remaining hot list callers: /api/status active count, _session_latest_descendant fallback, /api/sessions/stats by-source - thread compact_rows through the compression-tip projection (_get_session_rich_row) so projected tips can't reintroduce the blob - add pagination tests for get_messages (NousResearch#60347 shipped none): paging order, offset-past-end, active-flag interaction; add tip-projection compact test - AUTHOR_MAP entries for mahdiwafy + CodeForgeNet (plain emails)
santhreal
pushed a commit
to santhreal/hermes-agent
that referenced
this pull request
Jul 13, 2026
tui_gateway session.list/most_recent now pass compact_rows=True (NousResearch#47437 salvage); the keyword-only fake signatures in test_tui_gateway_server.py rejected the new kwarg and CI slice 6/8 failed with TypeError. Other list_sessions_rich fakes use **kwargs and are unaffected.
santhreal
pushed a commit
to santhreal/hermes-agent
that referenced
this pull request
Jul 13, 2026
Rebase reconciliation with NousResearch#60884: _count_status_active_sessions (from NousResearch#58238) now passes compact_rows=True (this branch's NousResearch#47437 projection), so the fake asserts both.
justemu
pushed a commit
to justemu/hermes-agent
that referenced
this pull request
Jul 18, 2026
…sResearch#47437 - derive the compact_rows projection from SCHEMA_SQL (parse once, cache) instead of a hardcoded column list: the original NousResearch#47437 list was cut against a June schema and silently dropped session_key/chat_id/chat_type/ thread_id/display_name/origin_json/expiry_finalized/git_branch/ git_repo_root/compression_failure_* — including desktop sidebar fields. Schema-derived means declaratively reconciled new columns are included automatically; only system_prompt is excluded. - guard test pinning the schema<->projection contract (mutation-verified: dropping a column from the projection fails it) - wire compact_rows=(not full) into /api/sessions and /api/profiles/sessions so the SQL projection pairs with the API-level field strip (?full=1 still returns complete rows end-to-end) - pass compact_rows at the remaining hot list callers: /api/status active count, _session_latest_descendant fallback, /api/sessions/stats by-source - thread compact_rows through the compression-tip projection (_get_session_rich_row) so projected tips can't reintroduce the blob - add pagination tests for get_messages (NousResearch#60347 shipped none): paging order, offset-past-end, active-flag interaction; add tip-projection compact test - AUTHOR_MAP entries for mahdiwafy + CodeForgeNet (plain emails)
justemu
pushed a commit
to justemu/hermes-agent
that referenced
this pull request
Jul 18, 2026
tui_gateway session.list/most_recent now pass compact_rows=True (NousResearch#47437 salvage); the keyword-only fake signatures in test_tui_gateway_server.py rejected the new kwarg and CI slice 6/8 failed with TypeError. Other list_sessions_rich fakes use **kwargs and are unaffected.
justemu
pushed a commit
to justemu/hermes-agent
that referenced
this pull request
Jul 18, 2026
Rebase reconciliation with NousResearch#60884: _count_status_active_sessions (from NousResearch#58238) now passes compact_rows=True (this branch's NousResearch#47437 projection), so the fake asserts both.
Gravezzz
pushed a commit
to Gravezzz/hermes-agent
that referenced
this pull request
Jul 21, 2026
…sResearch#47437 - derive the compact_rows projection from SCHEMA_SQL (parse once, cache) instead of a hardcoded column list: the original NousResearch#47437 list was cut against a June schema and silently dropped session_key/chat_id/chat_type/ thread_id/display_name/origin_json/expiry_finalized/git_branch/ git_repo_root/compression_failure_* — including desktop sidebar fields. Schema-derived means declaratively reconciled new columns are included automatically; only system_prompt is excluded. - guard test pinning the schema<->projection contract (mutation-verified: dropping a column from the projection fails it) - wire compact_rows=(not full) into /api/sessions and /api/profiles/sessions so the SQL projection pairs with the API-level field strip (?full=1 still returns complete rows end-to-end) - pass compact_rows at the remaining hot list callers: /api/status active count, _session_latest_descendant fallback, /api/sessions/stats by-source - thread compact_rows through the compression-tip projection (_get_session_rich_row) so projected tips can't reintroduce the blob - add pagination tests for get_messages (NousResearch#60347 shipped none): paging order, offset-past-end, active-flag interaction; add tip-projection compact test - AUTHOR_MAP entries for mahdiwafy + CodeForgeNet (plain emails)
Gravezzz
pushed a commit
to Gravezzz/hermes-agent
that referenced
this pull request
Jul 21, 2026
tui_gateway session.list/most_recent now pass compact_rows=True (NousResearch#47437 salvage); the keyword-only fake signatures in test_tui_gateway_server.py rejected the new kwarg and CI slice 6/8 failed with TypeError. Other list_sessions_rich fakes use **kwargs and are unaffected.
Gravezzz
pushed a commit
to Gravezzz/hermes-agent
that referenced
this pull request
Jul 21, 2026
Rebase reconciliation with NousResearch#60884: _count_status_active_sessions (from NousResearch#58238) now passes compact_rows=True (this branch's NousResearch#47437 projection), so the fake asserts both.
This was referenced Aug 3, 2026
leewenjie
pushed a commit
to leewenjie/hermes-agent
that referenced
this pull request
Aug 7, 2026
…sResearch#47437 - derive the compact_rows projection from SCHEMA_SQL (parse once, cache) instead of a hardcoded column list: the original NousResearch#47437 list was cut against a June schema and silently dropped session_key/chat_id/chat_type/ thread_id/display_name/origin_json/expiry_finalized/git_branch/ git_repo_root/compression_failure_* — including desktop sidebar fields. Schema-derived means declaratively reconciled new columns are included automatically; only system_prompt is excluded. - guard test pinning the schema<->projection contract (mutation-verified: dropping a column from the projection fails it) - wire compact_rows=(not full) into /api/sessions and /api/profiles/sessions so the SQL projection pairs with the API-level field strip (?full=1 still returns complete rows end-to-end) - pass compact_rows at the remaining hot list callers: /api/status active count, _session_latest_descendant fallback, /api/sessions/stats by-source - thread compact_rows through the compression-tip projection (_get_session_rich_row) so projected tips can't reintroduce the blob - add pagination tests for get_messages (NousResearch#60347 shipped none): paging order, offset-past-end, active-flag interaction; add tip-projection compact test - AUTHOR_MAP entries for mahdiwafy + CodeForgeNet (plain emails)
leewenjie
pushed a commit
to leewenjie/hermes-agent
that referenced
this pull request
Aug 7, 2026
tui_gateway session.list/most_recent now pass compact_rows=True (NousResearch#47437 salvage); the keyword-only fake signatures in test_tui_gateway_server.py rejected the new kwarg and CI slice 6/8 failed with TypeError. Other list_sessions_rich fakes use **kwargs and are unaffected.
leewenjie
pushed a commit
to leewenjie/hermes-agent
that referenced
this pull request
Aug 7, 2026
Rebase reconciliation with NousResearch#60884: _count_status_active_sessions (from NousResearch#58238) now passes compact_rows=True (this branch's NousResearch#47437 projection), so the fake asserts both.
randlee
pushed a commit
to randlee/hermes-agent
that referenced
this pull request
Aug 11, 2026
…sResearch#47437 - derive the compact_rows projection from SCHEMA_SQL (parse once, cache) instead of a hardcoded column list: the original NousResearch#47437 list was cut against a June schema and silently dropped session_key/chat_id/chat_type/ thread_id/display_name/origin_json/expiry_finalized/git_branch/ git_repo_root/compression_failure_* — including desktop sidebar fields. Schema-derived means declaratively reconciled new columns are included automatically; only system_prompt is excluded. - guard test pinning the schema<->projection contract (mutation-verified: dropping a column from the projection fails it) - wire compact_rows=(not full) into /api/sessions and /api/profiles/sessions so the SQL projection pairs with the API-level field strip (?full=1 still returns complete rows end-to-end) - pass compact_rows at the remaining hot list callers: /api/status active count, _session_latest_descendant fallback, /api/sessions/stats by-source - thread compact_rows through the compression-tip projection (_get_session_rich_row) so projected tips can't reintroduce the blob - add pagination tests for get_messages (NousResearch#60347 shipped none): paging order, offset-past-end, active-flag interaction; add tip-projection compact test - AUTHOR_MAP entries for mahdiwafy + CodeForgeNet (plain emails)
randlee
pushed a commit
to randlee/hermes-agent
that referenced
this pull request
Aug 11, 2026
tui_gateway session.list/most_recent now pass compact_rows=True (NousResearch#47437 salvage); the keyword-only fake signatures in test_tui_gateway_server.py rejected the new kwarg and CI slice 6/8 failed with TypeError. Other list_sessions_rich fakes use **kwargs and are unaffected.
randlee
pushed a commit
to randlee/hermes-agent
that referenced
this pull request
Aug 11, 2026
Rebase reconciliation with NousResearch#60884: _count_status_active_sessions (from NousResearch#58238) now passes compact_rows=True (this branch's NousResearch#47437 projection), so the fake asserts both.
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.
Fixes #47414
Problem
list_sessions_richand_get_session_rich_rowuseSELECT s.*whichpulls the
system_promptTEXT blob on every row. Dashboard views andsession pickers never display this field — on large databases the blob
routinely runs to tens of kilobytes per session, causing unnecessary
B-tree I/O on every list call.
Fix
Add
compact_rows: bool = Falseto both functions. WhenTrue, anexplicit column list omitting
system_promptis substituted fors.*in both query paths (simple ORDER BY and recursive-CTE
order_by_last_active). Default isFalse— all existing callers areunaffected.
Updated dashboard and session-picker callers in
web_server.pyandtui_gateway/server.pyto passcompact_rows=True.Changes
hermes_state.py—_SESSION_COMPACT_COLSconstant,compact_rowsparam on both functionshermes_cli/web_server.py— 3 dashboard callers updatedtui_gateway/server.py— 3 session-picker callers updatedtests/test_hermes_state.py— 7 new regression testsTest plan
test_compact_rows_omits_system_prompttest_full_rows_include_system_prompttest_compact_rows_preserves_metadata_fieldstest_compact_rows_order_by_last_activetest_get_session_rich_row_compact_omits_system_prompttest_get_session_rich_row_full_includes_system_prompttest_compact_rows_default_is_false