Skip to content

feat: Replace Weaviate knowledge base with unified memory system - #556

Open
OlivierTrudeau wants to merge 72 commits into
mainfrom
feat/memory-system
Open

feat: Replace Weaviate knowledge base with unified memory system#556
OlivierTrudeau wants to merge 72 commits into
mainfrom
feat/memory-system

Conversation

@OlivierTrudeau

@OlivierTrudeau OlivierTrudeau commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Description

Replaces the Weaviate-based Knowledge Base with a unified Memory system stored in PostgreSQL. Org knowledge (context, runbooks, infrastructure, learned patterns, postmortems) lives in the artifacts table with categories, versioning, and a table-of-contents index injected into the agent system prompt. The agent reads memory on demand via tools instead of vector search. Existing KB data is migrated automatically on upgrade via a one-time Celery task. Weaviate is removed from the Docker Compose dev stack.

What changed

  • Memory stored in artifacts table with new category and description columns; unique index on (org_id, category, title)
  • Memory categories: context, runbook, infrastructure, learned, postmortem (legacy rows backfilled as artifact)
  • New REST API at /api/memory — list, create, get, delete entries; file upload for .md, .txt, .pdf
  • RBAC: memory:read for viewers, memory:write for editors
  • New Settings → Memory UI replacing Knowledge Base settings
  • New agent tools: list_memories, read_memory, write_memory, append_to_memory, edit_memory, grep_memories
  • Memory index (build_memory_index) injected into system prompt so the agent knows what exists and calls read_memory() on demand
  • New memory.md skill — shared behavioral contract for foreground chat and background RCA
  • Documents stored whole (no splitting) — agent paginates large entries via offset/limit params on read_memory
  • PDF uploads converted to text via pypdf before storage
  • Versioning on every write via services/artifacts/store.py
  • Postmortems migrated from postmortems table into artifacts with category='postmortem'
  • One-time Celery migration (migrate_kb_to_memory) — auto-triggered on startup if old KB data exists and nothing migrated yet
    • knowledge_base_memorycontext ("Org Context")
    • infrastructure_contextinfrastructure ("Infrastructure Context")
    • knowledge_base_documents (S3) → runbook entries (PDF/text extracted)
    • postmortemspostmortem entries (titled from incident alert_title)
  • MCP: added list_memories and read_memory; search_runbooks now queries memory runbooks
  • Prediscovery prompt updated to write infrastructure via write_memory instead of old KB tools
  • Sub-agent orchestrator metadata updated for memory tool capability tags
  • Removed Weaviate container, env vars, weaviate_client dependency, and health check from Docker Compose
  • Removed Knowledge Base UI, API routes, and blueprint registration
  • Removed old agent tools: knowledge_base_search, rag_indexer, infra_context_tool, save_discovery_finding
  • Removed incident feedback UI and Weaviate-backed feedback routes
  • Removed Aurora Learn user preference
  • Removed knowledge_base.cleanup_stale_documents Celery periodic task
  • MCP deprecated stubs for removed tools (chat_with_aurora, ask_incident, regenerate_rca)

What to test

  • Fresh install: server starts without Weaviate; artifacts table has category/description columns and unique index
  • Upgrade migration: existing KB data migrates into Memory on startup; check celery logs for [Migration] Complete; restart does not duplicate entries
  • Mulitple user knowledge base migrated without collisions or issues
  • Settings → Memory tab loads and replaces old Knowledge Base tab
  • Create, list, filter by category, and delete memory entries in the UI
  • Viewer can read but not write; editor has full write access
  • Upload small .md, .txt, and .pdf files — content stored correctly, PDF text extracted with page markers
  • Upload large files — stored whole as single entry; no splitting
  • Manual create rejects content over 500 KB
  • Chat: agent reads memory when asked ("what do you remember about…")
  • Chat: agent writes memory when asked to remember something — entry appears in Settings
  • Chat: grep_memories, append_to_memory, and edit_memory work as expected
  • Chat: agent can delete/forget memory entries on request
  • Chat works normally with empty memory (no errors)
  • Agent edit_memory rejects ambiguous matches (multiple occurrences of old_text)
  • Agent read_memory paginates large entries correctly via offset/limit
  • Trigger RCA — agent uses memory tools during investigation
  • Prediscovery (if enabled) creates/updates infrastructure/Infrastructure Context entry
  • MCP: list_memories, read_memory, and search_runbooks return expected results
  • Postmortems visible in Memory UI under "Postmortem" category
  • Incidents still work; incident feedback UI is gone (expected)
  • /health passes without Weaviate
  • No Weaviate/knowledge-base errors in server or celery logs during chat/RCA
  • Memory entries are org-scoped — Org A data not visible to Org B
  • Same title allowed in different categories; same (category, title) upserts instead of duplicating

