April 13, 2026 • Version: v2026.4.11

Active Memory Sub-Agent Returns NONE Despite Valid memory_search Results

The Active Memory sub-agent generates valid search queries and mcporter CLI returns high-scoring results, yet the sub-agent consistently returns NONE, indicating the sub-agent's internal tool call path differs from the main agent's memory bridge.

🔍 Symptom

A user on Ubuntu 24.04 with OpenClaw v2026.4.11 observes the following behavior in verbose mode:

  • The Active Memory sub-agent generates appropriate search queries (e.g., "bob grandsons grandchildren names gianni jayden family")
  • The memory_search operation returns valid JSON results with high relevance scores (0.69–0.99)
  • Matching document identified: people/bob-family.md containing grandchildren names "Jayden Violette" and "Gianni Violette"
  • The sub-agent executes 2 search passes (indicating multi-step reasoning is functioning)
  • Final result: Active Memory: empty (NONE)

Direct CLI verification via mcporter call qmd.search returns valid, well-formatted JSON confirming the data exists in the backend.

🧠 Principle

Root Cause: Divergent Tool Registration Paths Between Main Agent and Sub-Agent

The Active Memory sub-agent operates within an embedded transport context that may use a separate tool registration namespace from the main gateway agent. This architectural separation means:

  • The main agent's memory_search tool correctly routes through the QMD mcporter bridge to the custom backend
  • The sub-agent's internal memory_search may invoke a different tool handler or transport layer not subject to the same memory.qmd.mcporter.* configuration
  • Result aggregation occurs in the sub-agent's isolated context, which may have different result acceptance thresholds

Secondary Factor: Embedded Transport Silent Failure

Known issue #41282 identifies incomplete fixes for the openai-codex/gpt-5.4 embedded transport. When the sub-agent's tool execution encounters certain conditions (timeout, malformed response, or model-specific quirks), the failure manifests silently as NONE rather than propagating an error.

Observation Gap

The /verbose output only exposes the search queries and final result timestamp, not the actual tool call input/output payload from within the sub-agent runtime. This prevents direct diagnosis of whether results are fetched and discarded, or whether the tool call itself fails.

🛠️ Fix

Diagnostic Steps

  1. Enable Sub-Agent Logging: Set logLevel: "debug" in the active-memory plugin configuration to capture internal tool call traces
  2. Instrument the Tool Bridge: Add debug logging at the QMD manager's tool invocation layer (qmd-manager-*.js) to trace both main-agent and sub-agent calls
  3. Verify Tool Registration Source: Confirm whether the sub-agent loads tools from the same registry as the main agent by checking gateway/tools/ registration order

Workaround Options

  1. Switch to Direct Memory Backend: Replace memory.backend: "qmd" with a natively supported backend (chromadb, sqlite-vec) that registers tools identically for all agent contexts
  2. Disable Embedded Transport: Set a different model in plugins.entries.active-memory.config to avoid the openai-codex/gpt-5.4 embedded transport issues
  3. Use Direct Memory Tool: If the main agent's memory_search works, consider bypassing the Active Memory sub-agent and using direct memory queries in the main conversation flow

Verification Command

mcporter call qmd.search '{"query": "bob grandchildren names", "limit": 5}'

Confirm this returns the expected JSON before investigating sub-agent routing.