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

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