@OlivierTrudeau
OlivierTrudeau requested a review from a team as a code owner June 25, 2026 20:43
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The PR replaces knowledge-base, incident-feedback, and Weaviate-backed paths with memory-backed API routes, tools, prompts, and UI surfaces. It also updates database, Celery, and deployment wiring to use memory artifacts and remove the old feedback and Weaviate registrations.

Changes

Memory cutover

Layer / File(s) Summary
Client memory surface
client/src/app/api/proxy/memory/[...path]/route.ts, client/src/components/MemorySettings.tsx, client/src/components/SettingsModal.tsx, client/src/app/incidents/components/IncidentCard.tsx, client/src/components/tool-calls/*, client/src/app/api/incidents/[id]/feedback/route.ts, client/src/app/api/feedback/route.ts
The client exposes a Memory settings tab through the proxy route, removes the incident feedback section and feedback API handlers, and renames memory-related tool labels and icons.
Memory API and persistence
server/services/memory/__init__.py, server/services/memory/splitter.py, server/routes/memory/__init__.py, server/routes/memory/routes.py, server/services/artifacts/store.py, server/utils/auth/enforcer.py, server/utils/db/db_utils.py, server/main_compute.py, docker-compose*.yml
The new memory blueprint serves artifact-backed list/create/read/delete/upload endpoints, and the auth, schema, app-registration, Celery, and deployment wiring add memory permissions, category support, route registration, and service removal.
Memory migration and indexing
server/services/memory/index_builder.py, server/services/memory/migration_task.py, server/celery_config.py, server/utils/db/db_utils.py
The memory index builder and KB-to-memory migration task convert legacy knowledge-base records into artifacts, with Celery and DB initialization wiring the migration.
Memory tool implementation
server/chat/backend/agent/tools/memory_tool.py
The org-scoped memory tool module adds list/read/write/append/edit/grep helpers over artifacts with RLS, validation, and versioning.
Tool registration and MCP exposure
server/aurora_mcp/*, server/chat/backend/agent/tools/cloud_tools.py, server/chat/backend/agent/tools/rag_indexer_tool.py, server/chat/background/citation_extractor.py
MCP dispatch, runbook resources, always-on tools, cloud tool registration, and citation labels switch from knowledge-base and RAG tooling to memory helpers.
Prompt and skill updates
server/chat/backend/agent/orchestrator/select_skills.py, server/chat/backend/agent/prompt/*, server/chat/backend/agent/skills/*, server/chat/background/prediscovery_task.py, server/chat/background/rca_prompt_builder.py
Prompt composition, skill metadata, and background prompt/task text reference memory segments and workflows instead of the removed knowledge-base prompt injection.
Weaviate removal and runtime wiring
server/chat/backend/agent/agent.py, server/chat/backend/agent/orchestrator/sub_agent.py, server/chat/background/task.py, server/main_chatbot.py, server/requirements.txt, docker-compose*.yml
The agent runtime and deployment wiring stop constructing Weaviate clients, and the compose and requirements files remove the Weaviate service and client dependency.
Incident feedback route removal
server/routes/incident_feedback/*
The Flask incident feedback blueprint and its Weaviate-backed helpers are removed from the server routes package.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~90+ minutes

Possibly related PRs

  • Arvo-AI/aurora#173: Directly related to the prediscovery flow this PR rewrites from Weaviate-based discovery findings to memory writes.
  • Arvo-AI/aurora#257: The prompt-composition changes in this PR reuse the same prompt architecture and memory-injection path touched by that earlier prompt work.
  • Arvo-AI/aurora#395: The main PR is related because it removes incident_submit_feedback from the MCP dispatch allowlist, directly building on the MCP hybrid tool/allowlist system introduced there.

Suggested reviewers

  • damianloch
  • isiddharthsingh

Poem

I hopped through memory gardens bright,
and tucked old thorns out of sight.
New runbooks bloomed in rows of green,
with softer tabs and prompts unseen.
🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 78.95% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: replacing the Weaviate-backed knowledge base with a unified memory system.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/memory-system

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread server/routes/memory/routes.py Fixed
Comment thread server/chat/backend/agent/prompt/background.py Fixed

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

OlivierTrudeau and others added 2 commits July 6, 2026 14:05
* Remove t2v-transformers container

The embedding service was only used by the correlation engine's
SimilarityStrategy, which already had a Jaccard fallback. This
removes the container entirely and simplifies the strategy to
use Jaccard token similarity directly, reducing resource usage
and deployment complexity.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Add optional EMBEDDING_MODEL support for alert correlation

Replaces the removed t2v-transformers container with an optional,
provider-agnostic embedding client. Users can set EMBEDDING_MODEL
(e.g., openai/text-embedding-3-small) to enable semantic similarity;
otherwise the system falls back to Jaccard token similarity.

Supported providers: openai, google, bedrock — reuses existing
API keys already configured for the LLM.

Co-authored-by: Cursor <cursoragent@cursor.com>

* mini

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
…#578)

* refactor: eliminate postmortem tables in favor of artifacts

Postmortems are now stored as artifacts with category='postmortem' and
an incident_id FK. The old postmortems/postmortem_versions tables still
exist (data preserved) but are no longer read or written by any code path.

- Add incident_id + generation_session_id columns to artifacts table
- Rewrite postmortem_tool.py to read/write artifacts directly
- Rewrite all 10 postmortem_routes.py endpoints against artifacts +
  artifact_versions (same API contract, frontend unchanged)
- Rewrite postmortem_action.py reservation logic to insert into artifacts
- Update Notion export to read from artifacts, drop legacy UPDATE
- Update introspection_tools list_postmortems to query artifacts
- Remove postmortem section from memory migration_task (now at startup)
- Drop FK constraint on postmortem_exports so it accepts artifact UUIDs
- Startup migration backfills existing postmortem data into artifacts

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix

* fix for managed sql

* adress ben comments

---------

Co-authored-by: Cursor <cursoragent@cursor.com>

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

… prompt (#583)

* feat: add memory injector — async prefetch injects relevant memories into prompt

Single-pass LLM selector picks up to 5 memories from the index based on
title + description, reads their full content, and injects into the system
prompt. Runs as a non-blocking prefetch in parallel with prompt building.

- Fires early in agentic_tool_flow before prompt segments are built
- Consumed in composer.py alongside the static memory index
- Session-level dedup and 60KB cumulative budget via Redis
- Staleness headers on old memories
- 4KB per-file cap with truncation note

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor: extract memory data-access helpers into queries.py

Move get_memory_entries and fetch_memory_content out of index_builder.py
into a dedicated queries module. index_builder now only handles index
formatting, and injector imports directly from queries.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor: use centralized RCA_MODEL and reorder class before function

Use ModelConfig.RCA_MODEL instead of a one-off env var for the memory
selector. Move MemoryPrefetch class above start_memory_prefetch so the
forward reference is no longer needed.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor: inline prefetch pipeline into MemoryPrefetch._execute

Remove the _run_prefetch wrapper function and put the pipeline logic
directly in the class method that runs it.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor: simplify memory injector — remove budget tracking, wrapper, and min-length guard

- Remove session byte budget (redundant with context trim middleware)
- Remove start_memory_prefetch wrapper (caller uses MemoryPrefetch directly)
- Remove MIN_QUERY_LENGTH gate (short queries like "db down" are valid)
- Remove redundant MAX_INDEX_ENTRIES constant (default lives in queries.py)

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix memory injecter

* j

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread server/services/memory/injector.py Fixed

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aurora Risk Review — Latest changes

Verdict: RISKY

Reviewed the latest changes. The new MemoryPrefetch system introduces a synchronous blocking call (Future.result(timeout=6.0)) inside the async agentic_tool_flow coroutine, which will stall the asyncio event loop for up to 6 seconds on every chat turn for every user who has memory entries. Additionally, the module-level ThreadPoolExecutor(max_workers=4) is a process-wide singleton shared across all concurrent users; under modest concurrency the pool saturates and the blocking wait compounds, degrading all chat responses simultaneously.

Findings

# Severity File Finding
1 HIGH server/chat/backend/agent/agent.py:380 Blocking Future.result() called inside async coroutine — stalls event loop up to 6s per chat turn
2 MEDIUM server/services/memory/injector.py:39 Process-wide ThreadPoolExecutor(max_workers=4) saturates under concurrent chat load, compounding the event-loop block

Aurora reviews PRs for incident prevention. This is advisory only and does not block merge.

Comment thread server/chat/backend/agent/agent.py
Comment thread server/services/memory/injector.py Outdated
* feat: add memory collector and dream consolidation

Collector: Celery task that fires after each turn, reads the conversation,
and saves durable learnings to org memory via LLM extraction.

Consolidation (Dream): Nightly Celery Beat task that reviews all org
memories, merges duplicates, removes stale entries, and keeps the memory
bank clean and well-organized.

- Collector hooked into workflow.py (interactive) and task.py (RCA)
- Consolidation scheduled via celery beat (default: every 24h)
- Redis-based distributed lock prevents parallel consolidations per org
- Both tasks registered in celery_config.py includes + beat_schedule

Co-authored-by: Cursor <cursoragent@cursor.com>

* update collector

* udpates

* latest

* change consolidation to make it an action

* change prompt a bit

* mo

* jj

* update

* comments

---------

Co-authored-by: Cursor <cursoragent@cursor.com>

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aurora Risk Review — Latest changes

Verdict: RISKY

Reviewed the latest changes. The backfill value change from 'artifact' to 'context' introduces a category mismatch with the hardcoded INSERT in store.py, which still writes category='artifact' on every upsert. After this migration runs, pre-existing artifacts are stamped 'context' in the DB but the upsert conflict key targets 'artifact', so every subsequent write to an existing artifact silently creates a duplicate row instead of updating it. The DEFAULT column change is correct and safe; the backfill value change is the risk.

Findings

# Severity File Finding
1 HIGH server/utils/db/db_utils.py:3018 Backfill value 'context' conflicts with hardcoded category='artifact' in store.py upsert

Aurora reviews PRs for incident prevention. This is advisory only and does not block merge.

Comment thread server/utils/db/db_utils.py Outdated
""")
# Back-fill any rows missing a category
cursor.execute("""
UPDATE artifacts SET category = 'context' WHERE category IS NULL OR category = '';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] Backfill value 'context' conflicts with hardcoded category='artifact' in store.py upsert

This migration stamps all NULL/empty category rows as 'context', but server/services/artifacts/store.py:upsert_artifact_by_title always inserts with category='artifact' and relies on ON CONFLICT (org_id, category, title) for idempotency. After deploy, any artifact that existed before this migration will have category='context' in the DB, so the conflict clause (keyed on 'artifact') will never fire — every agent or UI write to a pre-existing artifact will INSERT a new duplicate row under category='artifact' instead of updating the original. This silently corrupts artifact state for all existing orgs on upgrade, breaking the write_artifact / write_memory tools and causing the memory system to accumulate phantom duplicates.

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aurora Risk Review — Latest changes

Verdict: RISKY

Reviewed the latest changes. The fix correctly identifies that FORCE ROW LEVEL SECURITY blocks the original bulk UPDATE, but the seed query that discovers which orgs need backfilling (SELECT DISTINCT org_id FROM artifacts WHERE ...) runs before any myapp.current_org_id is set, so it will itself be filtered to zero rows by the same RLS policy it is trying to work around. The loop never executes, backfill_orgs is empty, and the subsequent ALTER COLUMN SET NOT NULL will still raise a constraint violation on any production instance that has NULL-category artifact rows — crashing initialize_tables() on startup.

Findings

# Severity File Finding
1 HIGH server/utils/db/db_utils.py:3018 Seed SELECT for backfill loop is itself blocked by RLS — loop never runs, NOT NULL migration still fails

Aurora reviews PRs for incident prevention. This is advisory only and does not block merge.

Comment thread server/utils/db/db_utils.py Outdated
""")
# Backfill per-org to satisfy RLS (FORCE is already active)
cursor.execute("SELECT DISTINCT org_id FROM artifacts WHERE category IS NULL OR category = ''")
backfill_orgs = [row[0] for row in cursor.fetchall()]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] Seed SELECT for backfill loop is itself blocked by RLS — loop never runs, NOT NULL migration still fails

The new code does SELECT DISTINCT org_id FROM artifacts WHERE category IS NULL OR category = '' with no myapp.current_org_id set in the session. Because FORCE ROW LEVEL SECURITY is active on artifacts and the RLS policy gates visibility on current_setting('myapp.current_org_id'), this query returns zero rows regardless of actual table contents. backfill_orgs is always empty, the per-org UPDATE loop never fires, and the immediately-following ALTER TABLE artifacts ALTER COLUMN category SET NOT NULL will raise ERROR: column "category" of relation "artifacts" contains null values on any production database that has legacy NULL-category rows — causing server startup to abort. The fix requires either (a) executing the seed SELECT via a BYPASSRLS role/connection, (b) using a raw SET LOCAL myapp.current_org_id = '' bypass sentinel that the RLS policy explicitly allows for admin operations, or (c) restructuring the migration to run before RLS FORCE is applied to the table.

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@sonarqubecloud

Copy link
Copy Markdown

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.

3 participants