SceneExtractor is the L2 memory pipeline layer that autonomously reads and writes scene blocks using an LLM agent with tool access, replacing the earlier keyword-based approach and operating in a sandboxed scene_blocks/ directory invisible to system files. SceneExtractor follows a five-phase flow for each extraction: snapshot state, assemble LLM prompt with memories and scene context, run the agent with tool access, clean up soft-deletes and sync the index, then parse output for persona signals — returning early with success if memories are empty.
SceneExtractor in src/core/scene/scene-extractor.ts is the L2 layer of the memory pipeline, replacing the keyword-based SceneManager.processNewMemories() with an LLM agent that autonomously reads and writes scene block files using tools.[1] The ExtractionResult interface exported from src/core/scene/scene-extractor.ts has three fields: memoriesProcessed: number, success: boolean, and optional error?: string.[1]
SceneExtractor sandboxes the LLM to scene_blocks/ by setting workspaceDir to that directory, making system files (checkpoint, scene_index, persona.md) physically invisible to the LLM.[1] Before invoking the LLM, SceneExtractor snapshots both the scene index and the content of every scene file, enabling diffing of created, updated, and deleted scenes after the run.[1] An optional SceneExtractorOptions.llmRunner injection point accepts any host-neutral LLMRunner; when provided it is used instead of creating a CleanContextRunner, decoupling SceneExtractor from the OpenClaw runtime — see OpenClaw integration. The injected runner must be configured with enableTools: true.[1]
SceneExtractor.extract() follows a five-phase flow: (1) backup + load scene index + build summaries, (2) assemble extraction prompt with memories and scene context, (3) run via CleanContextRunner sandboxed to scene_blocks/, (4) cleanup soft-deletes + sync index + update navigation, (5) parse LLM text output for out-of-band persona update signals.[1] SceneExtractor.extract() returns { memoriesProcessed: 0, success: true } immediately — skipping all LLM work — when called with an empty memories array.[1]
The LLM "deletes" scene files by writing the marker [DELETED] into the file rather than issuing shell commands; SceneExtractor post-processes these soft-deletes by detecting and removing marked files before calling syncSceneIndex, preventing stale entries from being re-indexed.[1] On LLM runner failure, SceneExtractor.extract() attempts a fail-soft restore of scene_blocks/ from the Phase 1 backup so partial LLM writes do not leak into the next recall cycle; a restore failure is logged but does not mask the original LLM error.[1]
SceneExtractor defaults: maxScenes = 15, sceneBackupCount = 10, and timeoutMs = 300,000 ms (5 minutes, to accommodate multiple tool calls).[1] parsePersonaUpdateSignal(text) is an exported function that parses LLM output for out-of-band persona update request signals, supporting a block format ([PERSONA_UPDATE_REQUEST]reason: xxx[/PERSONA_UPDATE_REQUEST]) and an inline format (PERSONA_UPDATE_REQUEST: xxx).[1]
Sources