Skip to content

Token consolidation failure loop blocks WeChat long-poll, causes launchd SIGTERM #309

Description

@shao-zhijie

Bug Description

Token consolidation (maybe_consolidate_by_tokens) can enter a failure loop that blocks the WeChat long-poll channel and eventually causes macOS launchd to kill the nanobot process.

Steps to Reproduce

  1. Have an extended conversation via WeChat (64+ messages, ~61k+ tokens)
  2. Token count reaches context_window_tokens threshold
  3. pick_consolidation_boundary fails to find enough user-turn boundaries to reduce tokens below budget × consolidation_ratio target
  4. After 5 rounds (_MAX_CONSOLIDATION_ROUNDS = 5), consolidation exits with "no safe boundary" log message
  5. Next incoming message triggers consolidation again → infinite failure loop
  6. WeChat long-poll is blocked because consolidation runs synchronously under an asyncio.Lock
  7. Process appears "idle" to macOS launchd → SIGTERM sent

Root Causes

1. Consolidation failure is non-fatal but loops forever

When pick_consolidation_boundary returns None, the function logs "no safe boundary" and exits. The next message to arrive re-triggers the same logic, creating an infinite retry loop under the session lock.

2. No timeout on consolidation lock

maybe_consolidate_by_tokens holds an asyncio.Lock for the entire session with no timeout. All subsequent messages for that session queue behind the lock, effectively blocking the channel.

3. macOS "inefficient" process kill

launchd considers a process "inefficient" if it has no external network activity for a period. During the consolidation retry loop, the process is CPU-bound but not network-active, triggering SIGTERM.

Logs

2026-05-11 10:00:54  Consolidation round 0: 61460/65536 tokens, chunk=64 msgs
2026-05-11 10:01:07  Consolidation: no safe boundary (round 1)
  [WeChat long-poll completely blocked from this point]
2026-05-11 10:17:52  launchd[1]: [ai.nanobot.agent [44514]:] signaled service: Terminated: 15

Suggested Fixes

  1. Add timeout to consolidation: If consolidation cannot complete within N seconds, abandon it and let messages through rather than holding the lock.
  2. Make consolidation failure non-blocking: After _MAX_CONSOLIDATION_ROUNDS, log a warning but don't re-trigger on every message. Add a back-off (e.g., only retry after N new messages or N minutes).
  3. Consider partial consolidation: If full consolidation fails, reduce tokens by whatever boundary was found rather than giving up entirely.
  4. Add monitoring: Log when consolidation fails so this condition is visible before the process is killed.

Environment

  • nanobot v0.1.5.post3
  • macOS (launchd)
  • WeChat channel
  • Model: qwen/qwen3-next-80b-a3b-instruct (free tier, 65k context)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions