Skip to content

fix(gateway): migrate active /goal to new session on context compression - #45065

Closed
liuhao1024 wants to merge 1 commit into
NousResearch:mainfrom
liuhao1024:fix/goal-migration-on-compression
Closed

fix(gateway): migrate active /goal to new session on context compression#45065
liuhao1024 wants to merge 1 commit into
NousResearch:mainfrom
liuhao1024:fix/goal-migration-on-compression

Conversation

@liuhao1024

Copy link
Copy Markdown
Contributor

What does this PR do?

Migrates the active /goal to the new session when context compression rotates session_id. Without this fix, the goal continuation loop silently stops after compression because state_meta key goal:<old_session_id> is orphaned.

Related Issue

Fixes #45059

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • gateway/run.py: Added goal migration in both compression paths — agent-result compression (line ~8638) and hygiene compression (line ~8335). After session_id rotation, the active goal is copied from the old session to the new one via load_goal/save_goal.
  • tests/hermes_cli/test_goals.py: Added TestGoalMigrationOnCompression with 3 tests — active goal migration, cleared goal non-migration, and no-goal safety.

How to Test

  1. Start a gateway session (Discord/Telegram/etc.)
  2. Set a /goal (e.g., /goal Research and summarize Q4 earnings)
  3. Have a long enough conversation to trigger context compression
  4. After compression, verify the goal loop continues (agent still works toward the goal)
python -m pytest tests/hermes_cli/test_goals.py::TestGoalMigrationOnCompression -v

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Code Intelligence

  • Analyzed: gateway/run.py session_id rotation in compression (2 call sites: agent-result path + hygiene path)
  • Blast radius: LOW — adds a try/except block at each compression point; no existing code paths changed
  • Related patterns: mirrors _sync_telegram_topic_binding pattern already present at both sites

When context compression creates a child session (rotating session_id),
the standing /goal is lost because state_meta key goal:<old_session_id>
is never migrated to goal:<new_session_id>. The goal continuation loop
silently stops after compression.

Add goal migration to both compression paths (agent-result and hygiene):
after session_id rotation, copy the active goal from the old session to
the new one via load_goal/save_goal.

Fixes NousResearch#45059
@skycaier

Copy link
Copy Markdown

LGTM! The fix covers both compression paths correctly.

One suggestion for a follow-up: consider adding a parent-chain fallback in _goal_still_active_for_session as a safety net. If a goal migration ever fails silently (e.g. save_goal raises inside the try/except), the continuation queue check would still find the goal by walking parent_session_id:

def _goal_still_active_for_session(self, session_id: str) -> bool:
    if not session_id:
        return False
    try:
        from hermes_cli.goals import GoalManager
        if GoalManager(session_id=session_id).is_active():
            return True
        # Walk parent chain (compression can create multiple generations)
        if self._session_db is not None:
            cur = session_id
            for _ in range(10):
                row = self._session_db._conn.execute(
                    "SELECT parent_session_id FROM sessions WHERE id = ?", (cur,)
                ).fetchone()
                parent = row[0] if row else None
                if not parent:
                    break
                if GoalManager(session_id=parent).is_active():
                    return True
                cur = parent
        return False
    except Exception:
        return False

This makes the system resilient to edge cases where the migration in agent_result or hygiene paths doesn't fire (e.g. a new compression path added in the future).

@liuhao1024

Copy link
Copy Markdown
Contributor Author

Thanks for the review and the thoughtful suggestion!

The parent-chain fallback in _goal_still_active_for_session is a great defensive idea — especially the for _ in range(10) guard against infinite loops. You're right that if save_goal ever silently fails inside the try/except, the goal would be orphaned. Walking parent_session_id as a safety net makes the system resilient to future compression paths that might not trigger migration.

I'll add this as a follow-up PR to keep this one focused on the core migration fix. Appreciate the detailed code snippet!

@alt-glitch alt-glitch added type/bug Something isn't working comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists duplicate This issue or pull request already exists labels Jun 12, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Duplicate of #18427 (canonical, earliest-open) — this is a heavily saturated competing-fix cluster for the goal-migration-on-compression root cause (also #34035, #29955, #18749, #33890, #41478).

@liuhao1024

Copy link
Copy Markdown
Contributor Author

Closing as duplicate of #18427 by @fadelguy, which implements the same fix for goal migration across compression session splits. That PR was opened earlier (2026-05-01) and covers the same root cause.

Thanks to @skycaier for the review and the parent-chain fallback suggestion — I'll note it as a follow-up improvement for whoever lands the canonical fix. Appreciate the detailed code snippet!

This cluster has 5 competing PRs (#18427, #18749, #33890, #34035, #45065) — consolidating to the earliest-open canonical PR.

@liuhao1024 liuhao1024 closed this Jun 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: /goal lost after context compression rotates session_id

3 participants