Skip to content

feat: agent memory & institutional knowledge base - #47

Open
joshuajerin wants to merge 2 commits into
10xapp:mainfrom
joshuajerin:feat/agent-memory
Open

feat: agent memory & institutional knowledge base#47
joshuajerin wants to merge 2 commits into
10xapp:mainfrom
joshuajerin:feat/agent-memory

Conversation

@joshuajerin

@joshuajerin joshuajerin commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds agent memories system with 4 memory types (episodic, semantic, procedural, preference), vector embeddings (1536d), relevance decay, access tracking, and similarity search via search_agent_memories() RPC
  • Adds workspace knowledge base with category/key/value entries, vector search via search_knowledge_base() RPC, confidence scoring, and human verification flow
  • Full stack: Supabase migration, Python service + FastAPI router (12 endpoints), TypeScript API client, Zustand store with realtime handlers

Files

Layer File What
Migration core-api/supabase/migrations/20260409000003_agent_memory.sql Tables, RLS, vector indexes, RPC functions, triggers, grants
Service core-api/api/services/agents/memory.py CRUD + vector search + embedding generation (OpenAI)
Router core-api/api/routers/agent_memory.py 12 endpoints with Pydantic models
Registration core-api/index.py Router registration
API Client core-web/src/api/client.ts TypeScript types + fetch wrappers
Store core-web/src/stores/agentMemoryStore.ts Zustand store with persist + realtime

Branch 3 of the Agent Infra Plan

Test plan

  • Run migration against local Supabase
  • Verify RLS policies enforce workspace membership
  • Test memory CRUD endpoints via API
  • Test knowledge base CRUD + verify flow
  • Test vector search with embeddings (requires OPENAI_API_KEY)
  • Verify graceful degradation when embedding generation fails
  • Confirm frontend store hydrates and updates correctly

Summary by CodeRabbit

New Features

  • Agent memory system: store, list, search, update, and delete agent-specific memories
  • Workspace knowledge base: add categorized knowledge entries with verification support
  • Semantic search across memories and knowledge entries
  • Automatic memory decay to maintain relevance over time
  • Optional tagging for memories and confidence scoring for knowledge entries

Migration, service, router, API client, and Zustand store for:
- Agent memories with vector embeddings, decay, and similarity search
- Workspace knowledge base with category/key/value entries and verification
@coderabbitai

coderabbitai Bot commented Apr 14, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@joshuajerin has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 38 minutes and 38 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 38 minutes and 38 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 260b51dd-6c40-4f3c-9197-eb979c8c72b9

📥 Commits

Reviewing files that changed from the base of the PR and between 76f99d8 and 02ba22a.

📒 Files selected for processing (4)
  • core-api/api/routers/agent_memory.py
  • core-api/api/services/agents/memory.py
  • core-api/supabase/migrations/20260409000003_agent_memory.sql
  • core-web/src/stores/agentMemoryStore.ts
📝 Walkthrough

Walkthrough

This PR adds agent memory and workspace knowledge-base features by introducing backend API endpoints, async service layer functions, and Supabase database tables with vector search capability. Frontend TypeScript interfaces, API client functions, and a Zustand store enable client-side state management and API interactions.

Changes

Cohort / File(s) Summary
Backend API Router
core-api/api/routers/agent_memory.py
Defines FastAPI endpoints for agent memory CRUD (store, list, search, update, delete) and workspace knowledge-base operations (add, list, search, verify, delete), with Pydantic request/response schemas, auth dependency injection, error handling, and structured response payloads.
Backend Service Layer
core-api/api/services/agents/memory.py
Implements async service functions for memory and knowledge-base operations: insertion with embedding generation, retrieval with filtering, vector similarity search via Supabase RPC, updates, deletion, and access tracking. Includes helper for OpenAI embedding generation with graceful fallback.
Database Schema
core-api/supabase/migrations/20260409000003_agent_memory.sql
Creates agent_memories and agent_knowledge_base tables with vector columns, similarity search RPC functions, decay/expiration logic, Row Level Security policies scoped to workspace members, and supporting indexes (btree and ivfflat for vector similarity).
App Integration
core-api/index.py
Registers the new agent_memory router with the FastAPI application.
Frontend API Client
core-web/src/api/client.ts
Introduces TypeScript interfaces (AgentMemory, MemorySearchResult, KnowledgeEntry, KnowledgeSearchResult) and async client functions to call memory and knowledge-base endpoints (GET/POST/PATCH/DELETE operations).
Frontend State Management
core-web/src/stores/agentMemoryStore.ts
Zustand store managing agent memories and workspace knowledge with caching, collections, search results, loading flags, and realtime handlers; persists only current selection identifiers.

