Skip to content

Sub-agent session causes gateway blocking: before_prompt_build hooks need subagent skip logic #600

@jlin53882

Description

@jlin53882

Problem

When a sub-agent (e.g. via /new command or delegate) runs, its before_prompt_build hooks execute synchronously inside the same Node.js process as the gateway, blocking the event loop. User sessions waiting on the gateway's IPC response are starved.

This manifests as:

The root cause is that memory-lancedb-pro registers multiple before_prompt_build hooks (priority 12 and 15) that call await loadAgentReflectionSlices() which does store.list() -- a blocking DB operation during prompt build. The agent:bootstrap hook has subagent skip logic but before_prompt_build hooks do not.

Proposed Solution

A per-agent exclusion mechanism via the existing autoRecallExcludeAgents config field, extended to also protect the memoryReflection hooks.

Changes

1. New helper function isAgentOrSessionExcluded

Supports three pattern types:

  • Exact match: memory-distiller
  • Wildcard prefix: pi- (matches pi-agent, pi-coder)
  • Special temp:* for internal reflection sessions

2. Fixed auto-recall before_prompt_build exclusion check

Removed the ineffective agentId !== undefined check (always true due to || "main" fallback).

3. Added exclusion checks to both reflection before_prompt_build hooks (priority 12 & 15)

Both hooks now have isInternalReflectionSessionKey guard first, followed by isAgentOrSessionExcluded check.

4. Three-layer guard on runMemoryReflection command hook

  • Internal session guard
  • Re-entrant guard (global lock via Symbol.for + globalThis)
  • Serial cooldown guard (120s)

5. Added internal session guard to appendSelfImprovementNote

Consistent with agent:bootstrap hook behavior.

6. Enhanced early-return logging

All early returns now include sessionKey/sessionId for observability.

Protection Matrix

Hook Protection
before_prompt_build (auto-recall) exclusion check
before_prompt_build (priority 12) isInternal guard + exclusion
before_prompt_build (priority 15) isInternal guard + exclusion
command:new/reset -> runMemoryRefl. three-layer guard
appendSelfImprovementNote internal session guard

Usage

{
  "memory-lancedb-pro": {
    "autoRecallExcludeAgents": ["memory-distiller", "pi-", "temp:*"]
  }
}

Questions for Maintainers

  1. Is this approach acceptable? autoRecallExcludeAgents now serves both auto-recall and reflection exclusion purposes.
  2. Should we split into reflectionExcludeAgents for clarity?
  3. Is the 120s cooldown (SERIAL_GUARD_COOLDOWN_MS) reasonable, or should it be configurable?
  4. Any concerns about using globalThis with Symbol.for for the lock maps?

Related: #492

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions