spacedriveapp / spacedriveapp/spacebot
Ingestion: memory_persistence_complete false negatives cause duplicate memories on retry
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 2.4k
- Forks
- 367
- PR merge metrics
- No merged PRs in 30d
Description
Problem
The ingestion pipeline (src/agent/ingestion.rs) has two compounding issues that cause duplicate memories when using non-Anthropic models:
Issue 1: memory_persistence_complete check is too strict
When the model calls memory_persistence_complete successfully but then generates text afterward (common with non-Claude models), the chunk is marked as failed even though:
memory_savewas called and data was committed to the DBmemory_persistence_completewas called and returned success- The model simply added a text summary after the tool call
The prompt_once() approach in ingestion (line ~529) lacks the retry mechanism that branch.rs has (MAX_MEMORY_CONTRACT_RETRIES = 2). The branch code injects a retry prompt "You must finish this memory-persistence run by calling memory_persistence_complete..." — ingestion has no equivalent.
Issue 2: Retries create duplicate memories with no deduplication
When a chunk "fails" (even falsely):
- Memories already committed by
memory_saveremain in the DB (no rollback) - The chunk is NOT recorded as completed in
ingestion_progress - On retry, a fresh agent processes the same chunk with zero context about previously saved memories
memory_savedoes a plain INSERT withUuid::new_v4()— no content-hash dedup- Result: duplicate memories from the same chunk content
Issue 3: ToolUseEnforcement::Auto doesn't cover non-GPT/non-Codex models
The default Auto mode only injects the enforcement prompt for models with "gpt" or "codex" in the name. Models like MiniMax, Step Flash, Gemma, DeepSeek, etc. get no enforcement prompt, making them more likely to generate text instead of calling required tools.
Combined with the ingestion prompt (prompts/en/ingestion.md.j2) telling the model to "Return a brief summary of what you extracted," the model is incentivized to generate text rather than call memory_persistence_complete.
Observed Behavior
Using openrouter/stepfun/step-3.5-flash for branch routing:
- model calls
memory_save✅ (memories saved) - model calls
memory_persistence_complete✅ (success returned) - model generates post-tool summary text
- chunk marked as FAILED ❌ (false negative)
- file kept for retry → creates duplicates
With openrouter/minimax/minimax-m2.7:
- Similar pattern but lower tool compliance (~0% success vs ~44% with Step Flash)
Suggested Fixes
-
Add retry loop to ingestion (parity with
branch.rs): Whenhas_terminal_outcome()is false afterprompt_once(), inject the retry prompt and give 2 more attempts — matchingMAX_MEMORY_CONTRACT_RETRIES -
Check if
memory_persistence_completewas called at any point, not just as the terminal action. If the tool was called and returned success, the chunk should be marked complete regardless of post-tool text. -
Deduplication on retry: Either (a) add content-hash dedup to
memory_save, (b) record saved memory IDs per chunk iningestion_progressand delete them before retry, or (c) use a transaction that rolls back memories if the chunk fails to complete. -
Widen
ToolUseEnforcement::Autoto cover more model families, or document that non-Claude/non-GPT models should settool_use_enforcement = "always"in config.
Environment
- Spacebot deployed via Coolify (Docker)
- Models via OpenRouter: MiniMax M2.7, Step 3.5 Flash
tool_use_enforcement = "always"set as workaround- Config:
[agents.convey.routing] branch = "openrouter/stepfun/step-3.5-flash"
Workaround
Set tool_use_enforcement = "always" in config. This improves but doesn't fully resolve the issue since the ingestion code path still lacks the retry mechanism.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/agent/ingestion.rs around prompt_once() and compare its outcome handling with the retry logic in branch.rs, including MAX_MEMORY_CONTRACT_RETRIES. Review prompts/en/ingestion.md.j2 and the ToolUseEnforcement::Auto behavior, then verify that successful memory_persistence_complete calls do not produce false failures or duplicate memories when chunks are retried.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- ai, backend, databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100