Sequence Diagram(s)

sequenceDiagram
    actor Client as Client
    participant Router as API Router
    participant Service as Service Layer
    participant OpenAI as OpenAI API
    participant Supabase as Supabase DB

    Client->>Router: POST /agents/{id}/memories (store_memory_endpoint)
    activate Router
    Router->>Service: store_memory(agent_id, memory_type, content, ...)
    activate Service
    Service->>OpenAI: Generate embedding for content
    activate OpenAI
    OpenAI-->>Service: embedding vector (1536D)
    deactivate OpenAI
    Service->>Supabase: INSERT into agent_memories (content, embedding, ...)
    activate Supabase
    Supabase-->>Service: {id, created_at, ...}
    deactivate Supabase
    Service-->>Router: MemoryResponse
    deactivate Service
    Router-->>Client: 200 OK {memory}
    deactivate Router

    Client->>Router: POST /agents/{id}/memories/search (search_memories_endpoint)
    activate Router
    Router->>Service: search_memories(agent_id, query, ...)
    activate Service
    Service->>OpenAI: Generate embedding for query
    activate OpenAI
    OpenAI-->>Service: embedding vector (1536D)
    deactivate OpenAI
    Service->>Supabase: CALL search_agent_memories(embedding, ...)
    activate Supabase
    rect rgba(100, 150, 200, 0.5)
    Note over Supabase: Vector similarity search<br/>(ivfflat cosine index)
    end
    Supabase-->>Service: [{id, content, similarity, ...}, ...]
    deactivate Supabase
    Service-->>Router: MemorySearchResponse
    deactivate Service
    Router-->>Client: 200 OK {results, count}
    deactivate Router

    Client->>Router: POST /knowledge/{id}/verify (verify_knowledge_endpoint)
    activate Router
    Router->>Service: verify_knowledge(knowledge_id, verified_by)
    activate Service
    Service->>Supabase: UPDATE agent_knowledge_base (verified_by, verified_at)
    activate Supabase
    Supabase-->>Service: {id, verified_by, verified_at, ...}
    deactivate Supabase
    Service-->>Router: KnowledgeResponse
    deactivate Service
    Router-->>Client: 200 OK {knowledge}
    deactivate Router
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 wiggles whiskers with delight
Memory vectors dance through the night,
Knowledge gardens bloom with care,
Embeddings twirl through database air,
Now every thought finds its place so bright! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: agent memory & institutional knowledge base' accurately and concisely summarizes the primary changes—adding agent memory and workspace knowledge base systems across the full stack.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

@coderabbitai coderabbitai 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.

Actionable comments posted: 5

🧹 Nitpick comments (4)
core-api/supabase/migrations/20260409000003_agent_memory.sql (2)

120-140: Consider adding an index to optimize the decay_agent_memories function.

The decay_agent_memories function performs a full table scan filtering on last_accessed_at < NOW() - INTERVAL '7 days' and expired_at IS NULL. For large datasets, this could be slow.

Consider adding a partial index to optimize decay queries:

