hermes-agent/agent
xxxigm 691ff7c188 fix(compressor): keep last visible assistant reply out of compaction summary + label handoffs in WebUI (#29824)
Two-pronged fix for the WebUI "context compaction block in place of
last assistant response" regression.

Agent layer (the real fix). ``_find_tail_cut_by_tokens`` already had
``_ensure_last_user_message_in_tail`` to keep the most recent user
request out of the compressed middle (#10896), but no symmetric
anchor for the assistant side. When the conversation has an
oversized recent tool result or a long stretch of tool-call/result
pairs *after* the assistant's last visible reply, the token-budget
walk can stop with the previously-visible reply on the wrong side
of ``cut_idx``. The summariser then rolls it into the single
``[CONTEXT COMPACTION — REFERENCE ONLY]`` block persisted as
``role="user"`` or ``role="assistant"``, and from the operator's
perspective the WebUI session viewer
(``web/src/pages/SessionsPage.tsx``) and the TUI chat panel both
suddenly show the opaque "Context compaction" block in the slot
where they were just reading the actual answer:

    User:  "i cant see the output of the last message you sent,
            i did see it previously, however now see 'context
            compaction'"

Added ``_ensure_last_assistant_message_in_tail`` mirror of the
user-side anchor. It looks for the most recent assistant message
with non-empty text content (skipping tool-call-only assistant
"stubs" which the UI renders as small "calling tool X" indicators
rather than a readable bubble) and walks ``cut_idx`` back through
the standard ``_align_boundary_backward`` so we don't split a
tool_call/result group that immediately precedes it. The two
anchors are chained — each only walks ``cut_idx`` backward, so
the tail can only grow.

Falls back to "most recent assistant of any kind" only when no
content-bearing reply exists in the compressible region (fresh
multi-step tool sequence with no prior reply) — in that case the
agent-side fix is effectively a no-op and the existing
user-message anchor carries the load.

WebUI layer (clarity). Added ``isCompactionMessage`` detector that
recognises the ``[CONTEXT COMPACTION — REFERENCE ONLY]`` (current)
and ``[CONTEXT SUMMARY]:`` (legacy) prefixes from
``agent/context_compressor.py``, and a new ``compaction`` entry
in ``MessageBubble``'s ``ROLE_STYLES`` map. Compaction blocks
now render as muted, italicised system-style rows labelled
``Context handoff`` — clearly metadata, not the assistant's
actual reply — so an operator scrolling back through a long
session can't mistake the summary for a real answer.

Keeping the detected prefixes inline (rather than importing them)
because the WebUI bundle has no Python interop. A guardrail comment
points readers at the source-of-truth constants in
``agent/context_compressor.py``.
2026-06-12 15:41:57 -07:00
..
lsp fix: prevent TUI gateway stdin EOF crash across all TUI-context subprocess calls 2026-06-08 22:46:57 -07:00
secret_sources fix: prevent TUI gateway stdin EOF crash across all TUI-context subprocess calls 2026-06-08 22:46:57 -07:00
transports fix(anthropic): strip output-only SDK fields from replayed content blocks 2026-06-10 20:45:16 -07:00
__init__.py
…
account_usage.py feat(billing): /credits command — balance + portal top-up handoff (#44776) 2026-06-12 08:51:10 +00:00
agent_init.py feat(desktop): resizable VS Code-themed terminal pane + palette polish (#42521) 2026-06-09 23:15:20 -05:00
agent_runtime_helpers.py fix(gateway): gate oversized Telegram voice/audio before download (#44245) 2026-06-11 10:01:51 -04:00
anthropic_adapter.py fix(anthropic): redact replayed tool inputs and broaden thinking-replay 400 recovery 2026-06-10 20:45:16 -07:00
async_utils.py
…
auxiliary_client.py fix(params): send max_completion_tokens for newer OpenAI families on custom endpoints 2026-06-09 23:22:10 -07:00
azure_identity_adapter.py
…
background_review.py
…
bedrock_adapter.py fix(bedrock): fall back to non-streaming InvokeModel when IAM denies InvokeModelWithResponseStream (#44293) 2026-06-11 07:15:30 -07:00
browser_provider.py
…
browser_registry.py
…
chat_completion_helpers.py fix(bedrock): fall back to non-streaming InvokeModel when IAM denies InvokeModelWithResponseStream (#44293) 2026-06-11 07:15:30 -07:00
codex_responses_adapter.py refactor(memory): reuse _summarize_user_message_for_log instead of forking it 2026-06-12 12:49:18 +05:30
codex_runtime.py fix(codex): record app-server token usage in session accounting 2026-06-09 02:46:04 -07:00
coding_context.py fix(coding): teach agents terminal env state persists 2026-06-11 19:50:08 -05:00
context_compressor.py fix(compressor): keep last visible assistant reply out of compaction summary + label handoffs in WebUI (#29824) 2026-06-12 15:41:57 -07:00
context_engine.py
…
context_references.py fix(agent): make a binary @file: reference actionable instead of a dead end 2026-06-09 19:16:46 -05:00
conversation_compression.py
…
conversation_loop.py fix(agent): re-enter retry loop on genuine Nous 429 so fallback guard runs 2026-06-12 12:21:29 -07:00
copilot_acp_client.py
…
credential_persistence.py
…
credential_pool.py fix(auth): add Codex OAuth accounts as distinct pool entries 2026-06-08 11:57:03 -07:00
credential_sources.py
…
credits_tracker.py feat(billing): /credits command — balance + portal top-up handoff (#44776) 2026-06-12 08:51:10 +00:00
curator.py fix(curator): use shared atomic state writer 2026-06-10 03:04:54 -07:00
curator_backup.py
…
display.py feat(web): Parallel-backed web search & extract — free Search MCP when keyless, v1 REST when keyed 2026-06-10 19:54:38 -07:00
error_classifier.py fix(agent): route 'thinking blocks cannot be modified' 400 to recovery 2026-06-10 12:39:44 -07:00
file_safety.py
…
gemini_cloudcode_adapter.py
…
gemini_native_adapter.py
…
gemini_schema.py
…
google_code_assist.py
…
google_oauth.py
…
i18n.py
…
image_gen_provider.py
…
image_gen_registry.py
…
image_routing.py
…
insights.py
…
iteration_budget.py
…
jiter_preload.py
…
lmstudio_reasoning.py
…
manual_compression_feedback.py
…
markdown_tables.py
…
memory_manager.py refactor(memory): reuse _summarize_user_message_for_log instead of forking it 2026-06-12 12:49:18 +05:30
memory_provider.py
…
message_sanitization.py
…
model_metadata.py fix(model_metadata): prefer hardcoded 1M for MiniMax M3 over stale models.dev probe 2026-06-09 23:24:40 -07:00
models_dev.py
…
moonshot_schema.py
…
nous_rate_guard.py
…
onboarding.py
…
plugin_llm.py
…
portal_tags.py
…
process_bootstrap.py
…
prompt_builder.py fix: rich messages follow-ups — reply_parameters, send latch, opt-in default 2026-06-12 11:47:54 -07:00
prompt_caching.py
…
rate_limit_tracker.py
…
redact.py
…
retry_utils.py
…
runtime_cwd.py
…
shell_hooks.py
…
skill_bundles.py
…
skill_commands.py
…
skill_preprocessing.py fix: prevent TUI gateway stdin EOF crash across all TUI-context subprocess calls 2026-06-08 22:46:57 -07:00
skill_utils.py
…
stream_diag.py
…
subdirectory_hints.py
…
system_prompt.py fix(agent): gate skill-index demotion behind the opt-in focus mode (#44387) 2026-06-11 10:00:57 -07:00
think_scrubber.py
…
title_generator.py
…
tool_dispatch_helpers.py
…
tool_executor.py fix(delegate): stop subagent tool completion lines leaking into parent CLI display (#44223) 2026-06-11 05:10:10 -07:00
tool_guardrails.py
…
tool_result_classification.py
…
trajectory.py
…
transcription_provider.py
…
transcription_registry.py
…
tts_provider.py
…
tts_registry.py
…
turn_context.py
…
turn_finalizer.py refactor(agent): extract run_conversation post-loop tail into finalize_turn (god-file Phase 1) 2026-06-08 09:42:23 -07:00
turn_retry_state.py
…
usage_pricing.py fix(model): require confirmation for expensive model selections 2026-06-10 00:24:06 -07:00
video_gen_provider.py
…
video_gen_registry.py
…
web_search_provider.py
…
web_search_registry.py
…