Skip to content

feat(memory): retrieve-inject long-term memory at turn start (closes #154) - #156

Open
dahai80 wants to merge 1 commit into
mainfrom
feat/memory-retrieve-inject
Open

feat(memory): retrieve-inject long-term memory at turn start (closes #154)#156
dahai80 wants to merge 1 commit into
mainfrom
feat/memory-retrieve-inject

Conversation

@dahai80

@dahai80 dahai80 commented Aug 27, 2026

Copy link
Copy Markdown
Owner

Closes #154. Completes the retrieve half deferred by #151 (which landed turn-end commit only). fusion-cowork #68 and fusion-agent-studio #247 already have both commit+retrieve; this brings fusion-code to parity.

What

At main-agent turn start (processUserInput), recall relevant cross-session memory from fusion-memory (fm-server) and inject it as an attachment message on the same path as UserPromptSubmit hook additionalContext. The agent starts each turn with relevant prior context, not stateless.

Why now

#151 deliberately wired only the commit half — its body noted the subagent spawn path (AgentTool.tsx) was the wrong injection seam for retrieve and deferred the correct main-agent seam to a follow-up issue (#154). The correct seam is the user-input processing path (processUserInput), which runs per-turn for the main conversational agent and already collects additionalContext from UserPromptSubmit hooks. This PR injects memory there.

How

  • src/services/memory/retrieveContext.ts (new) — retrieveMemorySection(): calls the existing retrieveContext RPC + formatContextToPrompt (both added by feat(memory): integrate fusion-memory long-term memory commit #151 but unwired), returns a <fusion_memory_context> section string or "". Main-agent guard (!agentId), fail-empty (logForDebugging, never throws). Env override: FUSION_MEMORY_RETRIEVE_TOP_K (default 10) / FUSION_MEMORY_RETRIEVE_BUDGET (default 4096).
  • src/utils/processUserInput/processUserInput.ts (edit) — after UserPromptSubmit hooks, on the happy path (result.shouldQuery) with real input and !context.agentId, fire-and-forget retrieveMemorySection and push the section as a hook_additional_context attachment message. Mirrors the existing hook additionalContext push. Lazy-require the module (same pattern as feat(memory): integrate fusion-memory long-term memory commit #151's stopHooks) to avoid circular deps.

Wire contract (already implemented in fm-server)

JSON-RPC 2.0: retrieve -> {blocks: ContextBlock[], total_tokens: number}. HTTP POST /v1/memory/retrieve (Bearer auth). Full contract: fusion-memory/clients/README.md.

Degradation

fm-server down / FUSION_MEMORY_API_KEY unset / no memory matched -> section is empty, nothing injected, debug log only. Never blocks the main loop. 100% offline — HTTP only to 127.0.0.1.

Config (operator env, same as #151)

Env Default Purpose
FUSION_MEMORY_BASE_URL http://127.0.0.1:11440 fm-server base URL
FUSION_MEMORY_API_KEY (none) Bearer token; if unset, retrieve is skipped
FUSION_MEMORY_RETRIEVE_TOP_K 10 top-k memories to recall
FUSION_MEMORY_RETRIEVE_BUDGET 4096 token budget for retrieved context

Tests

10 tests in retrieveContext.test.ts (subagent skip, empty input, success format, RPC error, HTTP non-2xx, fetch throw, missing API key, no-match, top_k env override, invalid env fallback). Full memory suite 25 pass, bun run build green (verified against current main incl. #155).

Scope

Closes #154. Completes the retrieve half deferred by #151 (which landed
turn-end commit only). fusion-cowork #68 and fusion-agent-studio #247
already have both commit+retrieve; this brings fusion-code to parity.

## What

At main-agent turn start (processUserInput), recall relevant cross-session
memory from fusion-memory (fm-server) and inject it as an attachment message
on the same path as UserPromptSubmit hook additionalContext. The agent now
starts each turn with relevant prior context, not stateless.

## How

- src/services/memory/retrieveContext.ts (new) — retrieveMemorySection():
  calls the existing retrieveContext RPC + formatContextToPrompt (both added
  by #151 but unwired), returns a <fusion_memory_context> section string or
  . Main-agent guard (!agentId), fail-empty (logForDebugging, never throws).
  Env override: FUSION_MEMORY_RETRIEVE_TOP_K / FUSION_MEMORY_RETRIEVE_BUDGET.
- src/utils/processUserInput/processUserInput.ts (edit) — after UserPromptSubmit
  hooks, on the happy path with real input and !context.agentId, fire-and-forget
  retrieveMemorySection and push the section as a hook_additional_context
  attachment message. Mirrors the existing hook additionalContext push. Skips
  silently if fm-server down or FUSION_MEMORY_API_KEY unset.

## Degradation

fm-server down / FUSION_MEMORY_API_KEY unset / no memory matched -> section
is empty, nothing injected, debug log only. Never blocks the main loop.
100% offline — HTTP only to 127.0.0.1.

## Tests

10 tests in retrieveContext.test.ts (subagent skip, empty input, success
format, RPC error, HTTP non-2xx, fetch throw, missing API key, no-match,
top_k env override, invalid env fallback). Full memory suite 25 pass,
bun run build green.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Retrieve-inject long-term memory into main-agent system prompt (follow-up to #151)

1 participant