Skip to content

Bug: L2 scene extraction never triggers in standalone (LocalStateBackend) mode #226

Description

@maxwell-feng

Hermes agent Version | Hermes agent 版本

0.16.0

Plugin Version | 插件版本

1.0.0

Operating System | 操作系统

ubuntu

System Specification | 系统配置

N100+12G RAM

Describe the bug | 问题描述

+### Summary
+In standalone mode (LocalStateBackend), the onTimerExpired callback in server.ts:1173 maps the pipeline's L2_schedule timer to offload-l2 instead of L2. This causes the long-term memory scene extraction (SceneExtractor.extract()scene_blocks/*.md) to never run. Only scenes_processed stays 0 forever; seed-produced scenes in subdirectories are unaffected.
+
+The Redis (production) path works correctly because timer-scanner.ts:251 uses prefix matching and routes L2_scheduleL2.
+
+### Root Cause
+
+Two paths for handling the same L2_schedule timer, with inconsistent routing:
+
+Redis mode (correct):
+```
+timer-scanner.ts:251

  • timerType.startsWith("L2") → taskType: "L2" → executeL2 → core.runL2WithStore → SceneExtractor ✓
    +```

+Local mode (bug):
+```
+server.ts:1173

  • suffix === "L2_schedule" ? "offload-l2" → executeOffloadL2 → OffloadTaskExecutor ✗
    +```

+executeOffloadL2 expects offload storage (entries.jsonl, mmds, state.json) and returns in ~16ms when none exist — never calling SceneExtractor.extract().

To Reproduce | 复现步骤

+### Reproduction
+
+1. Install v1.0.0 on Hermes (standalone/deployMode=standalone)
+2. Send captures via POST /capture
+3. Wait for L1 → L2 timer chain
+4. Check /healthscansCompleted increments but scenes_processed stays 0
+5. scene_blocks/ directory remains empty
+6. Gateway logs show:

  • [local-timer] Timer fired: :L2_schedule → enqueued offload-l2 task
  • core.task.offload-l2 SPAN_END duration=16ms

+### Evidence
+
+- scenes_processed = 0 across all sessions (checkpoint.json)
+- Gateway logs confirm timer fires but routes to offload-l2 path
+- executeOffloadL2 completes in 16ms (no LLM call, no scene extraction)
+- The executeL2 handler and createL2Runner exist but are never invoked in standalone mode
+- OffloadTaskExecutor.executeOffloadL2 has zero references to SceneExtractor or scene_blocks/
+
+### Fix
+
+One-line change in src/gateway/server.ts:1173:
+
+diff +- taskType = suffix === "L2_schedule" ? "offload-l2" : suffix === "L1_idle" ? "offload-l1" : "L3"; ++ taskType = suffix === "L2_schedule" ? "L2" : suffix === "L1_idle" ? "L1" : "L3"; +
+
+This aligns the onTimerExpired callback with timer-scanner.ts:250-251's prefix-based routing. The offload system uses offload-l2: prefixed timer members (handled in the earlier branch of onTimerExpired), so this change does not affect offload behavior

Expected behavior | 预期行为

Fix

+One-line change in src/gateway/server.ts:1173:
+
+```diff
+- taskType = suffix === "L2_schedule" ? "offload-l2" : suffix === "L1_idle" ? "offload-l1" : "L3";
++ taskType = suffix === "L2_schedule" ? "L2" : suffix === "L1_idle" ? "L1" : "L3";

Error Logs / Screenshots | 报错日志/截图

No response

Additional context | 补充信息

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    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