📊 Proposed index for decay optimization
-- Add after existing indexes (around line 252)
CREATE INDEX "idx_agent_memories_decay_candidates" 
  ON "public"."agent_memories" USING "btree" ("last_accessed_at")
  WHERE "expired_at" IS NULL AND "relevance_score" > 0.01;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core-api/supabase/migrations/20260409000003_agent_memory.sql` around lines
120 - 140, Add a partial btree index to speed the decay_agent_memories() updates
by indexing agent_memories.last_accessed_at for only non-expired, still-relevant
rows; create an index named idx_agent_memories_decay_candidates on
agent_memories(last_accessed_at) with a WHERE clause restricting to expired_at
IS NULL AND relevance_score > 0.01 and add it alongside the other agent_memories
indexes so the UPDATEs in decay_agent_memories() can use the index instead of a
full table scan.

246-246: IVFFlat indexes perform poorly on empty tables; consider HNSW or add post-population rebuild documentation.

IVFFlat requires bulk-loaded data for effective clustering. When created on empty tables before data exists, the index won't provide accurate similarity search until rebuilt after data is populated. For these migration indexes:

  1. Switch to HNSW if data is populated incrementally (recommended for dynamic workloads):

    CREATE INDEX "idx_agent_memories_embedding" ON "public"."agent_memories" 
      USING "hnsw" ("embedding" vector_cosine_ops);
  2. Or document that REINDEX must be executed after initial data load, and periodically as the dataset grows.

Also applies to line 259 (agent_knowledge_base_embedding).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core-api/supabase/migrations/20260409000003_agent_memory.sql` at line 246,
The IVFFlat index on "idx_agent_memories_embedding" (table agent_memories) is
suboptimal when created on empty or incrementally populated tables; either
change the index to HNSW by replacing the USING "ivfflat" clause with USING
"hnsw" for idx_agent_memories_embedding (and similarly for
idx_agent_knowledge_base_embedding on agent_knowledge_base) or add a
migration-note that documents running REINDEX/REBUILD after initial bulk load
and periodically as the dataset grows; update the migration SQL or accompanying
migration README to reflect the chosen approach so similarity searches are
accurate post-population.
core-api/api/routers/agent_memory.py (1)

208-210: All exceptions return HTTP 400, masking server-side errors.

The catch-all except Exception blocks uniformly return status_code=400. This masks infrastructure failures (DB down, timeout, etc.) as client errors, making debugging harder and violating REST semantics where 5xx indicates server issues.

Consider distinguishing error types:

🔧 Suggested pattern for better error classification
+from fastapi import status
+
 `@router.post`("/agents/{agent_id}/memories", response_model=MemoryResponse)
 async def store_memory_endpoint(...):
     try:
         memory = await store_memory(...)
         return memory
+    except ValueError as e:
+        # Client-side validation errors
+        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
     except Exception as e:
         logger.error(f"Error storing memory: {e}")
-        raise HTTPException(status_code=400, detail=str(e))
+        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Internal server error")

Also applies to: 224-226, 246-248, 266-268, 280-282, 308-310, 324-326, 345-347, 360-362, 374-376

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core-api/api/routers/agent_memory.py` around lines 208 - 210, The current
catch-all except Exception blocks (e.g., the one logging "Error storing memory")
always return HTTP 400; change them to classify errors: re-raise existing
HTTPException unchanged, map validation/argument errors (ValueError, TypeError)
to HTTP 400 (or 422), map not-found semantics to 404 if you have a
NotFound/KeyError, and for any other unexpected exceptions log full traceback
via logger.exception(...) and raise HTTPException(status_code=500,
detail="Internal server error"). Update all similar handlers (the shown block
and the other except blocks referenced) so client errors return 4xx and
server/infrastructure failures return 5xx, and ensure logs include traceback for
diagnostics.
core-web/src/stores/agentMemoryStore.ts (1)

117-122: Mutation actions lack error handling unlike fetch/search actions.

The addMemory, editMemory, removeMemory, addKnowledge, verifyKnowledge, and removeKnowledge actions don't wrap API calls in try/catch blocks, unlike the fetch and search actions. If the API call fails after optimistically updating state (or vice versa), the UI state could become inconsistent.

Currently, errors propagate to the caller which may be intentional. However, for consistency and to prevent potential state desync, consider adding try/catch with rollback logic or documenting that callers must handle errors.

💡 Example: Adding error handling with rollback for removeMemory
 removeMemory: async (memoryId) => {
+  const { memories } = get();
+  // Optimistic update
+  set({ memories: memories.filter((m) => m.id !== memoryId) });
+  try {
     await deleteAgentMemory(memoryId);
-  const { memories } = get();
-  set({ memories: memories.filter((m) => m.id !== memoryId) });
+  } catch (err) {
+    // Rollback on failure
+    set({ memories });
+    throw err;
+  }
 },

Also applies to: 136-148, 176-181, 195-209

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core-web/src/stores/agentMemoryStore.ts` around lines 117 - 122, The mutation
actions (addMemory, editMemory, removeMemory, addKnowledge, verifyKnowledge,
removeKnowledge) currently call their respective API helpers (storeAgentMemory,
updateAgentMemory, deleteAgentMemory, storeAgentKnowledge, verifyAgentKnowledge,
deleteAgentKnowledge) without try/catch or rollback; wrap each API call in a
try/catch, perform the optimistic state update only after successful API
response or revert state on error (e.g., restore previous memories/knowledge
array or trigger a fresh fetch), log the error via the same logger used
elsewhere, and either re-throw or return a standardized error so callers can
handle it—apply this pattern in the functions addMemory, editMemory,
removeMemory, addKnowledge, verifyKnowledge, and removeKnowledge.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@core-api/api/routers/agent_memory.py`:
- Line 17: The import access_memory is unused in the agent memory router; remove
access_memory from the import list in the agent_memory module (or alternatively
implement and register an endpoint that calls access_memory such as a GET/POST
handler) so there are no dead imports; update the import statement that
currently lists access_memory and run linters/tests to confirm the unused-import
warning is resolved.

In `@core-api/api/services/agents/memory.py`:
- Around line 175-201: The access_memory function is imported in agent_memory.py
but never used; add a simple POST endpoint to call it: create a route POST
/memories/{memory_id}/access in the agent_memory.py router that extracts
memory_id from the path and the user's JWT from the request/auth context, calls
access_memory(memory_id, user_jwt), returns the updated memory object (or
appropriate 404/500 on error), and ensures proper auth/permission checks mirror
other agents endpoints; alternatively, if you prefer integrating into search
flow, call access_memory(memory_id, user_jwt) for each returned memory in
search_memories before returning results—update imports accordingly and handle
errors gracefully.
- Around line 316-324: In verify_knowledge, the update is assigning the literal
string "now()" to verified_at so the DB will store that string; change the
update to set verified_at to a real Python datetime (e.g.,
datetime.datetime.utcnow() or timezone-aware now) before calling
supabase.table("agent_knowledge_base").update(...). Use the existing variables
verified_by and knowledge_id and pass the datetime object in the update payload
for the "verified_at" key so the Supabase client stores a proper timestamp
rather than the string "now()".
- Around line 189-197: The update is passing the literal string "now()" so
last_accessed_at will store that text; change the update to set last_accessed_at
to a Python datetime (e.g., utcnow() or timezone-aware datetime) converted to an
ISO/UTC string or a Python datetime object acceptable by Supabase/Postgres,
e.g., import datetime and use datetime.datetime.utcnow().isoformat() (or
timezone-aware equivalent) in the dictionary passed to
supabase.table("agent_memories").update(...) so last_accessed_at receives an
actual timestamp rather than the string "now()".

In `@core-api/supabase/migrations/20260409000003_agent_memory.sql`:
- Around line 54-56: The functions search_agent_memories and
search_knowledge_base are defined with SECURITY DEFINER and the migration grants
ALL to anon, which allows unauthenticated RPCs to bypass RLS; remove the GRANT
ALL to anon for these functions and either (a) change the functions from
SECURITY DEFINER to SECURITY INVOKER or (b) add explicit authorization checks
inside the functions (e.g., validate current_setting('jwt.claims.workspace_id')
or session_user against the workspace/agent owner) before returning results so
unauthenticated callers cannot access other workspaces; update the SQL that
declares LANGUAGE "plpgsql" SECURITY DEFINER and the corresponding GRANT
statements for these functions accordingly.

---

Nitpick comments:
In `@core-api/api/routers/agent_memory.py`:
- Around line 208-210: The current catch-all except Exception blocks (e.g., the
one logging "Error storing memory") always return HTTP 400; change them to
classify errors: re-raise existing HTTPException unchanged, map
validation/argument errors (ValueError, TypeError) to HTTP 400 (or 422), map
not-found semantics to 404 if you have a NotFound/KeyError, and for any other
unexpected exceptions log full traceback via logger.exception(...) and raise
HTTPException(status_code=500, detail="Internal server error"). Update all
similar handlers (the shown block and the other except blocks referenced) so
client errors return 4xx and server/infrastructure failures return 5xx, and
ensure logs include traceback for diagnostics.

In `@core-api/supabase/migrations/20260409000003_agent_memory.sql`:
- Around line 120-140: Add a partial btree index to speed the
decay_agent_memories() updates by indexing agent_memories.last_accessed_at for
only non-expired, still-relevant rows; create an index named
idx_agent_memories_decay_candidates on agent_memories(last_accessed_at) with a
WHERE clause restricting to expired_at IS NULL AND relevance_score > 0.01 and
add it alongside the other agent_memories indexes so the UPDATEs in
decay_agent_memories() can use the index instead of a full table scan.
- Line 246: The IVFFlat index on "idx_agent_memories_embedding" (table
agent_memories) is suboptimal when created on empty or incrementally populated
tables; either change the index to HNSW by replacing the USING "ivfflat" clause
with USING "hnsw" for idx_agent_memories_embedding (and similarly for
idx_agent_knowledge_base_embedding on agent_knowledge_base) or add a
migration-note that documents running REINDEX/REBUILD after initial bulk load
and periodically as the dataset grows; update the migration SQL or accompanying
migration README to reflect the chosen approach so similarity searches are
accurate post-population.

In `@core-web/src/stores/agentMemoryStore.ts`:
- Around line 117-122: The mutation actions (addMemory, editMemory,
removeMemory, addKnowledge, verifyKnowledge, removeKnowledge) currently call
their respective API helpers (storeAgentMemory, updateAgentMemory,
deleteAgentMemory, storeAgentKnowledge, verifyAgentKnowledge,
deleteAgentKnowledge) without try/catch or rollback; wrap each API call in a
try/catch, perform the optimistic state update only after successful API
response or revert state on error (e.g., restore previous memories/knowledge
array or trigger a fresh fetch), log the error via the same logger used
elsewhere, and either re-throw or return a standardized error so callers can
handle it—apply this pattern in the functions addMemory, editMemory,
removeMemory, addKnowledge, verifyKnowledge, and removeKnowledge.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fc21ae3f-1ac3-4941-bdff-4b19832a0950

📥 Commits

Reviewing files that changed from the base of the PR and between 8459aed and 76f99d8.

📒 Files selected for processing (6)
  • core-api/api/routers/agent_memory.py
  • core-api/api/services/agents/memory.py
  • core-api/index.py
  • core-api/supabase/migrations/20260409000003_agent_memory.sql
  • core-web/src/api/client.ts
  • core-web/src/stores/agentMemoryStore.ts

Comment thread core-api/api/routers/agent_memory.py
Comment thread core-api/api/services/agents/memory.py
Comment thread core-api/api/services/agents/memory.py
Comment thread core-api/api/services/agents/memory.py
Comment thread core-api/supabase/migrations/20260409000003_agent_memory.sql
- Fix now() string bug: use datetime.now(timezone.utc).isoformat()
- Remove anon grants from SECURITY DEFINER search functions
- Add access_memory endpoint (POST /memories/{id}/access)
- Switch ivfflat to hnsw indexes for empty-table compatibility
- Add decay_candidates partial index for cron performance
- Improve error classification: ValueError→400, Exception→500
- Add try/catch + rollback to frontend store mutations
- Remove unused imports (ruff clean)
@sonarqubecloud

Copy link
Copy Markdown

@joshuajerin

Copy link
Copy Markdown
Contributor Author

@hackertron since yall are going the agentic route, thought ill push something that u can use in that system

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.

1 participant