Skip to content

feat(memory): replace prompt injection to use mempalace pipeline [phase-5] #358

@quangdang46

Description

@quangdang46

Problem

jcode's memory prompt injection (build_memory_prompt_nonblocking) reads from PENDING_MEMORY which is populated by the async MemoryAgent singleton. When using mempalace, the pipeline should go through mempalace's ActivityEvent system and Palace search instead of the current MemoryAgent::process_context() path.

Scope

Files: crates/jcode-base/src/memory_agent.rs, crates/jcode-base/src/memory/pending.rs, crates/jcode-app-core/src/agent/prompting.rs, crates/jcode-tui/src/tui/app/turn_memory.rs

  1. When memory_backend = "mempalace":

    • Bypass the existing MemoryAgent singleton entirely
    • Instead, spawn a mempalace-native pipeline per turn:
      embed context → search Palace → verify (sidecar) → surface → maintenance
      
    • Write results into the same PENDING_MEMORY static so take_pending_memory() continues to work unchanged
  2. Mempalace-native per-turn pipeline:

    async fn mempalace_per_turn_pipeline(
        palace: &Palace,
        context: &str,
        session_id: &str,
        working_dir: &Path,
    ) {
        // 1. Embed context
        let query_vec = palace.embedder().embed(context).await?;
        // 2. Search
        let hits = palace.search_with_embedding(&query_vec, &scope).await?;
        // 3. Verify (if sidecar enabled)
        let verified = sidecar_verify(&hits, context).await?;
        // 4. Surface → set_pending_memory()
        let prompt = format_entries_for_prompt(&verified);
        set_pending_memory_with_ids(session_id, &prompt, verified_ids);
        // 5. Maintenance (spawned, non-blocking)
        tokio::spawn(maintenance.run(ctx));
    }
  3. Activity event mapping: Map mempalace ActivityEvent → jcode MemoryEventKind for TUI compatibility:

    Embedding → MemoryState::Embedding
    SidecarChecking → MemoryState::SidecarChecking
    FoundRelevant → MemoryState::FoundRelevant
    Extracting → MemoryState::Extracting
    Maintaining → MemoryState::Maintaining
    
  4. Topic change detection: Keep jcode's cosine similarity check (< 0.3 threshold) as the trigger for incremental extraction, but call palace.extract_from_transcript() instead of sidecar.extract_memories_with_existing().

  5. Final extraction: On session end, call palace.extract_from_transcript(full_transcript, session_id) instead of MemoryAgent::trigger_final_extraction().

Acceptance Criteria

  • Memory prompt injection works through mempalace pipeline
  • TUI shows same activity states (Embedding, SidecarChecking, FoundRelevant, etc.)
  • take_pending_memory() still works unchanged
  • Turn N+1 latency preserved (non-blocking pipeline)
  • Topic change detection triggers extraction
  • Final extraction on session end works
  • Feature-gated behind memory_backend = "mempalace"
  • cargo test --workspace passes

Dependencies

Reference

jcode prompt injection: crates/jcode-app-core/src/agent/prompting.rs lines 20-48
jcode PendingMemory: crates/jcode-base/src/memory/pending.rs lines 39-199
jcode MemoryAgent pipeline: crates/jcode-base/src/memory_agent.rs lines 395-643
jcode TUI memory injection: crates/jcode-tui/src/tui/app/turn_memory.rs lines 98-228
mempalace ActivityEvent: crates/core/src/palace.rs lines 1248-1278

Metadata

Metadata

Assignees

No one assigned

    Labels

    mp-migrationjcode → mempalace memory migrationphase-5Migration Phase 5 (jcode adapter)

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions