Skip to content

feat: implement Mem0 memory backend adapter#345

Merged
Aureliolo merged 17 commits intomainfrom
feat/mem0-adapter
Mar 13, 2026
Merged

feat: implement Mem0 memory backend adapter#345
Aureliolo merged 17 commits intomainfrom
feat/mem0-adapter

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Summary

  • Implements the MemoryBackend, MemoryCapabilities, and SharedKnowledgeStore protocols via Mem0MemoryBackend adapter
  • Adds Mem0Config and Mem0EmbedderConfig Pydantic models with build_config_from_company_config() factory
  • Implements bidirectional mapping between Mem0 raw dicts and MemoryEntry domain models (mappers.py)
  • Adds create_memory_backend() factory function for config-driven backend instantiation
  • Shared knowledge store with publisher ownership verification (publish/search_shared/retract)
  • Full async wrapping of sync Mem0 SDK via asyncio.to_thread()
  • Double-checked locking for connect/disconnect lifecycle
  • Type-safe client access via _require_connected() returning Mem0Client Protocol
  • Post-filter pipeline for category, date range, and tag filtering
  • Observability events for all memory operations
  • PurePosixPath for Docker-targeted path construction (cross-platform safe)

Test plan

  • 7453 tests passing, 94.74% coverage
  • Unit tests for adapter CRUD operations (test_adapter_crud.py — 696 lines)
  • Unit tests for shared knowledge store (test_adapter_shared.py — 450 lines)
  • Unit tests for adapter lifecycle and capabilities (test_adapter.py — 347 lines)
  • Unit tests for mappers (test_mappers.py — 665 lines)
  • Unit tests for config (test_config.py — 230 lines)
  • Unit tests for factory (test_factory.py — updated)
  • All edge cases: orphan rejection, namespace guards, ownership verification, error wrapping
  • mypy strict mode passes
  • ruff lint + format clean

Review coverage

Pre-reviewed through 9 rounds of automated review (8 specialized agents per round). 106 files changed, 11,261 insertions.

Closes #206

Add concrete MemoryBackend implementation using Mem0 (embedded Qdrant +
SQLite) as the storage layer, unblocking all downstream memory features.

- Mem0MemoryBackend implements MemoryBackend, MemoryCapabilities, and
  SharedKnowledgeStore protocols with asyncio.to_thread for all sync
  Mem0 calls
- Mapping layer (mappers.py) for bidirectional domain model <-> Mem0
  dict conversion with _synthorg_ metadata prefix
- Mem0BackendConfig + config builder deriving from CompanyMemoryConfig
- Factory wired up with deferred import (no longer raises
  MemoryConfigError for mem0 backend)
- Shared knowledge via reserved __synthorg_shared__ namespace with
  publisher ownership tracking
- 95 unit tests (adapter, mappers, config) + 6 integration tests
  (retrieval pipeline, shared knowledge flow)

Closes #206
Pre-reviewed by 9 agents, 33 findings addressed:
- Remove vendor-specific defaults from Mem0EmbedderConfig (now required)
- Fix metadata dict mutation in publish() (use spread instead)
- Add path traversal validation on Mem0BackendConfig.data_dir
- Extract _validate_add_result helper for store/publish result validation
- Add explicit ImportError handling in connect()
- Make health_check() probe backend with lightweight get_all call
- Add defensive category parsing in _extract_category (handle invalid enums)
- Add missing publisher check in retract() (not a shared memory entry)
- Replace C-style loop in search_shared with generator expression
- Use meaningful variable names (raw_entries/filtered vs triple result)
- Change logger.exception to logger.warning for self-raised errors
- Add structured error/error_type kwargs to all re-raise logs
- Add MemoryConnectionError to Raises docstrings for shared methods
- Update factory to require embedder config (no vendor defaults)
- Remove dead store_request_to_mem0_args function and its tests
- Add tests: path traversal, missing id, empty content, malformed datetime,
  invalid category, no-publisher retract, delete-after-get failure,
  protocol conformance, health_check probe failure
…iewers

- Add MemoryError/RecursionError guards before all except Exception blocks
- Capture exceptions in re-raise blocks for structured logging
- Move helper functions (validate_add_result, extract_category, extract_publisher)
  from adapter.py to mappers.py to keep adapter under 800-line limit
- Add type/tag/confidence validation in mappers (items 9, 11, 23)
- Add logging before all raise statements (items 7, 20, 21)
- Fix health_check exception log level from debug to warning
- Add search_shared query context to error logs
- Strengthen factory.py type annotation (embedder: Mem0EmbedderConfig | None)
- Parametrize config traversal tests, add ImportError/MemoryError/publish tests
- Update CLAUDE.md, README, roadmap, and design spec for Mem0 adapter status
- Fix dependency review CI: add LicenseRef-scancode-protobuf, ZPL-2.1
  to license allow-list and allow-dependencies-licenses for packages
  with null SPDX metadata (mem0ai, numpy, qdrant-client, posthog)
- Fix validate_add_result blank-ID gap: check for None and whitespace
  IDs, not just missing key (Greptile finding)
- Fix factory.py wrong event constant: use MEMORY_BACKEND_CONFIG_INVALID
  instead of MEMORY_BACKEND_UNKNOWN for embedder config errors (Greptile)
- Fix retract() bare except: capture as exc and log error detail
- Document count() limitation: capped at max_memories_per_agent
- Add 37 new tests: validate_add_result (blank/None/whitespace/numeric
  ID, non-list results), extract_category, extract_publisher, MemoryError
  re-raise for all operations, blank-ID through store/retrieve, shared
  namespace fallback, count empty results, retract delete failure
…ig, and tests

- mappers.py: add str() conversion before NotBlankStr for tags, clamp
  confidence to [0.0, 1.0], log missing/non-dict metadata and unexpected
  tag types, guard blank publisher strings, document None relevance
  score behavior in apply_post_filters, clean up historical comment
- config.py: add structured logging to _reject_traversal validator,
  validate unsupported storage overrides in build_config_from_company_config
- factory.py: wrap ValueError from config construction as MemoryConfigError
- pyproject.toml: move mem0ai to optional-dependencies, add TC to test
  per-file-ignores
- __init__.py: guard Mem0 imports with contextlib.suppress(ImportError)
- adapter.py: log during disconnect reset failure instead of bare pass
- dependency-review.yml: version-pin allowed PURLs
- docs: add embedder config to memory.md YAML example, update roadmap
  Current Status to mention Mem0 adapter
- tests: split test_adapter.py (1118 lines) into conftest.py +
  test_adapter.py + test_adapter_crud.py + test_adapter_shared.py;
  add protocol isinstance checks, connect MemoryError/RecursionError
  propagation, agent_id validation, ownership mismatch, and shared
  namespace guard tests
- Clean up 78 now-unused noqa: TC* directives across test files
mem0ai was moved to optional-dependencies — CI needs --extra mem0
in the uv sync command to install it for tests.
mem0ai is the only memory backend — no reason to make it optional.
Reverts the optional-dependencies split and CI extra flag.
…d Gemini

- CRITICAL: remove Memory.reset() from disconnect() — it wiped all data
- MAJOR: wrap Mem0MemoryBackend init errors in factory as MemoryConfigError
- MEDIUM: coerce string scores in normalize_relevance_score
- MEDIUM: validate dict structure in validate_add_result
- MEDIUM: sanitize source metadata via _coerce_source helper
- MEDIUM: update CLAUDE.md — mem0ai is a required dependency, not optional
- MEDIUM: extract _coerce_confidence, _coerce_source, _normalize_tags helpers
- MINOR: coerce non-string values in extract_publisher
- MINOR: add user_id param to mem0_get_result fixture
- MINOR: document adapter.py 800-line exemption
- Tests: add coverage for string scores, non-dict results, source
  sanitization, publisher coercion, disconnect-no-reset
- Remove unused noqa A004 directive (ruff auto-fix)
- Fix import sorting in adapter.py (ruff auto-fix)
- Add connect() idempotency test (verifies no-op when already connected)
- Add _validate_agent_id error_cls tests for read ops (retrieve, get, count)
- Add expires_at filtering tests in apply_post_filters
- Add config validation tests using model_construct to bypass Pydantic
- Fix factory init test patch target to match local import
…and factory

- Add Mem0Client protocol (TYPE_CHECKING) for structural typing documentation
- Add asyncio.Lock + double-check locking to prevent concurrent connect()
- Expand docstrings: adapter, config, design spec protocol snippets
- Replace inline generator in search_shared with explicit loop + publisher fallback logging
- Narrow factory exception catch to (ValueError, ValidationError)
- Add YAML enum value annotations in design spec
- Update CLAUDE.md logging event domains
- Remove unused event constants (MEMORY_BACKEND_NOT_IMPLEMENTED, MEMORY_CAPABILITY_UNSUPPORTED)
- Rename _PUBLISHER_KEY → PUBLISHER_KEY (public constant)
- Add tests: RecursionError propagation, _validate_mem0_result, _coerce_confidence,
  _normalize_tags, count truncation warning, category post-filter, publisher fallback
…ig, factory, and tests

- Remove @runtime_checkable from TYPE_CHECKING-only Mem0Client protocol
- Add _connect_lock to disconnect() to prevent race with connect()
- Fix MEMORY_ENTRY_DELETE_FAILED event on non-failure path (unverifiable owner)
- Add shared namespace verification in retract() (defense-in-depth)
- Add _validate_agent_id() call in retract()
- Add math.isfinite() guards in normalize_relevance_score() and _coerce_confidence()
- Prefer updated_at over now() as created_at fallback in mem0_result_to_entry()
- Reject qdrant-external in build_config_from_company_config() (not supported)
- Extract _create_mem0_backend() helper from create_memory_backend()
- Fix MemoryQuery class docstring: "after" → "at or after" for since field
- Use explicit builtins.MemoryError in all test assertions
…mes, pathlib

- get(): return None for memories with no user_id (unverifiable ownership)
- delete(): raise MemoryStoreError for orphan memories instead of allowing
- search_shared(): reject exclude_agent matching reserved shared namespace
- config: replace vendor-specific docstring examples with generic identifiers
- config: use PurePosixPath for Docker-targeted path construction
- factory: catch ValidationError alongside ValueError in config build
- mappers: improved created_at fallback cascade (updated_at → expires_at → now)
- tests: add orphan rejection tests (get/delete), namespace guard test
- tests: freeze clock in expiry test, parameterize validate_add_result tests
Pre-reviewed by 8 agents, 11 findings addressed:
- _require_connected() now returns Mem0Client for type-safe call sites
- Replaced truthiness checks with explicit `is not None` in post-filters
- Replaced dynamic log_fn dispatch with explicit branches in mappers
- Added DEBUG logging for dropped tags in _normalize_tags
- Extracted _resolve_publisher helper, replaced intermediate list with generator
- Added logging to search_shared namespace guard
- Removed dead owner-is-not-None conditions in delete()
- Widened factory catch from (ValueError, ValidationError) to Exception
- Added tests: orphan rejection, shared namespace guards, fallback dates
Copilot AI review requested due to automatic review settings March 13, 2026 10:22
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 13, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

OpenSSF Scorecard

Scorecard details
PackageVersionScoreDetails
pip/backoff 2.2.1 🟢 3.4
Details
CheckScoreReason
Code-Review⚠️ 2Found 7/24 approved changesets -- score normalized to 2
Maintained⚠️ 0project is archived
Packaging⚠️ -1packaging workflow not detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST🟢 7SAST tool detected but not run on all commits
pip/greenlet 3.3.2 UnknownUnknown
pip/grpcio 1.78.0 UnknownUnknown
pip/h2 4.3.0 UnknownUnknown
pip/hpack 4.1.0 UnknownUnknown
pip/hyperframe 6.1.0 UnknownUnknown
pip/mem0ai 1.0.5 UnknownUnknown
pip/numpy 2.4.3 UnknownUnknown
pip/portalocker 3.2.0 UnknownUnknown
pip/posthog 7.9.12 UnknownUnknown
pip/protobuf 5.29.6 UnknownUnknown
pip/pytz 2026.1.post1 UnknownUnknown
pip/qdrant-client 1.17.0 UnknownUnknown
pip/sqlalchemy 2.0.48 UnknownUnknown

Scanned Files

  • uv.lock

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 13, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4c6073fe-43f3-491a-8a46-7e710482204e

📥 Commits

Reviewing files that changed from the base of the PR and between 155d263 and 1c20792.

📒 Files selected for processing (3)
  • src/ai_company/memory/backends/mem0/adapter.py
  • src/ai_company/memory/backends/mem0/mappers.py
  • tests/unit/memory/backends/mem0/test_adapter_shared.py

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Mem0 memory backend added (embedder-backed initialization, CRUD, shared-knowledge flows, and public backend exports).
  • Documentation

    • Memory docs and roadmap updated with Mem0 adapter and embedder configuration guidance; factory API docs reflect embedder parameter.
  • Bug Fixes

    • Clarified timestamp semantics for memory queries.
  • Tests

    • Extensive unit and integration tests for Mem0 backend, mappers, config, shared flows, and factory.
  • Chores

    • Cleaned up test import formatting and updated memory observability event constants.
  • Dependencies

    • Added mem0 memory-backend dependency.

Walkthrough

Adds a complete Mem0 memory backend: adapter, config, mappers, shared helpers, factory dispatch, docs/packaging updates, package exports, observability events, and extensive unit/integration tests; plus dependency-review and test import cleanup changes.

Changes

Cohort / File(s) Summary
Mem0 Backend Core
src/ai_company/memory/backends/mem0/adapter.py, src/ai_company/memory/backends/mem0/config.py, src/ai_company/memory/backends/mem0/mappers.py, src/ai_company/memory/backends/mem0/shared.py
New Mem0MemoryBackend implementation, Mem0BackendConfig & Mem0EmbedderConfig, stateless mappers, shared-store helpers; lifecycle, CRUD, shared flows, validation, error mapping, and observability instrumentation.
Factory & Public Exports
src/ai_company/memory/factory.py, src/ai_company/memory/__init__.py, src/ai_company/memory/backends/__init__.py, src/ai_company/memory/backends/mem0/__init__.py
create_memory_backend signature now accepts an embedder kwarg and dispatches to Mem0; added internal _create_mem0_backend; re-exports Mem0 types at package level; new memory observability events.
Docs, Packaging & CI
docs/design/memory.md, docs/roadmap/index.md, README.md, CLAUDE.md, .github/workflows/dependency-review.yml, pyproject.toml
Docs updated for pluggable Mem0 backend and factory embedder arg; added mem0ai dependency and tooling overrides; expanded dependency-review allowlist and explicit allow-dependencies-licenses entries.
Observability Events
src/ai_company/observability/events/memory.py
Removed/added memory event constants (removed MEMORY_BACKEND_NOT_IMPLEMENTED and MEMORY_CAPABILITY_UNSUPPORTED; added MEMORY_BACKEND_CONFIG_INVALID, MEMORY_BACKEND_AGENT_ID_REJECTED, MEMORY_BACKEND_SYSTEM_ERROR).
Tests — Mem0 Unit & Integration
tests/unit/memory/backends/mem0/*, tests/integration/memory/test_mem0_backend.py, tests/unit/memory/*
New extensive unit and integration tests for adapter, CRUD, shared flows, mappers, config, factory behavior; tests assert new exports/events and exercise error paths with mocked Mem0 client.
Test Import Cleanup
tests/unit/**, tests/integration/** (many files)
Removed inline noqa comments (# noqa: TC001/TC002/TC003) across many test files; stylistic only.
Misc docs/text & small changes
src/ai_company/memory/models.py, tests/unit/observability/test_events.py
Minor wording tweak in MemoryQuery.since and updated test parameterization to reflect changed event constants.

Sequence Diagram(s)

sequenceDiagram
    participant Factory as Memory Factory
    participant Config as Config Builder
    participant Adapter as Mem0MemoryBackend
    participant Mem0 as Mem0 Memory Client
    participant Mappers as Domain Mappers

    rect rgba(100, 150, 200, 0.5)
    note over Factory,Mem0: Backend Initialization
    Factory->>Config: build_config_from_company_config(config, embedder)
    Config->>Config: validate embedder & vector_store
    Config-->>Factory: Mem0BackendConfig
    Factory->>Adapter: __init__(config)
    Adapter-->>Factory: Mem0MemoryBackend instance
    end

    rect rgba(200, 150, 100, 0.5)
    note over Adapter,Mappers: Store Operation
    Adapter->>Adapter: connect() via asyncio.to_thread
    Adapter->>Mem0: Memory.from_config() / add(...)
    Mem0-->>Adapter: add result {id,...}
    Adapter->>Mappers: build_mem0_metadata(request)
    Mappers-->>Adapter: metadata dict
    Adapter->>Mappers: validate_add_result(result)
    Mappers-->>Adapter: memory_id
    end

    rect rgba(150, 200, 100, 0.5)
    note over Adapter,Mappers: Retrieve Operation
    Adapter->>Mem0: search(...) or get_all(...)
    Mem0-->>Adapter: list of raw results
    Adapter->>Mappers: mem0_result_to_entry() / parse timestamps / normalize score
    Mappers-->>Adapter: MemoryEntry...
    Adapter->>Mappers: apply_post_filters(entries, query)
    Mappers-->>Adapter: filtered entries
    Adapter-->>Factory: tuple[MemoryEntry, ...]
    end

    rect rgba(200, 100, 150, 0.5)
    note over Adapter,Mem0: Shared Knowledge Store
    Adapter->>Mem0: add(user_id="_shared", metadata={_synthorg_publisher: agent_id})
    Mem0-->>Adapter: memory_id
    Adapter->>Mem0: search(user_id="_shared")
    Mem0-->>Adapter: shared memories
    Adapter->>Mappers: extract_publisher() per entry
    Mappers-->>Adapter: agent_id
    Adapter->>Adapter: filter by exclude_agent if provided
    Adapter-->>Factory: shared entries
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • #206: feat: implement concrete memory backend adapter — This PR implements a concrete Mem0 MemoryBackend, its config/mappers/factory wiring, and tests, directly addressing the issue’s scope.

Possibly related PRs

  • Aureliolo/synthorg#345 — Appears to add the same Mem0 backend implementation, modules, tests, and packaging changes; likely the same work or closely related.
  • Aureliolo/synthorg#308 — Related documentation changes affecting the memory design pages and references to the new Mem0 backend.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.64% 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
Title check ✅ Passed The title 'feat: implement Mem0 memory backend adapter' clearly and specifically describes the main change—implementing a Mem0-based memory backend that fulfills the protocol requirements.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, covering implementation details, test coverage, and design decisions aligned with the PR objectives.
Linked Issues check ✅ Passed The PR fully implements the requirements from issue #206: provides a concrete MemoryBackend adapter, ensures protocol conformance, integrates with factory/config, includes integration tests, and supports Python 3.14+.
Out of Scope Changes check ✅ Passed All changes are in-scope: Mem0 backend implementation, configuration, mappers, factory updates, documentation, tests, and cleanup of linting comments across test files are all aligned with issue #206 objectives.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/mem0-adapter
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/mem0-adapter
📝 Coding Plan
  • Generate coding plan for human review comments

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

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 13, 2026

Codecov Report

❌ Patch coverage is 96.10619% with 22 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.90%. Comparing base (2f10d49) to head (1c20792).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/ai_company/memory/backends/mem0/adapter.py 95.19% 8 Missing and 2 partials ⚠️
src/ai_company/memory/backends/mem0/config.py 90.69% 3 Missing and 1 partial ⚠️
src/ai_company/memory/backends/mem0/shared.py 93.84% 3 Missing and 1 partial ⚠️
src/ai_company/memory/factory.py 88.23% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #345      +/-   ##
==========================================
+ Coverage   93.82%   93.90%   +0.07%     
==========================================
  Files         441      447       +6     
  Lines       20243    20803     +560     
  Branches     1950     2010      +60     
==========================================
+ Hits        18993    19535     +542     
- Misses        966      981      +15     
- Partials      284      287       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 13, 2026

Greptile Summary

This PR implements the Mem0 memory backend adapter, satisfying the MemoryBackend, MemoryCapabilities, and SharedKnowledgeStore protocols. The implementation is well-structured: the adapter, shared-knowledge logic, mappers, and config are cleanly separated into focused modules. Async wrapping via asyncio.to_thread, double-checked locking, and the _require_connected() type-narrowing pattern are all correct. Observability is thorough — every operation emits structured events using the appropriate constants.

Key changes:

  • Mem0MemoryBackend adapter with full CRUD + shared-knowledge methods, lifecycle management, and capabilities introspection
  • Mem0BackendConfig / Mem0EmbedderConfig Pydantic models with path-traversal guards (_reject_traversal) and Docker-targeted POSIX path construction
  • Bidirectional mapper functions in mappers.py covering datetime parsing, confidence clamping, tag normalisation, and post-filter pipeline
  • build_config_from_company_config() factory and create_memory_backend() dispatcher
  • New memory event constants in observability/events/memory.py

One logic bug was found in apply_post_filters: the if query.categories truthiness check silently skips category filtering when query.categories is an empty frozenset(), returning all entries instead of none. The pattern used by query.since/query.until (is not None) should be applied here instead.

Confidence Score: 4/5

  • This PR is safe to merge after addressing the category filter logic bug in apply_post_filters.
  • The implementation is architecturally sound with correct async patterns, proper ownership guards, and thorough observability. One logic bug was found: if query.categories falsely skips the category filter for frozenset(), which is a one-line fix. All previously flagged issues from earlier review rounds appear to have been resolved in the code as submitted.
  • src/ai_company/memory/backends/mem0/mappers.py — the apply_post_filters category check at line 449

Important Files Changed

Filename Overview
src/ai_company/memory/backends/mem0/adapter.py Core Mem0 adapter implementing MemoryBackend, MemoryCapabilities, and SharedKnowledgeStore. Double-checked locking, asyncio.to_thread wrapping, and _require_connected type-narrowing are all correct. Minor: MEMORY_ENTRY_DELETED used for both "deleted" and "not found" paths (cosmetic).
src/ai_company/memory/backends/mem0/mappers.py Bidirectional Mem0↔domain mappers; all event constants use the correct symbols now. Contains a logic bug in apply_post_filters: if query.categories is falsy for frozenset(), causing the category filter to be silently skipped when an empty set is passed.
src/ai_company/memory/backends/mem0/shared.py SharedKnowledgeStore operations; ownership checks, event constants, and error propagation are correct. The exclude_agent post-filter under-delivery behaviour is documented as a known limitation.
src/ai_company/memory/backends/mem0/config.py Pydantic config models with path traversal and Windows-path rejection. PurePosixPath + PureWindowsPath combined check is thorough. build_config_from_company_config correctly isolates per-company data via data_dir (different paths → separate embedded Qdrant instances).
src/ai_company/memory/factory.py Clean factory with proper embedder validation, error wrapping, and observability. Type-check guard for the TYPE_CHECKING-only Mem0EmbedderConfig annotation is handled correctly.
src/ai_company/memory/models.py Frozen Pydantic domain models. Timestamp invariants, tag deduplication, and time-range validation are all correctly implemented.
src/ai_company/observability/events/memory.py New memory event constants follow the memory.. naming convention consistently. All constants used across adapter, mappers, shared, and factory are present.

Sequence Diagram

sequenceDiagram
    participant Caller
    participant Mem0MemoryBackend
    participant shared.py
    participant mappers.py
    participant Mem0SDK

    Caller->>Mem0MemoryBackend: connect()
    Mem0MemoryBackend->>Mem0SDK: asyncio.to_thread(Memory.from_config)
    Mem0SDK-->>Mem0MemoryBackend: client
    Mem0MemoryBackend-->>Caller: connected

    Caller->>Mem0MemoryBackend: store(agent_id, request)
    Mem0MemoryBackend->>mappers.py: build_mem0_metadata(request)
    mappers.py-->>Mem0MemoryBackend: metadata dict
    Mem0MemoryBackend->>Mem0SDK: asyncio.to_thread(client.add)
    Mem0SDK-->>Mem0MemoryBackend: raw result
    Mem0MemoryBackend->>mappers.py: validate_add_result(result)
    mappers.py-->>Mem0MemoryBackend: memory_id
    Mem0MemoryBackend-->>Caller: memory_id

    Caller->>Mem0MemoryBackend: retrieve(agent_id, query)
    Mem0MemoryBackend->>Mem0SDK: asyncio.to_thread(client.search / get_all)
    Mem0SDK-->>Mem0MemoryBackend: raw results
    Mem0MemoryBackend->>mappers.py: validate_mem0_result + mem0_result_to_entry (×N)
    Mem0MemoryBackend->>mappers.py: apply_post_filters(entries, query)
    mappers.py-->>Mem0MemoryBackend: filtered entries
    Mem0MemoryBackend-->>Caller: tuple[MemoryEntry]

    Caller->>Mem0MemoryBackend: publish(agent_id, request)
    Mem0MemoryBackend->>shared.py: publish_shared(client, agent_id, request)
    shared.py->>Mem0SDK: asyncio.to_thread(client.add, user_id=SHARED_NAMESPACE)
    Mem0SDK-->>shared.py: raw result
    shared.py-->>Mem0MemoryBackend: memory_id
    Mem0MemoryBackend-->>Caller: memory_id

    Caller->>Mem0MemoryBackend: retract(agent_id, memory_id)
    Mem0MemoryBackend->>shared.py: retract_shared(client, agent_id, memory_id)
    shared.py->>Mem0SDK: asyncio.to_thread(client.get, memory_id)
    Mem0SDK-->>shared.py: raw entry
    shared.py->>shared.py: _check_retract_ownership(raw, agent_id, memory_id)
    shared.py->>Mem0SDK: asyncio.to_thread(client.delete, memory_id)
    shared.py-->>Mem0MemoryBackend: True
    Mem0MemoryBackend-->>Caller: True
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/ai_company/memory/backends/mem0/mappers.py
Line: 449

Comment:
**Falsy frozenset bypasses category filter entirely**

`if query.categories` evaluates to `False` for an empty `frozenset()`, which means a caller who explicitly passes `categories=frozenset()` (intending to match no categories) will instead receive **all** entries unfiltered — the opposite of the expected behavior. The equivalent guard for `query.since`/`query.until` correctly uses `is not None` checks; this filter should follow the same pattern.

```suggestion
        if query.categories is not None and entry.category not in query.categories:
```

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: 1c20792

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements a concrete MemoryBackend for the memory subsystem by introducing a Mem0-based adapter, associated configuration models/builders, mapping utilities, and a factory integration so the backend can be instantiated from CompanyMemoryConfig (with an embedder config provided programmatically).

Changes:

  • Add Mem0 backend implementation (Mem0MemoryBackend) with shared knowledge operations and async wrapping of the Mem0 SDK.
  • Add Mem0-specific configuration (Mem0BackendConfig, Mem0EmbedderConfig) plus config-dict builder and factory wiring (create_memory_backend(..., embedder=...)).
  • Add Mem0 <-> domain model mappers and extensive unit/integration tests; update docs, dependencies, and observability events accordingly.

Reviewed changes

Copilot reviewed 81 out of 84 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
uv.lock Locks new transitive dependencies required by mem0ai (and its stack).
pyproject.toml Adds pinned mem0ai==1.0.5, adjusts ruff ignores, and mypy override for mem0.*.
src/ai_company/memory/factory.py Implements backend dispatch and Mem0 backend construction with config validation/logging.
src/ai_company/memory/backends/mem0/adapter.py New Mem0 adapter implementing backend CRUD + shared knowledge operations with async wrapping and observability.
src/ai_company/memory/backends/mem0/config.py New Pydantic config models and builders for Mem0 embedded Qdrant + SQLite history.
src/ai_company/memory/backends/mem0/mappers.py New mapping/validation utilities and post-filter pipeline for Mem0 results.
src/ai_company/memory/backends/mem0/init.py Exposes Mem0 backend/config public API for imports.
src/ai_company/memory/backends/init.py Adds concrete backend package exports.
src/ai_company/memory/init.py Re-exports Mem0 backend/config for ai_company.memory consumers.
src/ai_company/observability/events/memory.py Updates memory event constants to reflect new backend lifecycle/config errors.
src/ai_company/memory/models.py Clarifies since semantics (inclusive) in MemoryQuery docs/field description.
tests/unit/memory/test_init.py Ensures new Mem0 exports are importable from ai_company.memory.
tests/unit/memory/test_factory.py Updates factory tests for Mem0 creation, embedder requirements, and error wrapping.
tests/unit/memory/backends/mem0/conftest.py Adds shared fixtures for Mem0 backend tests.
tests/unit/memory/backends/mem0/test_mappers.py Adds comprehensive mapper and post-filter unit tests.
tests/unit/memory/backends/mem0/test_config.py Adds Mem0 config model/builder unit tests.
tests/unit/memory/backends/mem0/test_adapter.py Adds adapter lifecycle/capabilities/protocol/guard unit tests.
tests/unit/memory/backends/mem0/test_adapter_crud.py Adds adapter CRUD/count unit tests with error-path coverage.
tests/unit/memory/backends/mem0/test_adapter_shared.py Adds shared knowledge publish/search/retract unit tests.
tests/integration/memory/test_mem0_backend.py Adds retrieval-pipeline integration tests using the adapter with a mocked client.
tests/unit/observability/test_events.py Updates expected event constants list to match new memory events.
docs/design/memory.md Updates design spec to reflect Mem0 adapter now implemented + factory signature requiring embedder.
docs/roadmap/index.md Updates roadmap to remove “Mem0 adapter” as remaining work.
README.md Updates project status to indicate Mem0 backend adapter is implemented.
CLAUDE.md Updates architecture/docs to reflect memory/backends/mem0 implementation and dependency note.
.github/workflows/dependency-review.yml Adjusts dependency review allowlists for new packages and missing SPDX metadata.
tests/unit/tools/sandbox/test_protocol.py Removes type-checking import suppression comments (TC rules).
tests/unit/tools/sandbox/conftest.py Removes type-checking import suppression comments (TC rules).
tests/unit/tools/git/test_git_sandbox_integration.py Removes type-checking import suppression comments (TC rules).
tests/unit/tools/git/conftest.py Removes type-checking import suppression comments (TC rules).
tests/unit/providers/test_protocol.py Removes type-checking import suppression comments (TC rules).
tests/unit/providers/conftest.py Removes type-checking import suppression comments (TC rules).
tests/unit/hr/test_registry.py Removes type-checking import suppression comments (TC rules).
tests/unit/hr/test_onboarding_service.py Removes type-checking import suppression comments (TC rules).
tests/unit/hr/test_offboarding_service.py Removes type-checking import suppression comments (TC rules).
tests/unit/hr/test_hiring_service.py Removes type-checking import suppression comments (TC rules).
tests/unit/hr/test_full_snapshot_strategy.py Removes type-checking import suppression comments (TC rules).
tests/unit/engine/test_task_engine_mutations.py Removes type-checking import suppression comments (TC rules).
tests/unit/engine/test_routing_models.py Removes type-checking import suppression comments (TC rules).
tests/unit/engine/test_react_loop.py Removes type-checking import suppression comments (TC rules).
tests/unit/engine/test_plan_execute_loop.py Removes type-checking import suppression comments (TC rules).
tests/unit/engine/test_metrics.py Removes type-checking import suppression comments (TC rules).
tests/unit/engine/test_loop_protocol.py Removes type-checking import suppression comments (TC rules).
tests/unit/engine/test_context.py Removes type-checking import suppression comments (TC rules).
tests/unit/engine/test_agent_engine_lifecycle.py Removes type-checking import suppression comments (TC rules).
tests/unit/engine/test_agent_engine_errors.py Removes type-checking import suppression comments (TC rules).
tests/unit/engine/test_agent_engine.py Removes type-checking import suppression comments (TC rules).
tests/unit/engine/task_engine_helpers.py Removes type-checking import suppression comments (TC rules).
tests/unit/communication/meeting/test_structured_phases.py Removes type-checking import suppression comments (TC rules).
tests/unit/communication/meeting/test_round_robin.py Removes type-checking import suppression comments (TC rules).
tests/unit/communication/meeting/test_protocol.py Removes type-checking import suppression comments (TC rules).
tests/unit/communication/meeting/test_position_papers.py Removes type-checking import suppression comments (TC rules).
tests/unit/communication/meeting/test_orchestrator.py Removes type-checking import suppression comments (TC rules).
tests/unit/communication/meeting/conftest.py Removes type-checking import suppression comments (TC rules).
tests/unit/communication/conflict_resolution/test_service.py Removes type-checking import suppression comments (TC rules).
tests/unit/communication/conflict_resolution/test_hybrid_strategy.py Removes type-checking import suppression comments (TC rules).
tests/unit/communication/conflict_resolution/test_helpers.py Removes type-checking import suppression comments (TC rules).
tests/unit/communication/conflict_resolution/test_debate_strategy.py Removes type-checking import suppression comments (TC rules).
tests/unit/communication/conflict_resolution/test_authority_strategy.py Removes type-checking import suppression comments (TC rules).
tests/unit/budget/test_category_analytics.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/test_middleware.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/test_health.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/test_guards.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/test_app.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/controllers/test_tasks.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/controllers/test_providers.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/controllers/test_projects.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/controllers/test_messages.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/controllers/test_meetings.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/controllers/test_departments.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/controllers/test_company.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/controllers/test_budget.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/controllers/test_autonomy.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/controllers/test_artifacts.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/controllers/test_approvals.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/controllers/test_analytics.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/controllers/test_agents.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/conftest.py Removes type-checking import suppression comments (TC rules).
tests/unit/api/auth/test_controller.py Removes type-checking import suppression comments (TC rules).
tests/integration/tools/test_sandbox_integration.py Removes type-checking import suppression comments (TC rules).
tests/integration/tools/conftest.py Removes type-checking import suppression comments (TC rules).
tests/integration/communication/test_meeting_integration.py Removes type-checking import suppression comments (TC rules).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +195 to +196
if t and str(t).strip():
valid.append(NotBlankStr(str(t)))
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the system's memory capabilities by integrating Mem0 as a primary pluggable memory backend. It provides a robust and configurable solution for managing agent and shared knowledge, ensuring data integrity, efficient retrieval, and comprehensive observability. The changes lay the groundwork for a more flexible and scalable memory architecture.

Highlights

  • Mem0 Memory Backend Implementation: Implemented the Mem0MemoryBackend adapter, which conforms to the MemoryBackend, MemoryCapabilities, and SharedKnowledgeStore protocols, enabling Mem0 as a pluggable memory solution.
  • Configuration Models and Factory: Introduced Mem0Config and Mem0EmbedderConfig Pydantic models, along with a create_memory_backend() factory function for configuration-driven backend instantiation.
  • Bidirectional Data Mapping: Developed mappers.py to handle bidirectional mapping between raw Mem0 data structures and the system's MemoryEntry domain models.
  • Shared Knowledge Store with Ownership Verification: Enabled shared knowledge store functionalities including publishing, searching, and retracting memories, with robust publisher ownership verification.
  • Asynchronous Operation and Concurrency Control: Ensured full asynchronous wrapping of the synchronous Mem0 SDK using asyncio.to_thread() and implemented double-checked locking for the connect/disconnect lifecycle to prevent race conditions.
  • Enhanced Observability and Filtering: Integrated observability events for all memory operations and added a post-filter pipeline for category, date range, and tag-based memory filtering.
Changelog
  • CLAUDE.md
    • Updated the description of the memory/ directory to reflect the new pluggable MemoryBackend protocol and the Mem0 adapter.
    • Expanded the list of observability event constants to include new domains like communication, company, config, and various execution stages.
    • Added mem0ai to the list of required dependencies.
  • README.md
    • Updated the project status to explicitly mention the implementation of the Mem0 backend adapter.
  • docs/design/memory.md
    • Revised the 'Storage Backend' section to indicate Mem0 as the initial and implemented solution, alongside Qdrant and SQLite for history.
    • Clarified memory.level and memory.backend options in the YAML configuration example.
    • Added Raises documentation for all MemoryBackend and SharedKnowledgeStore protocol methods.
    • Included a comment block detailing the usage of Mem0EmbedderConfig in the create_memory_backend factory.
    • Updated the create_memory_backend factory signature to include the embedder keyword argument.
  • docs/roadmap/index.md
    • Modified the 'Memory system' description to explicitly include the Mem0 adapter.
    • Removed 'Mem0 adapter' from the list of remaining tasks, indicating its completion.
  • pyproject.toml
    • Added mem0ai==1.0.5 to the project's core dependencies.
    • Included TC in ruff.lint.ignore to bypass type-checking imports in certain contexts.
    • Added a mypy.overrides entry for mem0.* to ignore missing imports.
  • src/ai_company/memory/init.py
    • Updated the module docstring to reflect the inclusion of Mem0MemoryBackend as a concrete backend.
    • Imported Mem0EmbedderConfig and Mem0MemoryBackend for direct access.
    • Added Mem0EmbedderConfig and Mem0MemoryBackend to the module's __all__ export list.
  • src/ai_company/memory/backends/init.py
    • Added a new file to define concrete memory backend implementations, specifically re-exporting Mem0MemoryBackend.
  • src/ai_company/memory/backends/mem0/init.py
    • Added a new file to export Mem0BackendConfig, Mem0EmbedderConfig, and Mem0MemoryBackend for the Mem0-backed memory module.
  • src/ai_company/memory/backends/mem0/adapter.py
    • Added a new file implementing the Mem0MemoryBackend class, which acts as an adapter for Mem0, conforming to MemoryBackend, MemoryCapabilities, and SharedKnowledgeStore protocols.
    • Implemented connection lifecycle management, health checks, and CRUD operations for individual and shared memories.
    • Incorporated publisher ownership verification for shared knowledge and a post-filter pipeline for retrieval.
    • Ensured all synchronous Mem0 SDK calls are wrapped with asyncio.to_thread() for non-blocking execution.
  • src/ai_company/memory/backends/mem0/config.py
    • Added a new file defining Mem0EmbedderConfig and Mem0BackendConfig Pydantic models for Mem0-specific settings.
    • Included build_mem0_config_dict to translate internal configuration into the format expected by the Mem0 SDK.
    • Provided build_config_from_company_config to derive Mem0 backend configuration from the top-level company memory configuration.
    • Implemented validation to reject parent-directory traversal in data_dir for security.
  • src/ai_company/memory/backends/mem0/mappers.py
    • Added a new file containing stateless mapping functions for converting between SynthOrg domain models and Mem0 raw data structures.
    • Implemented logic for building Mem0 metadata, parsing datetimes, normalizing relevance scores, and applying post-retrieval filters.
    • Defined PUBLISHER_KEY for tracking ownership in shared memories.
  • src/ai_company/memory/factory.py
    • Modified create_memory_backend to correctly instantiate Mem0MemoryBackend when mem0 is selected, requiring an embedder configuration.
    • Removed the MEMORY_BACKEND_NOT_IMPLEMENTED event and added MEMORY_BACKEND_CONFIG_INVALID and MEMORY_BACKEND_CREATED events.
  • src/ai_company/memory/models.py
    • Updated the description for MemoryQuery.since to clarify that it includes memories created 'at or after' the specified timestamp.
  • src/ai_company/observability/events/memory.py
    • Removed MEMORY_BACKEND_NOT_IMPLEMENTED and MEMORY_CAPABILITY_UNSUPPORTED event constants.
    • Added MEMORY_BACKEND_CONFIG_INVALID and MEMORY_BACKEND_AGENT_ID_REJECTED event constants for improved error reporting.
  • tests/integration/communication/test_meeting_integration.py
    • Removed unnecessary noqa: TC001 comments from imports.
  • tests/integration/memory/test_mem0_backend.py
    • Added a new file with integration tests for the Mem0 backend, covering store/retrieve operations, pipeline message preparation, shared knowledge flow, and memory counting.
  • tests/integration/tools/conftest.py
    • Removed unnecessary noqa: TC003 comment from an import.
  • tests/integration/tools/test_sandbox_integration.py
    • Removed unnecessary noqa: TC003 comment from an import.
  • tests/unit/api/auth/test_controller.py
    • Removed unnecessary noqa comments from imports.
  • tests/unit/api/conftest.py
    • Removed unnecessary noqa comments from imports.
  • tests/unit/api/controllers/test_agents.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/api/controllers/test_analytics.py
    • Removed unnecessary noqa: TC002 comment from an import.
  • tests/unit/api/controllers/test_approvals.py
    • Removed unnecessary noqa comments from imports.
  • tests/unit/api/controllers/test_artifacts.py
    • Removed unnecessary noqa: TC002 comment from an import.
  • tests/unit/api/controllers/test_autonomy.py
    • Removed unnecessary noqa: TC002 comment from an import.
  • tests/unit/api/controllers/test_budget.py
    • Removed unnecessary noqa comments from imports.
  • tests/unit/api/controllers/test_company.py
    • Removed unnecessary noqa: TC002 comment from an import.
  • tests/unit/api/controllers/test_departments.py
    • Removed unnecessary noqa: TC002 comment from an import.
  • tests/unit/api/controllers/test_meetings.py
    • Removed unnecessary noqa: TC002 comment from an import.
  • tests/unit/api/controllers/test_messages.py
    • Removed unnecessary noqa: TC002 comment from an import.
  • tests/unit/api/controllers/test_projects.py
    • Removed unnecessary noqa: TC002 comment from an import.
  • tests/unit/api/controllers/test_providers.py
    • Removed unnecessary noqa: TC002 comment from an import.
  • tests/unit/api/controllers/test_tasks.py
    • Removed unnecessary noqa: TC002 comment from an import.
  • tests/unit/api/test_app.py
    • Removed unnecessary noqa: TC002 comment from an import.
  • tests/unit/api/test_guards.py
    • Removed unnecessary noqa: TC002 comment from an import.
  • tests/unit/api/test_health.py
    • Removed unnecessary noqa: TC002 comment from an import.
  • tests/unit/api/test_middleware.py
    • Removed unnecessary noqa: TC002 comment from an import.
  • tests/unit/budget/test_category_analytics.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/communication/conflict_resolution/test_authority_strategy.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/communication/conflict_resolution/test_debate_strategy.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/communication/conflict_resolution/test_helpers.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/communication/conflict_resolution/test_hybrid_strategy.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/communication/conflict_resolution/test_service.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/communication/meeting/conftest.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/communication/meeting/test_orchestrator.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/communication/meeting/test_position_papers.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/communication/meeting/test_protocol.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/communication/meeting/test_round_robin.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/communication/meeting/test_structured_phases.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/engine/task_engine_helpers.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/engine/test_agent_engine.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/engine/test_agent_engine_errors.py
    • Removed unnecessary noqa: TC001 comments from imports.
  • tests/unit/engine/test_agent_engine_lifecycle.py
    • Removed unnecessary noqa: TC001 comments from imports.
  • tests/unit/engine/test_context.py
    • Removed unnecessary noqa: TC001 comments from imports.
  • tests/unit/engine/test_loop_protocol.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/engine/test_metrics.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/engine/test_plan_execute_loop.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/engine/test_react_loop.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/engine/test_routing_models.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/engine/test_task_engine_mutations.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/hr/test_full_snapshot_strategy.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/hr/test_hiring_service.py
    • Removed unnecessary noqa: TC001 comments from imports.
  • tests/unit/hr/test_offboarding_service.py
    • Removed unnecessary noqa comments from imports.
  • tests/unit/hr/test_onboarding_service.py
    • Removed unnecessary noqa: TC001 comments from imports.
  • tests/unit/hr/test_registry.py
    • Removed unnecessary noqa: TC001 comment from an import.
  • tests/unit/memory/backends/mem0/conftest.py
    • Added a new file providing shared fixtures for Mem0 adapter unit tests, including configuration, mocked client, and helper functions for test data.
  • tests/unit/memory/backends/mem0/test_adapter.py
    • Added a new file with unit tests for the Mem0MemoryBackend adapter's properties, capabilities, protocol conformance, and lifecycle management, including connection guards and error handling.
  • tests/unit/memory/backends/mem0/test_adapter_crud.py
    • Added a new file with unit tests for the CRUD operations (store, retrieve, get, delete, count) of the Mem0MemoryBackend, covering success cases, error handling, and ownership verification.
  • tests/unit/memory/backends/mem0/test_adapter_shared.py
    • Added a new file with unit tests for the shared knowledge store operations (publish, search_shared, retract) of the Mem0MemoryBackend, focusing on ownership verification and namespace handling.
  • tests/unit/memory/backends/mem0/test_config.py
    • Added a new file with unit tests for Mem0EmbedderConfig, Mem0BackendConfig, and related configuration building functions, covering validation, defaults, and error conditions.
  • tests/unit/memory/backends/mem0/test_mappers.py
    • Added a new file with unit tests for the mapping functions between SynthOrg domain models and Mem0 data structures, ensuring correct data transformation and validation.
  • tests/unit/memory/test_factory.py
    • Updated tests to verify the correct creation of Mem0MemoryBackend instances and their properties, including handling of embedder configurations and error wrapping during initialization.
  • tests/unit/memory/test_init.py
    • Added Mem0EmbedderConfig and Mem0MemoryBackend to the expected exports of the ai_company.memory package.
  • tests/unit/observability/test_events.py
    • Removed deprecated memory event constants and added new ones related to configuration invalidation and agent ID rejection.
  • tests/unit/providers/conftest.py
    • Removed unnecessary noqa: TC003 comment from an import.
  • tests/unit/providers/test_protocol.py
    • Removed unnecessary noqa: TC003 comment from an import.
  • tests/unit/tools/git/conftest.py
    • Removed unnecessary noqa: TC003 comment from an import.
  • tests/unit/tools/git/test_git_sandbox_integration.py
    • Removed unnecessary noqa: TC003 comment from an import.
  • tests/unit/tools/sandbox/conftest.py
    • Removed unnecessary noqa: TC003 comment from an import.
  • tests/unit/tools/sandbox/test_protocol.py
    • Removed unnecessary noqa comments from imports.
  • uv.lock
    • Added new dependencies: backoff, greenlet, grpcio, h2, hpack, hyperframe, mem0ai, numpy, portalocker, posthog, protobuf, pytz, qdrant-client, and sqlalchemy.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/dependency-review.yml
Activity
  • The pull request includes extensive test coverage with 7453 tests passing and 94.74% coverage, including dedicated unit tests for the adapter's CRUD operations, shared knowledge store, lifecycle, capabilities, mappers, config, and factory.
  • All edge cases, such as orphan rejection, namespace guards, ownership verification, and error wrapping, have been thoroughly tested.
  • The code adheres to strict quality standards, with mypy strict mode passing and ruff linting and formatting being clean.
  • The changes underwent a rigorous pre-review process through 9 rounds of automated review, utilizing 8 specialized agents per round, indicating a high level of scrutiny before human review.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 11

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/design/memory.md`:
- Around line 303-315: The Mem0 docs example misleads by showing configurable
storage.vector_store and storage.history_store even though Mem0 hardcodes Qdrant
+ SQLite; update the docs around CompanyMemoryConfig / MemoryStorageConfig /
MemoryOptionsConfig and the create_memory_backend description to either remove
the storage.vector_store and storage.history_store keys from the Mem0 YAML
example or explicitly annotate them as "not configurable for Mem0 (hardcoded to
Qdrant + SQLite in the Mem0 backend implementation)", and mention that the
embedder kwarg must be a Mem0EmbedderConfig for create_memory_backend; ensure
the text references Mem0's fixed storage behavior so readers don't expect
selectable stores.

In `@src/ai_company/memory/backends/mem0/adapter.py`:
- Around line 276-280: In disconnect(), avoid emitting INFO lifecycle logs when
there is no actual state change: acquire self._connect_lock, check the current
state via self._connected (or self._client) and if already disconnected log a
DEBUG message (using MEMORY_BACKEND_DISCONNECTING or a new DEBUG message) and
return; only when transitioning from connected to disconnected perform the INFO
logs and set self._client = None and self._connected = False; update the method
around the existing async with self._connect_lock block in adapter.disconnect to
gate MEMORY_BACKEND_DISCONNECTING and MEMORY_BACKEND_DISCONNECTED behind the
actual state change.
- Around line 13-17: The Mem0MemoryBackend class is too large—extract the Mem0
call wrappers, ownership checks, and shared-store flows into smaller helper
modules while keeping the core client lifecycle and connection-guard logic
inside Mem0MemoryBackend (which implements MemoryBackend, MemoryCapabilities,
and SharedKnowledgeStore). Create separate modules (e.g., mem0_calls.py for
low-level RPC/wrapper functions referenced by Mem0MemoryBackend, ownership.py
for ownership/permission checks, and shared_store.py for shared knowledge store
flows) and replace the in-class large methods with thin delegating calls to
those helpers; update imports and any tests to use the new helper functions,
ensuring public method signatures on Mem0MemoryBackend remain unchanged.
- Around line 501-509: The current retrieval passes query.limit into Mem0 (via
query_to_mem0_search_args / query_to_mem0_getall_args) then applies client-side
filters (apply_post_filters / exclude_agent), which can yield fewer results if
early pages are all filtered; change the logic in the retrieval flow (the block
that calls client.search / client.get_all, _validate_mem0_result,
mem0_result_to_entry, and apply_post_filters) to page/over-fetch: repeatedly
call client.search or client.get_all with an offset/pagination token and
accumulate validated entries, converting with mem0_result_to_entry and applying
apply_post_filters and exclude_agent as you accumulate until you have at least
query.limit post-filtered entries or the backend is exhausted, then slice to
query.limit before returning; add a regression test that simulates the first
page being entirely filtered out so the caller still receives query.limit
results.
- Around line 10-11: Several methods in the mem0 adapter currently catch
builtins.MemoryError and RecursionError and re-raise them without logging, which
loses operation/backend context; update each catch branch in the adapter module
to log the exception at WARNING or ERROR with contextual fields (operation name,
backend "mem0", relevant ids/params) before re-raising, or add a small helper
(e.g., _log_and_reraise(exc, operation, **ctx)) and call it from each catch to
emit the log and then re-raise the original exception to preserve type and
traceback.

In `@src/ai_company/memory/backends/mem0/config.py`:
- Around line 132-183: build_config_from_company_config currently passes
MemoryStorageConfig.data_dir and leaves collection_name defaulted, causing
multiple companies to share the same Mem0 storage; update
build_config_from_company_config to namespace Mem0 by company (e.g., append or
prefix a stable company identifier from config such as config.company_id or
config.organization to data_dir or to collection_name when constructing
Mem0BackendConfig) so each company gets a unique collection/path, and if no
company identifier is available, raise ValueError to fail fast; ensure you
reference Mem0BackendConfig (where data_dir/collection_name are set) and
consider adapter.py usages that key by agent_id/_SHARED_NAMESPACE so the
namespace change isolates records per company.
- Around line 77-98: The _reject_traversal() validator currently only checks for
".." but must also reject Windows-style paths so build_mem0_config_dict()
doesn't later produce mixed-separator paths; update _reject_traversal() (the
model_validator in class for mem0 config) to detect and reject Windows paths by
checking PureWindowsPath(self.data_dir).drive or the presence of "\\" in
self.data_dir, log MEMORY_BACKEND_CONFIG_INVALID with backend="mem0",
field="data_dir", value=self.data_dir and an appropriate reason message, and
raise ValueError when detected; keep the existing ".." check and return self
when valid.

In `@src/ai_company/memory/backends/mem0/mappers.py`:
- Around line 346-394: The agent_id parameters in query_to_mem0_search_args and
query_to_mem0_getall_args (and similarly in extract_publisher) should use the
NotBlankStr type from core.types instead of plain str; update the function
signatures to accept NotBlankStr (or NotBlankStr | None for optional cases),
import NotBlankStr from core.types, and ensure the returned dict values (user_id
or publisher) preserve the NotBlankStr type (no extra whitespace normalization
logic). Also apply the same change to the other affected functions around the
region mentioned (the functions at ~513-526) so all public agent/identifier
parameters use NotBlankStr consistently.
- Around line 264-343: Reduce mem0_result_to_entry's size by extracting its
raw-field validation and created_at fallback logic into two small helpers: one
to validate/extract the id and content (e.g., _extract_mem0_id(raw) and
_extract_mem0_content(raw)) that perform the logger.warning +
MemoryRetrievalError behavior, and one to compute created_at fallback (e.g.,
_resolve_created_at(created_raw, updated_at, expires_at)) that wraps the
parse_mem0_datetime usage and the fallback selection + warning. Keep the
remainder of mem0_result_to_entry to call parse_mem0_metadata,
normalize_relevance_score, and construct MemoryEntry with the values returned
from these helpers (preserve existing logger messages, constants like
MEMORY_MODEL_INVALID, and types such as NotBlankStr and MemoryRetrievalError) so
the function stays under 50 lines and the recovery paths are easy to unit-test.
- Around line 371-375: The mapper currently sends query.limit to Mem0 before
local post-filtering, which causes under-filled results; update the payloads
returned by the mapping functions that build Mem0 requests (the dicts around the
return at lines ~371 and the similar blocks at ~391-394 and ~397-439) to request
a larger candidate window or enable pagination instead of using query.limit
directly (for example: page_size = max(query.limit * N, query.limit + M) or
fetch pages until enough candidates are retrieved), then run
apply_post_filters() and only slice the final results to query.limit locally;
ensure the change is applied wherever the function returns {"query": ...,
"user_id": ..., "limit": ...} so post-filtering can produce a fully-filled
result set.
- Around line 308-328: The fallback logic for created_at currently always picks
updated_at first which can violate MemoryEntry invariants when expires_at is
earlier; modify the branch that computes fallback (in the code handling
created_at None near variables created_at, updated_at, expires_at,
logger.warning, MEMORY_MODEL_INVALID, raw) to choose the earliest timestamp
among the available candidates (updated_at, expires_at, and datetime.now(UTC))
rather than preferring updated_at always, and set fallback_source to a
descriptive string reflecting which value(s) were used (e.g. "updated_at",
"expires_at", "min(updated_at,expires_at)", or "now()") before assigning
created_at to that earliest fallback.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: d5aa0f5f-a248-421a-bab8-9a99e5a0b05d

📥 Commits

Reviewing files that changed from the base of the PR and between 2f10d49 and fc9fcb7.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (83)
  • .github/workflows/dependency-review.yml
  • CLAUDE.md
  • README.md
  • docs/design/memory.md
  • docs/roadmap/index.md
  • pyproject.toml
  • src/ai_company/memory/__init__.py
  • src/ai_company/memory/backends/__init__.py
  • src/ai_company/memory/backends/mem0/__init__.py
  • src/ai_company/memory/backends/mem0/adapter.py
  • src/ai_company/memory/backends/mem0/config.py
  • src/ai_company/memory/backends/mem0/mappers.py
  • src/ai_company/memory/factory.py
  • src/ai_company/memory/models.py
  • src/ai_company/observability/events/memory.py
  • tests/integration/communication/test_meeting_integration.py
  • tests/integration/memory/test_mem0_backend.py
  • tests/integration/tools/conftest.py
  • tests/integration/tools/test_sandbox_integration.py
  • tests/unit/api/auth/test_controller.py
  • tests/unit/api/conftest.py
  • tests/unit/api/controllers/test_agents.py
  • tests/unit/api/controllers/test_analytics.py
  • tests/unit/api/controllers/test_approvals.py
  • tests/unit/api/controllers/test_artifacts.py
  • tests/unit/api/controllers/test_autonomy.py
  • tests/unit/api/controllers/test_budget.py
  • tests/unit/api/controllers/test_company.py
  • tests/unit/api/controllers/test_departments.py
  • tests/unit/api/controllers/test_meetings.py
  • tests/unit/api/controllers/test_messages.py
  • tests/unit/api/controllers/test_projects.py
  • tests/unit/api/controllers/test_providers.py
  • tests/unit/api/controllers/test_tasks.py
  • tests/unit/api/test_app.py
  • tests/unit/api/test_guards.py
  • tests/unit/api/test_health.py
  • tests/unit/api/test_middleware.py
  • tests/unit/budget/test_category_analytics.py
  • tests/unit/communication/conflict_resolution/test_authority_strategy.py
  • tests/unit/communication/conflict_resolution/test_debate_strategy.py
  • tests/unit/communication/conflict_resolution/test_helpers.py
  • tests/unit/communication/conflict_resolution/test_hybrid_strategy.py
  • tests/unit/communication/conflict_resolution/test_service.py
  • tests/unit/communication/meeting/conftest.py
  • tests/unit/communication/meeting/test_orchestrator.py
  • tests/unit/communication/meeting/test_position_papers.py
  • tests/unit/communication/meeting/test_protocol.py
  • tests/unit/communication/meeting/test_round_robin.py
  • tests/unit/communication/meeting/test_structured_phases.py
  • tests/unit/engine/task_engine_helpers.py
  • tests/unit/engine/test_agent_engine.py
  • tests/unit/engine/test_agent_engine_errors.py
  • tests/unit/engine/test_agent_engine_lifecycle.py
  • tests/unit/engine/test_context.py
  • tests/unit/engine/test_loop_protocol.py
  • tests/unit/engine/test_metrics.py
  • tests/unit/engine/test_plan_execute_loop.py
  • tests/unit/engine/test_react_loop.py
  • tests/unit/engine/test_routing_models.py
  • tests/unit/engine/test_task_engine_mutations.py
  • tests/unit/hr/test_full_snapshot_strategy.py
  • tests/unit/hr/test_hiring_service.py
  • tests/unit/hr/test_offboarding_service.py
  • tests/unit/hr/test_onboarding_service.py
  • tests/unit/hr/test_registry.py
  • tests/unit/memory/backends/__init__.py
  • tests/unit/memory/backends/mem0/__init__.py
  • tests/unit/memory/backends/mem0/conftest.py
  • tests/unit/memory/backends/mem0/test_adapter.py
  • tests/unit/memory/backends/mem0/test_adapter_crud.py
  • tests/unit/memory/backends/mem0/test_adapter_shared.py
  • tests/unit/memory/backends/mem0/test_config.py
  • tests/unit/memory/backends/mem0/test_mappers.py
  • tests/unit/memory/test_factory.py
  • tests/unit/memory/test_init.py
  • tests/unit/observability/test_events.py
  • tests/unit/providers/conftest.py
  • tests/unit/providers/test_protocol.py
  • tests/unit/tools/git/conftest.py
  • tests/unit/tools/git/test_git_sandbox_integration.py
  • tests/unit/tools/sandbox/conftest.py
  • tests/unit/tools/sandbox/test_protocol.py
💤 Files with no reviewable changes (1)
  • tests/unit/observability/test_events.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Agent
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (6)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Do NOT use from __future__ import annotations — Python 3.14 has PEP 649 native lazy annotations
Use except A, B: (no parentheses) for exception handling syntax per PEP 758 — ruff enforces this on Python 3.14

Files:

  • tests/unit/communication/meeting/test_structured_phases.py
  • tests/unit/providers/conftest.py
  • tests/unit/hr/test_registry.py
  • tests/integration/communication/test_meeting_integration.py
  • tests/unit/api/controllers/test_projects.py
  • tests/unit/communication/conflict_resolution/test_hybrid_strategy.py
  • tests/unit/tools/sandbox/conftest.py
  • tests/integration/tools/conftest.py
  • tests/unit/api/test_middleware.py
  • tests/unit/api/controllers/test_providers.py
  • tests/unit/communication/meeting/test_orchestrator.py
  • tests/unit/tools/git/test_git_sandbox_integration.py
  • tests/unit/memory/backends/mem0/test_adapter.py
  • tests/unit/hr/test_onboarding_service.py
  • tests/unit/engine/test_agent_engine_lifecycle.py
  • tests/unit/engine/test_plan_execute_loop.py
  • tests/unit/providers/test_protocol.py
  • tests/unit/tools/git/conftest.py
  • src/ai_company/observability/events/memory.py
  • tests/unit/api/controllers/test_company.py
  • tests/unit/engine/test_agent_engine.py
  • tests/unit/api/controllers/test_approvals.py
  • tests/unit/hr/test_hiring_service.py
  • src/ai_company/memory/backends/mem0/__init__.py
  • src/ai_company/memory/factory.py
  • tests/unit/tools/sandbox/test_protocol.py
  • tests/unit/memory/test_init.py
  • tests/unit/budget/test_category_analytics.py
  • tests/unit/api/controllers/test_agents.py
  • tests/unit/hr/test_offboarding_service.py
  • tests/unit/memory/backends/mem0/test_mappers.py
  • tests/unit/engine/test_metrics.py
  • tests/unit/api/conftest.py
  • src/ai_company/memory/models.py
  • tests/unit/engine/test_loop_protocol.py
  • tests/unit/communication/conflict_resolution/test_service.py
  • tests/unit/engine/test_agent_engine_errors.py
  • tests/unit/hr/test_full_snapshot_strategy.py
  • tests/unit/engine/task_engine_helpers.py
  • tests/unit/api/controllers/test_messages.py
  • tests/unit/api/controllers/test_analytics.py
  • tests/unit/communication/meeting/test_position_papers.py
  • tests/unit/communication/meeting/test_round_robin.py
  • tests/unit/api/auth/test_controller.py
  • tests/unit/api/controllers/test_meetings.py
  • tests/unit/api/test_health.py
  • tests/unit/api/controllers/test_tasks.py
  • tests/unit/communication/conflict_resolution/test_authority_strategy.py
  • tests/unit/api/controllers/test_departments.py
  • tests/unit/api/test_app.py
  • tests/unit/engine/test_task_engine_mutations.py
  • tests/unit/api/test_guards.py
  • tests/unit/engine/test_context.py
  • tests/unit/memory/backends/mem0/test_adapter_crud.py
  • tests/unit/communication/conflict_resolution/test_helpers.py
  • tests/unit/communication/conflict_resolution/test_debate_strategy.py
  • tests/unit/api/controllers/test_artifacts.py
  • src/ai_company/memory/backends/__init__.py
  • src/ai_company/memory/__init__.py
  • tests/unit/engine/test_react_loop.py
  • tests/unit/engine/test_routing_models.py
  • tests/unit/communication/meeting/test_protocol.py
  • tests/unit/memory/test_factory.py
  • tests/integration/memory/test_mem0_backend.py
  • tests/unit/communication/meeting/conftest.py
  • tests/unit/memory/backends/mem0/conftest.py
  • tests/unit/api/controllers/test_budget.py
  • tests/unit/memory/backends/mem0/test_adapter_shared.py
  • tests/unit/api/controllers/test_autonomy.py
  • tests/unit/memory/backends/mem0/test_config.py
  • tests/integration/tools/test_sandbox_integration.py
  • src/ai_company/memory/backends/mem0/adapter.py
  • src/ai_company/memory/backends/mem0/mappers.py
  • src/ai_company/memory/backends/mem0/config.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.e2e, @pytest.mark.slow for test markers
Prefer @pytest.mark.parametrize for testing similar cases

Files:

  • tests/unit/communication/meeting/test_structured_phases.py
  • tests/unit/providers/conftest.py
  • tests/unit/hr/test_registry.py
  • tests/integration/communication/test_meeting_integration.py
  • tests/unit/api/controllers/test_projects.py
  • tests/unit/communication/conflict_resolution/test_hybrid_strategy.py
  • tests/unit/tools/sandbox/conftest.py
  • tests/integration/tools/conftest.py
  • tests/unit/api/test_middleware.py
  • tests/unit/api/controllers/test_providers.py
  • tests/unit/communication/meeting/test_orchestrator.py
  • tests/unit/tools/git/test_git_sandbox_integration.py
  • tests/unit/memory/backends/mem0/test_adapter.py
  • tests/unit/hr/test_onboarding_service.py
  • tests/unit/engine/test_agent_engine_lifecycle.py
  • tests/unit/engine/test_plan_execute_loop.py
  • tests/unit/providers/test_protocol.py
  • tests/unit/tools/git/conftest.py
  • tests/unit/api/controllers/test_company.py
  • tests/unit/engine/test_agent_engine.py
  • tests/unit/api/controllers/test_approvals.py
  • tests/unit/hr/test_hiring_service.py
  • tests/unit/tools/sandbox/test_protocol.py
  • tests/unit/memory/test_init.py
  • tests/unit/budget/test_category_analytics.py
  • tests/unit/api/controllers/test_agents.py
  • tests/unit/hr/test_offboarding_service.py
  • tests/unit/memory/backends/mem0/test_mappers.py
  • tests/unit/engine/test_metrics.py
  • tests/unit/api/conftest.py
  • tests/unit/engine/test_loop_protocol.py
  • tests/unit/communication/conflict_resolution/test_service.py
  • tests/unit/engine/test_agent_engine_errors.py
  • tests/unit/hr/test_full_snapshot_strategy.py
  • tests/unit/engine/task_engine_helpers.py
  • tests/unit/api/controllers/test_messages.py
  • tests/unit/api/controllers/test_analytics.py
  • tests/unit/communication/meeting/test_position_papers.py
  • tests/unit/communication/meeting/test_round_robin.py
  • tests/unit/api/auth/test_controller.py
  • tests/unit/api/controllers/test_meetings.py
  • tests/unit/api/test_health.py
  • tests/unit/api/controllers/test_tasks.py
  • tests/unit/communication/conflict_resolution/test_authority_strategy.py
  • tests/unit/api/controllers/test_departments.py
  • tests/unit/api/test_app.py
  • tests/unit/engine/test_task_engine_mutations.py
  • tests/unit/api/test_guards.py
  • tests/unit/engine/test_context.py
  • tests/unit/memory/backends/mem0/test_adapter_crud.py
  • tests/unit/communication/conflict_resolution/test_helpers.py
  • tests/unit/communication/conflict_resolution/test_debate_strategy.py
  • tests/unit/api/controllers/test_artifacts.py
  • tests/unit/engine/test_react_loop.py
  • tests/unit/engine/test_routing_models.py
  • tests/unit/communication/meeting/test_protocol.py
  • tests/unit/memory/test_factory.py
  • tests/integration/memory/test_mem0_backend.py
  • tests/unit/communication/meeting/conftest.py
  • tests/unit/memory/backends/mem0/conftest.py
  • tests/unit/api/controllers/test_budget.py
  • tests/unit/memory/backends/mem0/test_adapter_shared.py
  • tests/unit/api/controllers/test_autonomy.py
  • tests/unit/memory/backends/mem0/test_config.py
  • tests/integration/tools/test_sandbox_integration.py
pyproject.toml

📄 CodeRabbit inference engine (CLAUDE.md)

pyproject.toml: Use asyncio_mode = "auto" in pytest configuration—no manual @pytest.mark.asyncio needed on individual tests
Test timeout: 30 seconds per test
Dependencies: all versions pinned with == in pyproject.toml. Groups: test and dev (includes test). Install via uv sync.

Files:

  • pyproject.toml
src/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.py: Type hints: all public functions must have type hints, mypy strict mode
Docstrings: Google style, required on public classes/functions (enforced by ruff D rules)
Create new objects instead of mutating existing ones—never mutate existing objects. For non-Pydantic internal collections (registries, BaseTool), use copy.deepcopy() at construction + MappingProxyType wrapping for read-only enforcement.
For dict/list fields in frozen Pydantic models, rely on frozen=True for field reassignment prevention and use copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, serializing for persistence)
Config vs runtime state: use frozen Pydantic models for config/identity; use separate mutable-via-copy models (using model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Use Pydantic v2 (BaseModel, model_validator, computed_field, ConfigDict). Use @computed_field for derived values instead of storing + validating redundant fields. Use NotBlankStr (from core.types) for all identifier/name fields—including optional and tuple variants—instead of manual whitespace validators.
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code (e.g. multiple tool invocations, parallel agent calls). Prefer structured concurrency over bare create_task.
Line length: 88 characters (enforced by ruff)
Functions: < 50 lines, files < 800 lines
Handle errors explicitly, never silently swallow them
Validate at system boundaries (user input, external APIs, config files)
Every module with business logic MUST have: from ai_company.observability import get_logger then logger = get_logger(__name__)
Never use import logging / logging.getLogger() / print() in application code
Always use logger as the variable name (not _logger, not log)
Use event name constants from ai_company.observability.events domain-spe...

Files:

  • src/ai_company/observability/events/memory.py
  • src/ai_company/memory/backends/mem0/__init__.py
  • src/ai_company/memory/factory.py
  • src/ai_company/memory/models.py
  • src/ai_company/memory/backends/__init__.py
  • src/ai_company/memory/__init__.py
  • src/ai_company/memory/backends/mem0/adapter.py
  • src/ai_company/memory/backends/mem0/mappers.py
  • src/ai_company/memory/backends/mem0/config.py
docs/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Docs source: docs/ (Markdown, built with Zensical). Design spec: docs/design/ (7 pages: index, agents, organization, communication, engine, memory, operations).

Files:

  • docs/roadmap/index.md
  • docs/design/memory.md
.github/workflows/*.yml

📄 CodeRabbit inference engine (CLAUDE.md)

CI: Jobs (lint + type-check + test in parallel) → ci-pass gate. Pages workflow exports OpenAPI schema, builds Astro landing + Zensical docs, merges, deploys to GitHub Pages on push to main.

Files:

  • .github/workflows/dependency-review.yml
🧠 Learnings (11)
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to scripts/**/*.py : Scripts: `scripts/` directory with relaxed ruff rules allowing `print` and deferred imports

Applied to files:

  • pyproject.toml
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to src/**/*.py : All provider calls go through `BaseCompletionProvider` which applies retry + rate limiting automatically. Never implement retry logic in driver subclasses or calling code—it's handled by the base class.

Applied to files:

  • tests/unit/providers/test_protocol.py
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to docs/**/*.md : Docs source: `docs/` (Markdown, built with Zensical). Design spec: `docs/design/` (7 pages: index, agents, organization, communication, engine, memory, operations).

Applied to files:

  • docs/roadmap/index.md
  • CLAUDE.md
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to src/**/*.py : Every module with business logic MUST have: `from ai_company.observability import get_logger` then `logger = get_logger(__name__)`

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to src/**/*.py : Use event name constants from `ai_company.observability.events` domain-specific modules (e.g. `PROVIDER_CALL_START` from `events.provider`, `BUDGET_RECORD_ADDED` from `events.budget`, etc.) instead of hardcoded string literals

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to src/**/*.py : Always use structured logging kwargs: `logger.info(EVENT, key=value)` — never `logger.info("msg %s", val)`

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to src/**/*.py : Never use `import logging` / `logging.getLogger()` / `print()` in application code

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to src/**/*.py : Always use `logger` as the variable name (not `_logger`, not `log`)

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to src/**/*.py : All error paths must log at WARNING or ERROR with context before raising

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to src/**/*.py : All state transitions must log at INFO

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to pyproject.toml : Dependencies: all versions pinned with `==` in `pyproject.toml`. Groups: `test` and `dev` (includes test). Install via `uv sync`.

Applied to files:

  • CLAUDE.md
🧬 Code graph analysis (45)
tests/unit/communication/meeting/test_structured_phases.py (1)
src/ai_company/communication/meeting/models.py (1)
  • MeetingAgenda (77-96)
tests/unit/hr/test_registry.py (3)
tests/unit/hr/promotion/conftest.py (1)
  • registry (98-100)
tests/unit/hr/conftest.py (1)
  • registry (174-176)
src/ai_company/hr/registry.py (1)
  • AgentRegistryService (32-262)
tests/integration/communication/test_meeting_integration.py (1)
src/ai_company/communication/meeting/protocol.py (1)
  • MeetingProtocol (61-100)
tests/unit/communication/conflict_resolution/test_hybrid_strategy.py (1)
src/ai_company/communication/delegation/hierarchy.py (1)
  • HierarchyResolver (16-277)
tests/unit/communication/meeting/test_orchestrator.py (1)
src/ai_company/communication/meeting/protocol.py (1)
  • MeetingProtocol (61-100)
tests/unit/memory/backends/mem0/test_adapter.py (7)
src/ai_company/core/enums.py (1)
  • MemoryCategory (101-108)
src/ai_company/memory/backends/mem0/config.py (1)
  • Mem0BackendConfig (54-98)
src/ai_company/memory/errors.py (2)
  • MemoryConnectionError (17-18)
  • MemoryError (13-14)
src/ai_company/memory/models.py (1)
  • MemoryQuery (153-230)
src/ai_company/memory/protocol.py (1)
  • MemoryBackend (20-182)
src/ai_company/memory/shared.py (1)
  • SharedKnowledgeStore (18-82)
tests/unit/memory/backends/mem0/conftest.py (2)
  • make_store_request (111-117)
  • backend (41-49)
tests/unit/hr/test_onboarding_service.py (1)
tests/unit/hr/conftest.py (2)
  • onboarding_service (180-182)
  • registry (174-176)
tests/unit/engine/test_agent_engine_lifecycle.py (2)
src/ai_company/core/agent.py (1)
  • AgentIdentity (266-342)
src/ai_company/core/task.py (1)
  • Task (45-261)
tests/unit/engine/test_agent_engine.py (1)
src/ai_company/core/agent.py (1)
  • AgentIdentity (266-342)
tests/unit/api/controllers/test_approvals.py (2)
tests/unit/api/conftest.py (1)
  • approval_store (606-607)
src/ai_company/api/approval_store.py (1)
  • ApprovalStore (27-153)
tests/unit/hr/test_hiring_service.py (3)
tests/unit/hr/conftest.py (2)
  • onboarding_service (180-182)
  • registry (174-176)
src/ai_company/hr/onboarding_service.py (1)
  • OnboardingService (28-173)
src/ai_company/hr/registry.py (1)
  • AgentRegistryService (32-262)
src/ai_company/memory/backends/mem0/__init__.py (2)
src/ai_company/memory/backends/mem0/adapter.py (1)
  • Mem0MemoryBackend (194-1073)
src/ai_company/memory/backends/mem0/config.py (2)
  • Mem0BackendConfig (54-98)
  • Mem0EmbedderConfig (23-51)
src/ai_company/memory/factory.py (4)
src/ai_company/memory/config.py (1)
  • CompanyMemoryConfig (139-195)
src/ai_company/memory/backends/mem0/config.py (2)
  • Mem0EmbedderConfig (23-51)
  • build_config_from_company_config (132-183)
src/ai_company/memory/errors.py (1)
  • MemoryConfigError (40-41)
src/ai_company/memory/backends/mem0/adapter.py (2)
  • Mem0MemoryBackend (194-1073)
  • max_memories_per_agent (361-363)
tests/unit/budget/test_category_analytics.py (1)
src/ai_company/budget/tracker.py (1)
  • CostTracker (68-455)
tests/unit/api/controllers/test_agents.py (1)
src/ai_company/api/auth/service.py (1)
  • AuthService (36-245)
tests/unit/hr/test_offboarding_service.py (5)
src/ai_company/communication/channel.py (1)
  • Channel (14-39)
src/ai_company/communication/message.py (1)
  • Message (88-138)
src/ai_company/core/enums.py (2)
  • AgentStatus (67-73)
  • TaskStatus (198-224)
tests/unit/hr/conftest.py (1)
  • registry (174-176)
src/ai_company/hr/registry.py (1)
  • AgentRegistryService (32-262)
tests/unit/memory/backends/mem0/test_mappers.py (3)
src/ai_company/core/enums.py (1)
  • MemoryCategory (101-108)
src/ai_company/memory/errors.py (2)
  • MemoryRetrievalError (25-26)
  • MemoryStoreError (21-22)
src/ai_company/memory/models.py (2)
  • MemoryEntry (82-150)
  • MemoryMetadata (20-52)
tests/unit/engine/test_metrics.py (1)
src/ai_company/engine/context.py (1)
  • AgentContext (87-307)
tests/unit/api/conftest.py (7)
src/ai_company/budget/cost_record.py (1)
  • CostRecord (16-57)
src/ai_company/communication/channel.py (1)
  • Channel (14-39)
src/ai_company/communication/message.py (1)
  • Message (88-138)
src/ai_company/hr/enums.py (1)
  • LifecycleEventType (32-41)
src/ai_company/hr/performance/models.py (2)
  • CollaborationMetricRecord (69-124)
  • TaskMetricRecord (24-66)
src/ai_company/security/models.py (1)
  • AuditEntry (112-149)
src/ai_company/security/timeout/parked_context.py (1)
  • ParkedContext (19-64)
tests/unit/engine/test_loop_protocol.py (2)
tests/unit/engine/conftest.py (1)
  • engine (449-460)
src/ai_company/engine/context.py (1)
  • AgentContext (87-307)
tests/unit/communication/conflict_resolution/test_service.py (1)
src/ai_company/communication/delegation/hierarchy.py (1)
  • HierarchyResolver (16-277)
tests/unit/engine/test_agent_engine_errors.py (3)
src/ai_company/core/agent.py (1)
  • AgentIdentity (266-342)
src/ai_company/core/enums.py (1)
  • TaskStatus (198-224)
src/ai_company/core/task.py (1)
  • Task (45-261)
tests/unit/hr/test_full_snapshot_strategy.py (1)
src/ai_company/memory/consolidation/models.py (1)
  • ArchivalEntry (56-91)
tests/unit/engine/task_engine_helpers.py (1)
src/ai_company/core/task.py (1)
  • Task (45-261)
tests/unit/communication/meeting/test_position_papers.py (1)
src/ai_company/communication/meeting/models.py (1)
  • MeetingAgenda (77-96)
tests/unit/communication/meeting/test_round_robin.py (1)
src/ai_company/communication/meeting/models.py (1)
  • MeetingAgenda (77-96)
tests/unit/api/auth/test_controller.py (1)
src/ai_company/api/auth/service.py (1)
  • AuthService (36-245)
tests/unit/communication/conflict_resolution/test_authority_strategy.py (1)
src/ai_company/communication/delegation/hierarchy.py (1)
  • HierarchyResolver (16-277)
tests/unit/engine/test_task_engine_mutations.py (1)
src/ai_company/core/task.py (1)
  • Task (45-261)
tests/unit/engine/test_context.py (3)
src/ai_company/core/agent.py (1)
  • AgentIdentity (266-342)
src/ai_company/core/enums.py (1)
  • TaskStatus (198-224)
src/ai_company/core/task.py (1)
  • Task (45-261)
tests/unit/memory/backends/mem0/test_adapter_crud.py (4)
src/ai_company/core/enums.py (1)
  • MemoryCategory (101-108)
src/ai_company/memory/backends/mem0/adapter.py (6)
  • _validate_mem0_result (123-175)
  • store (417-474)
  • search (98-100)
  • retrieve (476-535)
  • delete (110-112)
  • delete (622-720)
src/ai_company/memory/errors.py (3)
  • MemoryRetrievalError (25-26)
  • MemoryStoreError (21-22)
  • MemoryError (13-14)
src/ai_company/memory/models.py (1)
  • MemoryQuery (153-230)
tests/unit/communication/conflict_resolution/test_helpers.py (1)
src/ai_company/communication/delegation/hierarchy.py (1)
  • HierarchyResolver (16-277)
tests/unit/communication/conflict_resolution/test_debate_strategy.py (1)
src/ai_company/communication/delegation/hierarchy.py (1)
  • HierarchyResolver (16-277)
src/ai_company/memory/backends/__init__.py (1)
src/ai_company/memory/backends/mem0/adapter.py (1)
  • Mem0MemoryBackend (194-1073)
src/ai_company/memory/__init__.py (2)
src/ai_company/memory/backends/mem0/config.py (1)
  • Mem0EmbedderConfig (23-51)
src/ai_company/memory/backends/mem0/adapter.py (1)
  • Mem0MemoryBackend (194-1073)
tests/unit/engine/test_react_loop.py (1)
src/ai_company/core/agent.py (1)
  • AgentIdentity (266-342)
tests/unit/engine/test_routing_models.py (1)
src/ai_company/core/agent.py (1)
  • AgentIdentity (266-342)
tests/integration/memory/test_mem0_backend.py (8)
src/ai_company/core/enums.py (1)
  • MemoryCategory (101-108)
src/ai_company/memory/backends/mem0/adapter.py (15)
  • Mem0MemoryBackend (194-1073)
  • max_memories_per_agent (361-363)
  • add (94-96)
  • search (98-100)
  • store (417-474)
  • retrieve (476-535)
  • publish (813-876)
  • search_shared (878-968)
  • get (106-108)
  • get (537-620)
  • delete (110-112)
  • delete (622-720)
  • retract (970-1073)
  • get_all (102-104)
  • count (722-809)
src/ai_company/memory/backends/mem0/config.py (2)
  • Mem0BackendConfig (54-98)
  • Mem0EmbedderConfig (23-51)
src/ai_company/memory/models.py (2)
  • MemoryQuery (153-230)
  • MemoryStoreRequest (55-79)
src/ai_company/memory/retrieval_config.py (1)
  • MemoryRetrievalConfig (20-132)
src/ai_company/memory/retriever.py (1)
  • ContextInjectionStrategy (97-400)
tests/unit/memory/test_factory.py (1)
  • _test_embedder (21-26)
tests/unit/memory/backends/mem0/conftest.py (1)
  • mem0_config (26-31)
tests/unit/memory/backends/mem0/conftest.py (4)
src/ai_company/core/enums.py (1)
  • MemoryCategory (101-108)
src/ai_company/memory/backends/mem0/adapter.py (1)
  • max_memories_per_agent (361-363)
src/ai_company/memory/backends/mem0/config.py (2)
  • Mem0BackendConfig (54-98)
  • Mem0EmbedderConfig (23-51)
src/ai_company/memory/models.py (1)
  • MemoryStoreRequest (55-79)
tests/unit/api/controllers/test_budget.py (2)
src/ai_company/budget/cost_record.py (1)
  • CostRecord (16-57)
src/ai_company/budget/tracker.py (1)
  • CostTracker (68-455)
tests/unit/memory/backends/mem0/test_adapter_shared.py (4)
src/ai_company/memory/backends/mem0/adapter.py (11)
  • Mem0MemoryBackend (194-1073)
  • add (94-96)
  • publish (813-876)
  • search (98-100)
  • search_shared (878-968)
  • get_all (102-104)
  • get (106-108)
  • get (537-620)
  • delete (110-112)
  • delete (622-720)
  • retract (970-1073)
src/ai_company/memory/errors.py (3)
  • MemoryRetrievalError (25-26)
  • MemoryStoreError (21-22)
  • MemoryError (13-14)
src/ai_company/memory/models.py (1)
  • MemoryQuery (153-230)
src/ai_company/core/enums.py (1)
  • MemoryCategory (101-108)
tests/unit/memory/backends/mem0/test_config.py (4)
src/ai_company/memory/backends/mem0/config.py (4)
  • Mem0BackendConfig (54-98)
  • Mem0EmbedderConfig (23-51)
  • build_config_from_company_config (132-183)
  • build_mem0_config_dict (101-129)
src/ai_company/memory/config.py (2)
  • CompanyMemoryConfig (139-195)
  • MemoryStorageConfig (25-104)
tests/integration/memory/test_mem0_backend.py (1)
  • backend (45-54)
tests/unit/memory/backends/mem0/conftest.py (1)
  • mem0_config (26-31)
src/ai_company/memory/backends/mem0/adapter.py (3)
src/ai_company/memory/backends/mem0/config.py (2)
  • Mem0BackendConfig (54-98)
  • build_mem0_config_dict (101-129)
src/ai_company/memory/backends/mem0/mappers.py (8)
  • apply_post_filters (397-439)
  • build_mem0_metadata (40-59)
  • extract_category (488-510)
  • extract_publisher (513-526)
  • mem0_result_to_entry (264-343)
  • query_to_mem0_getall_args (378-394)
  • query_to_mem0_search_args (346-375)
  • validate_add_result (445-485)
src/ai_company/memory/models.py (3)
  • MemoryEntry (82-150)
  • MemoryQuery (153-230)
  • MemoryStoreRequest (55-79)
src/ai_company/memory/backends/mem0/mappers.py (3)
src/ai_company/core/enums.py (1)
  • MemoryCategory (101-108)
src/ai_company/memory/errors.py (2)
  • MemoryRetrievalError (25-26)
  • MemoryStoreError (21-22)
src/ai_company/memory/models.py (2)
  • MemoryEntry (82-150)
  • MemoryMetadata (20-52)
src/ai_company/memory/backends/mem0/config.py (2)
src/ai_company/memory/config.py (1)
  • CompanyMemoryConfig (139-195)
src/ai_company/observability/_logger.py (1)
  • get_logger (8-28)
🪛 LanguageTool
CLAUDE.md

[style] ~130-~130: A comma is missing here.
Context: ...nder ai_company.observability.events (e.g. PROVIDER_CALL_START from `events.prov...

(EG_NO_COMMA)

docs/design/memory.md

[style] ~313-~313: Consider using the typographical ellipsis character here instead.
Context: ...g). All are frozen Pydantic models. The create_memory_backend(config, *, embedder=...) factory returns an isolated `MemoryBa...

(ELLIPSIS)

🔇 Additional comments (60)
tests/unit/api/controllers/test_messages.py (1)

6-6: Import cleanup looks good.

This change is non-functional and keeps typing intact for TestClient[Any].

tests/unit/providers/test_protocol.py (1)

3-3: Import cleanup looks good.

Removing the inline noqa here is safe and keeps the test module cleaner.

tests/unit/api/test_app.py (1)

7-7: Import cleanup looks good.

TestClient is directly used for the fixture type annotation, and removing the inline # noqa does not introduce any functional or guideline regressions.

tests/unit/api/controllers/test_providers.py (1)

6-6: Looks good — lint suppression removal is safe.

Line 6 now uses a clean TestClient import with no behavior change and no guideline violations.

tests/unit/engine/test_agent_engine_errors.py (1)

8-10: Import cleanup is correct and safe.

AgentIdentity and Task are both used by test signatures, so removing inline noqa here does not introduce lint or runtime risk.

tests/unit/api/controllers/test_approvals.py (1)

7-7: Import cleanup looks good.

Line 7 and Line 9 keep the same runtime behavior while removing inline lint suppressions, and the imports remain consistent with fixture/type usage in this test module.

Also applies to: 9-9

tests/unit/api/conftest.py (1)

5-39: LGTM: import cleanup is behavior-neutral and safe.

Removing the inline noqa suppressions here does not alter functionality, and the imported symbols are used within this fixture module.

tests/unit/api/controllers/test_departments.py (1)

6-6: Import cleanup is good.

Removing the inline suppression keeps the test import clean and does not change runtime behavior.

tests/unit/hr/test_registry.py (1)

7-7: Good cleanup: removing inline lint suppression is safe here.

This keeps the test import explicit and readable without changing behavior.

tests/unit/tools/sandbox/test_protocol.py (3)

3-3: Import cleanup is correct here.

Mapping is used by the protocol-signature annotation, so removing the inline suppression is safe.


4-4: Path import remains necessary and valid.

The line is used across type annotations in this file, so this cleanup looks good.


12-12: SubprocessSandbox import change is clean.

It is directly used by the typed fixture test, so dropping the suppression comment is appropriate.

tests/unit/engine/test_metrics.py (1)

6-6: Looks good — no issue with removing the suppression comment here.

This import remains valid and the change is non-functional.

tests/unit/api/controllers/test_budget.py (1)

7-10: Import cleanup looks good.

Removing inline lint suppressions on these imports keeps the test module cleaner without changing behavior.

tests/unit/hr/test_onboarding_service.py (1)

8-9: Import cleanup is good here.

This keeps type imports explicit without changing behavior.

tests/unit/budget/test_category_analytics.py (1)

15-15: Import cleanup looks good.

CostTracker is still used in this file’s type annotations, so removing the inline noqa is safe and improves lint hygiene.

tests/unit/hr/test_full_snapshot_strategy.py (1)

12-12: Import cleanup looks good.

Removing # noqa: TC001 on Line 12 is safe and keeps the test file lint-clean without changing behavior.

tests/unit/engine/test_context.py (1)

9-11: LGTM!

The removal of # noqa: TC001 suppressions is correct. These imports (AgentIdentity, Task) are used at runtime in pytest fixture type hints (e.g., sample_agent_with_personality: AgentIdentity), so they legitimately belong outside a TYPE_CHECKING block. The lint suppression was unnecessary.

tests/unit/api/controllers/test_autonomy.py (1)

6-6: LGTM! Lint suppression cleanup is appropriate.

The removal of # noqa: TC002 is correct since TestClient is used at runtime in test function signatures and cannot be moved to a type-checking block. This aligns with the PR's broader cleanup effort to remove unnecessary lint suppressions from test imports.

tests/unit/api/controllers/test_agents.py (1)

31-31: LGTM: removing the inline noqa here is a good cleanup.

AuthService is still referenced (type annotation at Line 45), so this change is clear and safe.

tests/unit/api/controllers/test_tasks.py (1)

6-6: LGTM!

Clean removal of the inline lint suppression comment. The import remains valid and the change aligns with the repository-wide cleanup of noqa annotations mentioned in the PR objectives.

.github/workflows/dependency-review.yml (2)

32-43: LGTM!

The license additions are well-documented with clear explanations. Both LicenseRef-scancode-protobuf and ZPL-2.1 are permissive licenses appropriate for inclusion.


44-51: LGTM — version-pinned allowlist is appropriate.

The purl format and manual license verification are correct. The version pins mean this list will need updating when these dependencies are upgraded (e.g., numpy@2.4.3numpy@2.5.x), but that's the intended secure behavior for packages with missing SPDX metadata.

Consider adding a brief inline comment noting this maintenance requirement so future contributors know to update this block during dependency bumps.

tests/unit/hr/test_hiring_service.py (1)

15-16: LGTM: Correct removal of unnecessary lint suppressions.

Both OnboardingService and AgentRegistryService are used at runtime (constructor arguments and method calls), not just in type annotations, so the # noqa: TC001 suppressions were unnecessary. This cleanup correctly aligns with linting standards.

tests/unit/api/test_middleware.py (1)

6-6: LGTM! Lint cleanup aligns with test-suite standards.

The removal of the # noqa: TC002 suppression is appropriate. TestClient is actively used in type annotations throughout the file (lines 45, 50, 56, 106, 111), and this cleanup aligns with the PR's broader effort to remove unnecessary linting suppressions.

tests/unit/api/test_health.py (1)

6-6: LGTM! Lint suppression cleanup.

Removing the # noqa: TC002 suppression is appropriate as part of the broader linting cleanup mentioned in the PR objectives. No functional impact.

tests/unit/hr/test_offboarding_service.py (1)

8-22: LGTM! Correct removal of unnecessary lint suppressions.

All four imports (Channel, Message, Task, AgentRegistryService) are used at runtime in the test file—not just for type annotations. Removing the # noqa: TC001 suppressions is appropriate and aligns with the PR's lint hygiene cleanup objectives.

tests/unit/providers/conftest.py (1)

3-3: LGTM!

The noqa: TC003 removal is correct. AsyncIterator is used at runtime in the FakeProvider.stream() return type annotation and generator, so the import cannot be moved to a TYPE_CHECKING block.

tests/unit/communication/conflict_resolution/test_service.py (1)

22-24: LGTM!

The noqa: TC001 removal is appropriate. HierarchyResolver is used at runtime in function signatures (e.g., _make_service() parameter and fixture type hints), so the import must remain outside TYPE_CHECKING.

tests/unit/engine/test_routing_models.py (1)

5-5: LGTM!

The noqa: TC001 removal is correct. AgentIdentity is used at runtime in fixture parameter type hints throughout the test class methods.

tests/unit/engine/test_agent_engine.py (1)

12-12: LGTM!

The noqa: TC001 removal is correct. AgentIdentity is used at runtime in fixture parameter type hints throughout multiple test classes.

tests/unit/api/controllers/test_analytics.py (1)

6-6: LGTM!

The noqa: TC002 removal is correct. TestClient is used at runtime in fixture parameter type hints.

docs/roadmap/index.md (1)

11-11: LGTM!

Documentation correctly updated to reflect the Mem0 adapter implementation. The Memory system entry now accurately lists all completed components including the new Mem0 adapter.

tests/unit/engine/test_loop_protocol.py (1)

9-9: LGTM!

The noqa: TC001 removal is correct. AgentContext is used at runtime in fixture parameter type hints throughout the test classes.

tests/unit/api/test_guards.py (1)

6-6: LGTM!

The noqa: TC002 removal is correct. TestClient is used at runtime in fixture parameter type hints and the bare_client fixture return type annotation.

tests/unit/api/auth/test_controller.py (2)

6-6: LGTM!

Lint suppression removal is appropriate. The TestClient import is valid and used throughout the test file.


47-47: LGTM!

Lint suppression removal is appropriate. The AuthService import is correctly used within the test method scope.

tests/unit/api/controllers/test_artifacts.py (1)

6-6: LGTM!

Lint suppression cleanup. The TestClient import is properly used for type annotations.

tests/unit/communication/meeting/test_position_papers.py (1)

13-13: LGTM!

Lint suppression cleanup. The MeetingAgenda import is used for type hints in fixture parameters throughout the test class.

tests/unit/communication/conflict_resolution/test_debate_strategy.py (1)

14-16: LGTM!

Lint suppression cleanup. The HierarchyResolver import is used for type hints in test method fixture parameters.

tests/unit/communication/meeting/test_structured_phases.py (1)

13-13: LGTM!

Lint suppression cleanup. The MeetingAgenda import is properly used for type annotations in fixture parameters.

tests/unit/api/controllers/test_company.py (1)

6-6: LGTM!

Lint suppression cleanup. The TestClient import is used for type annotations in test method signatures.

tests/unit/communication/conflict_resolution/test_hybrid_strategy.py (1)

17-19: LGTM!

Lint suppression cleanup. The HierarchyResolver import is used for type annotations in fixture parameters throughout the test classes.

tests/integration/tools/test_sandbox_integration.py (1)

4-4: LGTM!

Lint suppression cleanup. The Path import is used both for type annotations and runtime operations throughout the test file.

tests/unit/engine/task_engine_helpers.py (1)

6-6: Import cleanup is safe.

Line 6 only removes an inline suppression; behavior is unchanged and the import remains explicit.

tests/unit/tools/sandbox/conftest.py (1)

3-3: LGTM: non-functional lint cleanup.

Line 3 is an import-only cleanup with no behavioral change in fixture setup.

tests/integration/communication/test_meeting_integration.py (1)

29-30: Import cleanup looks good.

Lines 29–30 keep the same symbols and only remove lint suppression noise.

tests/unit/communication/meeting/test_round_robin.py (1)

13-13: Safe import-only change.

Line 13 is a lint-suppression removal with no effect on protocol test behavior.

tests/unit/api/controllers/test_meetings.py (1)

6-6: LGTM on lint suppression removal.

Line 6 preserves the same TestClient import and does not alter test execution.

tests/unit/communication/meeting/test_orchestrator.py (1)

31-31: No concerns with this import cleanup.

Line 31 removes suppression only; protocol typing import remains unchanged.

tests/unit/communication/conflict_resolution/test_authority_strategy.py (1)

12-12: Import cleanup is fine.

Line 12 keeps HierarchyResolver usage intact and only drops inline suppression.

src/ai_company/memory/models.py (1)

165-165: Good clarification of since boundary semantics.

Lines 165 and 197 make the lower bound explicitly inclusive, improving API clarity without changing behavior.

Also applies to: 197-197

tests/unit/api/controllers/test_projects.py (1)

6-6: Import cleanup is good and non-functional.

This keeps the test file cleaner without changing behavior.

tests/unit/engine/test_agent_engine_lifecycle.py (1)

9-11: Looks good — import-only cleanup with no behavior change.

tests/unit/communication/meeting/test_protocol.py (1)

6-6: Good cleanup on the import statement.

No correctness or maintainability concerns here.

tests/unit/engine/test_react_loop.py (1)

8-8: Import change is clean and safe.

tests/unit/engine/test_task_engine_mutations.py (1)

8-8: No issues — import-only cleanup is fine.

tests/integration/tools/conftest.py (1)

5-5: Looks good.

Pure import cleanup with no runtime impact.

tests/unit/communication/conflict_resolution/test_helpers.py (1)

12-12: Import formatting cleanup is fine.

pyproject.toml (1)

24-24: Configuration updates are coherent for Mem0 integration.

Pinned dependency, Ruff adjustment, and mypy override align with this backend addition.

Also applies to: 138-138, 189-191

Comment on lines +501 to +509
if query.text is not None:
kwargs = query_to_mem0_search_args(str(agent_id), query)
raw_result = await asyncio.to_thread(client.search, **kwargs)
else:
kwargs = query_to_mem0_getall_args(str(agent_id), query)
raw_result = await asyncio.to_thread(client.get_all, **kwargs)
raw_list = _validate_mem0_result(raw_result, context="retrieve")
entries = tuple(mem0_result_to_entry(item, agent_id) for item in raw_list)
entries = apply_post_filters(entries, query)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fetch more than query.limit before applying client-side filters.

query.limit is the caller-visible limit after category/tag/time/relevance/exclude filtering, but both methods hand that limit to Mem0 first and only then run apply_post_filters() / exclude_agent locally. If the first N raw hits are filtered out, you'll return too few results even though later hits match. Please paginate or over-fetch until you have query.limit filtered entries, then slice, and add a regression test where the first page is entirely filtered away.

Also applies to: 910-940

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

In `@src/ai_company/memory/backends/mem0/adapter.py` around lines 501 - 509, The
current retrieval passes query.limit into Mem0 (via query_to_mem0_search_args /
query_to_mem0_getall_args) then applies client-side filters (apply_post_filters
/ exclude_agent), which can yield fewer results if early pages are all filtered;
change the logic in the retrieval flow (the block that calls client.search /
client.get_all, _validate_mem0_result, mem0_result_to_entry, and
apply_post_filters) to page/over-fetch: repeatedly call client.search or
client.get_all with an offset/pagination token and accumulate validated entries,
converting with mem0_result_to_entry and applying apply_post_filters and
exclude_agent as you accumulate until you have at least query.limit
post-filtered entries or the backend is exhausted, then slice to query.limit
before returning; add a regression test that simulates the first page being
entirely filtered out so the caller still receives query.limit results.

Comment on lines +132 to +183
def build_config_from_company_config(
config: CompanyMemoryConfig,
*,
embedder: Mem0EmbedderConfig,
) -> Mem0BackendConfig:
"""Derive a ``Mem0BackendConfig`` from the top-level memory config.

Args:
config: Company-wide memory configuration.
embedder: Embedder settings (provider and model must be
supplied explicitly to avoid vendor names in defaults).

Returns:
Mem0-specific backend configuration.

Raises:
ValueError: If the storage config specifies a vector or
history store that the Mem0 backend does not support,
or if ``data_dir`` contains parent-directory traversal
(``..``) — propagated from ``Mem0BackendConfig``
validation.
"""
if config.storage.vector_store != "qdrant":
msg = (
f"Mem0 backend only supports embedded qdrant vector store, "
f"got {config.storage.vector_store!r}"
)
logger.warning(
MEMORY_BACKEND_CONFIG_INVALID,
backend="mem0",
field="vector_store",
value=config.storage.vector_store,
reason=msg,
)
raise ValueError(msg)
if config.storage.history_store != "sqlite":
msg = (
f"Mem0 backend only supports sqlite history store, "
f"got {config.storage.history_store!r}"
)
logger.warning(
MEMORY_BACKEND_CONFIG_INVALID,
backend="mem0",
field="history_store",
value=config.storage.history_store,
reason=msg,
)
raise ValueError(msg)
return Mem0BackendConfig(
data_dir=config.storage.data_dir,
embedder=embedder,
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Namespace Mem0 storage by company before building the backend.

build_config_from_company_config() passes storage.data_dir straight through and leaves collection_name at the shared "synthorg_memories" default. With the default MemoryStorageConfig.data_dir="/data/memory", multiple company backends on the same host/volume will point at the same Mem0 store, and src/ai_company/memory/backends/mem0/adapter.py keys records only by agent_id / _SHARED_NAMESPACE. That means overlapping agent IDs can leak both private and shared memories across companies. Please make the Mem0 namespace company-scoped here (collection, data_dir, or user_id prefix) or fail fast until one is provided.

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

In `@src/ai_company/memory/backends/mem0/config.py` around lines 132 - 183,
build_config_from_company_config currently passes MemoryStorageConfig.data_dir
and leaves collection_name defaulted, causing multiple companies to share the
same Mem0 storage; update build_config_from_company_config to namespace Mem0 by
company (e.g., append or prefix a stable company identifier from config such as
config.company_id or config.organization to data_dir or to collection_name when
constructing Mem0BackendConfig) so each company gets a unique collection/path,
and if no company identifier is available, raise ValueError to fail fast; ensure
you reference Mem0BackendConfig (where data_dir/collection_name are set) and
consider adapter.py usages that key by agent_id/_SHARED_NAMESPACE so the
namespace change isolates records per company.

Comment on lines +346 to +394
def query_to_mem0_search_args(
agent_id: str,
query: MemoryQuery,
) -> dict[str, Any]:
"""Convert a ``MemoryQuery`` to ``Memory.search()`` kwargs.

Args:
agent_id: Owning agent identifier.
query: Retrieval query.

Returns:
Dict of kwargs for ``Memory.search()``.

Raises:
ValueError: If ``query.text`` is ``None`` (search requires text).
"""
if query.text is None:
msg = "search requires query.text to be set"
logger.warning(
MEMORY_MODEL_INVALID,
field="query.text",
raw_value=None,
reason=msg,
)
raise ValueError(msg)
return {
"query": query.text,
"user_id": agent_id,
"limit": query.limit,
}


def query_to_mem0_getall_args(
agent_id: str,
query: MemoryQuery,
) -> dict[str, Any]:
"""Convert a ``MemoryQuery`` to ``Memory.get_all()`` kwargs.

Args:
agent_id: Owning agent identifier.
query: Retrieval query.

Returns:
Dict of kwargs for ``Memory.get_all()``.
"""
return {
"user_id": agent_id,
"limit": query.limit,
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Keep public agent identifiers typed as NotBlankStr.

query_to_mem0_search_args(), query_to_mem0_getall_args(), and extract_publisher() expose agent IDs as plain str. Using NotBlankStr/NotBlankStr | None here keeps the Mem0 boundary consistent with the rest of the memory layer and removes the ad hoc whitespace normalization.

Proposed fix
 def query_to_mem0_search_args(
-    agent_id: str,
+    agent_id: NotBlankStr,
     query: MemoryQuery,
 ) -> dict[str, Any]:
@@
 def query_to_mem0_getall_args(
-    agent_id: str,
+    agent_id: NotBlankStr,
     query: MemoryQuery,
 ) -> dict[str, Any]:
@@
-def extract_publisher(raw: dict[str, Any]) -> str | None:
+def extract_publisher(raw: dict[str, Any]) -> NotBlankStr | None:
@@
-    return coerced or None
+    return NotBlankStr(coerced) if coerced else None
As per coding guidelines, "Use `NotBlankStr` (from `core.types`) for all identifier/name fields—including optional and tuple variants—instead of manual whitespace validators."

Also applies to: 513-526

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

In `@src/ai_company/memory/backends/mem0/mappers.py` around lines 346 - 394, The
agent_id parameters in query_to_mem0_search_args and query_to_mem0_getall_args
(and similarly in extract_publisher) should use the NotBlankStr type from
core.types instead of plain str; update the function signatures to accept
NotBlankStr (or NotBlankStr | None for optional cases), import NotBlankStr from
core.types, and ensure the returned dict values (user_id or publisher) preserve
the NotBlankStr type (no extra whitespace normalization logic). Also apply the
same change to the other affected functions around the region mentioned (the
functions at ~513-526) so all public agent/identifier parameters use NotBlankStr
consistently.

Comment on lines +371 to +375
return {
"query": query.text,
"user_id": agent_id,
"limit": query.limit,
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don't apply the final limit before post-filtering.

query.limit is sent to Mem0 first, then apply_post_filters() drops expired/category/tag/date/min_relevance misses. That under-fills results whenever qualifying entries exist beyond the first raw limit hits. Fetch a larger candidate window or paginate, then slice to query.limit only after local filtering.

Also applies to: 391-394, 397-439

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

In `@src/ai_company/memory/backends/mem0/mappers.py` around lines 371 - 375, The
mapper currently sends query.limit to Mem0 before local post-filtering, which
causes under-filled results; update the payloads returned by the mapping
functions that build Mem0 requests (the dicts around the return at lines ~371
and the similar blocks at ~391-394 and ~397-439) to request a larger candidate
window or enable pagination instead of using query.limit directly (for example:
page_size = max(query.limit * N, query.limit + M) or fetch pages until enough
candidates are retrieved), then run apply_post_filters() and only slice the
final results to query.limit locally; ensure the change is applied wherever the
function returns {"query": ..., "user_id": ..., "limit": ...} so post-filtering
can produce a fully-filled result set.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This is an impressive and comprehensive pull request that implements the Mem0 memory backend. The changes are well-structured, covering configuration, the adapter implementation, data mapping, and a factory function. The code demonstrates strong design principles, including clear protocol adherence, robust error handling, and important security considerations like ownership verification and path traversal prevention. The test suite is extensive and thorough, providing confidence in the implementation. I've identified one critical syntax issue related to exception handling that needs to be addressed, but otherwise, this is an excellent contribution.

Comment on lines +253 to +254
except builtins.MemoryError, RecursionError:
raise
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

critical

The syntax for catching multiple exceptions is incorrect for Python 3. Using a comma-separated list of exceptions is a Python 2 feature. In Python 3, the exceptions must be enclosed in a tuple. This will cause a SyntaxError at runtime.

This issue is present in multiple locations throughout this file (e.g., lines 305, 456, 518, 601, 701, 778, 859, 950, 1054). Please correct all occurrences.

            except (builtins.MemoryError, RecursionError):

Comment on lines +78 to +79
except ValueError, TypeError:
logger.warning(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

critical

The syntax for catching multiple exceptions is incorrect for Python 3. Using a comma-separated list of exceptions is a Python 2 feature. In Python 3, the exceptions must be enclosed in a tuple. This will cause a SyntaxError at runtime.

This issue is also present in other functions within this file (normalize_relevance_score and _coerce_confidence). Please correct all occurrences.

    except (ValueError, TypeError):

…rror guards, docs

- Extract SharedKnowledgeStore methods from adapter.py to shared.py (797 < 800 line limit)
- Move validation helpers (validate_mem0_result, resolve_publisher, check_delete_ownership) to mappers.py
- Rename _SHARED_NAMESPACE to SHARED_NAMESPACE (public constant in mappers)
- Add MemoryError/RecursionError guards with logger.exception() in adapter, shared, factory
- Add MEMORY_BACKEND_SYSTEM_ERROR event constant
- Add Windows path rejection (backslashes, drive letters) to config validator
- Update CLAUDE.md event exemplar list
- Update docs/design/memory.md config comments (hardcoded stores)
- Update all test imports for renamed/moved symbols
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 13, 2026 11:57 — with GitHub Actions Inactive
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (4)
src/ai_company/memory/backends/mem0/config.py (1)

69-72: ⚠️ Potential issue | 🔴 Critical

Namespace the Mem0 store per company.

build_config_from_company_config() still forwards the shared data_dir and leaves collection_name at the global "synthorg_memories" default. The adapter writes private records under user_id=str(agent_id) and shared records under SHARED_NAMESPACE, so two companies on the same volume will read and overwrite each other's memories whenever agent IDs overlap. Derive a company-scoped path/collection here, or fail fast until a stable company identifier is available.

Also applies to: 199-202

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

In `@src/ai_company/memory/backends/mem0/config.py` around lines 69 - 72, The Mem0
config uses a global collection_name ("synthorg_memories") and shared data_dir
causing cross-company collisions; update build_config_from_company_config() and
the Mem0 config Field for collection_name to derive a company-scoped
collection/path (e.g., include the company_id or company_slug) or raise an
explicit error if no stable company identifier is available; ensure the adapter
behavior that writes private records under user_id=str(agent_id) and shared
records under SHARED_NAMESPACE remains compatible by namespacing collection_name
(or data_dir) per company so two companies on the same volume cannot
read/overwrite each other's memories.
src/ai_company/memory/backends/mem0/mappers.py (1)

302-366: 🛠️ Refactor suggestion | 🟠 Major

Break mem0_result_to_entry() down a bit more.

Even after extracting _resolve_created_at(), this function is still over the repo's 50-line cap and keeps raw id/content validation, metadata decoding, score normalization, and model construction in one block. Pulling the id/content validation into small helpers would bring it back under the limit and keep the recovery paths easier to test.

As per coding guidelines, "Functions: < 50 lines, files < 800 lines".

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

In `@src/ai_company/memory/backends/mem0/mappers.py` around lines 302 - 366, The
function mem0_result_to_entry is over the 50-line limit and mixes id/content
validation, metadata decoding, score normalization and object construction;
extract the id and content checks into small helpers (e.g.,
_validate_mem0_id(raw) -> NotBlankStr and _validate_mem0_content(raw) ->
NotBlankStr) that perform the logger.warning + MemoryRetrievalError behavior
currently in mem0_result_to_entry, call parse_mem0_metadata and
normalize_relevance_score as before, and then have mem0_result_to_entry simply
call those helpers, parse timestamps via _resolve_created_at/update helpers, and
build the MemoryEntry—this will shrink mem0_result_to_entry under 50 lines and
keep validation/recovery paths testable.
src/ai_company/memory/backends/mem0/shared.py (1)

212-242: ⚠️ Potential issue | 🟠 Major

Don't cap the Mem0 fetch before local filtering.

This asks Mem0 for only query.limit raw hits and then applies apply_post_filters() plus exclude_agent. If the first N shared hits are expired, category-mismatched, tag-mismatched, outside the time window, or excluded, callers get fewer than query.limit results even when later matches exist. Over-fetch/paginate until you have query.limit post-filtered entries, then slice locally, and add a regression test where the first page is fully filtered away.

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

In `@src/ai_company/memory/backends/mem0/shared.py` around lines 212 - 242, The
code currently requests only query.limit raw results from client.search/get_all
and then applies validate_mem0_result -> mem0_result_to_entry ->
apply_post_filters and exclude_agent, which can yield fewer than query.limit
results if early hits are filtered; change the logic around the
client.search/client.get_all call so you page/over-fetch until you have at least
query.limit post-filtered entries (or no more pages), i.e. repeatedly call
client.search/get_all with increasing offsets or next-page tokens for
SHARED_NAMESPACE, run validate_mem0_result + mem0_result_to_entry +
apply_post_filters + exclude_agent on each page, accumulate filtered entries,
stop when accumulated >= query.limit or no more raw results, then slice to
query.limit; adjust the code paths that use validate_mem0_result,
mem0_result_to_entry, apply_post_filters, and the exclude_agent filter
accordingly and add a regression test that simulates a first page whose all
items are filtered out to ensure later pages fill the result set.
src/ai_company/memory/backends/mem0/adapter.py (1)

425-433: ⚠️ Potential issue | 🟠 Major

retrieve() can under-fill results after post-filtering.

query.limit is forwarded to Mem0 before apply_post_filters() runs. If the first N hits are expired or fail the category/tag/date/min_relevance filters, the caller receives fewer than query.limit entries even though later matches exist. Please page/over-fetch until enough filtered entries are collected, then truncate locally, and add a regression test where the first page is filtered away.

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

In `@src/ai_company/memory/backends/mem0/adapter.py` around lines 425 - 433, The
retrieve() implementation forwards query.limit to Mem0 and then applies
apply_post_filters(), causing under-fill when early pages are filtered away;
change retrieve() to page/over-fetch: call query_to_mem0_search_args /
query_to_mem0_getall_args with a per-page size (e.g., min(max_page_size,
query.limit) or a fixed chunk), loop calling client.search or client.get_all via
asyncio.to_thread to fetch additional pages (using the Mem0 paging token/offset
returned in raw_result or incrementing offset), validate each raw_result with
validate_mem0_result, extend the entries by converting with mem0_result_to_entry
and filtering with apply_post_filters until you have >= query.limit filtered
entries or no more pages, then truncate the final entries tuple to query.limit
before returning; also add a regression test that simulates the first page being
entirely filtered out and ensures retrieve() returns up to query.limit entries
by fetching subsequent pages.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/design/memory.md`:
- Line 313: Replace the ASCII three-dot sequence in the prose with a
typographical ellipsis: change the prose instance of "embedder=..." to
"embedder=…" where it appears in the sentence describing the
create_memory_backend(config, *, embedder=...) factory (leave any code blocks or
inline code literals unchanged if they are intended to remain ASCII); ensure
only the prose text is updated and the rest of the sentence remains identical.

In `@src/ai_company/memory/backends/mem0/adapter.py`:
- Around line 107-109: In the constructor validation that checks
max_memories_per_agent (the block that currently raises ValueError when
max_memories_per_agent < 1), log the invalid value at WARNING level before
raising: ensure a module/class logger is available (import logging and get
logger if needed) and call logger.warning with the supplied limit and context
(e.g., "Invalid max_memories_per_agent=%s, must be >=1"), then raise the
ValueError as before; update the constructor (where max_memories_per_agent is
validated) to include this warning emission.

In `@src/ai_company/memory/backends/mem0/mappers.py`:
- Around line 464-478: The current branch logs legitimate post-filtering results
as MEMORY_MODEL_INVALID; change it to use a filter-specific event (e.g.,
MEMORY_FILTER_APPLIED) and lower severity (DEBUG or INFO) instead of
warning/invalid. Update the branch that checks "if pre_count > 0 and post_count
== 0" to call logger.debug or logger.info with event MEMORY_FILTER_APPLIED
(preserving context keys field="post_filter", reason="all entries filtered out
by post-filters", pre_filter_count=pre_count) and leave the existing elif
(pre_count != post_count) as debug but also switch its event to
MEMORY_FILTER_APPLIED so normal filter misses are not treated as model
invalidation.

In `@tests/unit/memory/backends/mem0/test_adapter_shared.py`:
- Around line 81-107: Replace the two duplicate publish passthrough tests
(test_publish_reraises_memory_error and test_publish_reraises_recursion_error)
with a single parametrized test using pytest.mark.parametrize over exception
types (builtins.MemoryError, RecursionError); inside the test set
mock_client.add.side_effect to the parametrized exception and assert await
backend.publish("test-agent-001", make_store_request()) raises that exception
via pytest.raises. Apply the same refactor pattern to the search_shared tests
(replace
test_search_shared_reraises_memory_error/test_search_shared_reraises_recursion_error
to one parametrized test that sets mock_client.search.side_effect and calls
await backend.search_shared(...)) and to the retract tests (combine
test_retract_reraises_memory_error/test_retract_reraises_recursion_error into
one parametrized test that sets mock_client.remove.side_effect and calls await
backend.retract(...)); keep references to mock_client.add/search/remove,
backend.publish/search_shared/retract,
make_store_request()/make_retract_request(), and use pytest.mark.parametrize to
supply the exception classes.

---

Duplicate comments:
In `@src/ai_company/memory/backends/mem0/adapter.py`:
- Around line 425-433: The retrieve() implementation forwards query.limit to
Mem0 and then applies apply_post_filters(), causing under-fill when early pages
are filtered away; change retrieve() to page/over-fetch: call
query_to_mem0_search_args / query_to_mem0_getall_args with a per-page size
(e.g., min(max_page_size, query.limit) or a fixed chunk), loop calling
client.search or client.get_all via asyncio.to_thread to fetch additional pages
(using the Mem0 paging token/offset returned in raw_result or incrementing
offset), validate each raw_result with validate_mem0_result, extend the entries
by converting with mem0_result_to_entry and filtering with apply_post_filters
until you have >= query.limit filtered entries or no more pages, then truncate
the final entries tuple to query.limit before returning; also add a regression
test that simulates the first page being entirely filtered out and ensures
retrieve() returns up to query.limit entries by fetching subsequent pages.

In `@src/ai_company/memory/backends/mem0/config.py`:
- Around line 69-72: The Mem0 config uses a global collection_name
("synthorg_memories") and shared data_dir causing cross-company collisions;
update build_config_from_company_config() and the Mem0 config Field for
collection_name to derive a company-scoped collection/path (e.g., include the
company_id or company_slug) or raise an explicit error if no stable company
identifier is available; ensure the adapter behavior that writes private records
under user_id=str(agent_id) and shared records under SHARED_NAMESPACE remains
compatible by namespacing collection_name (or data_dir) per company so two
companies on the same volume cannot read/overwrite each other's memories.

In `@src/ai_company/memory/backends/mem0/mappers.py`:
- Around line 302-366: The function mem0_result_to_entry is over the 50-line
limit and mixes id/content validation, metadata decoding, score normalization
and object construction; extract the id and content checks into small helpers
(e.g., _validate_mem0_id(raw) -> NotBlankStr and _validate_mem0_content(raw) ->
NotBlankStr) that perform the logger.warning + MemoryRetrievalError behavior
currently in mem0_result_to_entry, call parse_mem0_metadata and
normalize_relevance_score as before, and then have mem0_result_to_entry simply
call those helpers, parse timestamps via _resolve_created_at/update helpers, and
build the MemoryEntry—this will shrink mem0_result_to_entry under 50 lines and
keep validation/recovery paths testable.

In `@src/ai_company/memory/backends/mem0/shared.py`:
- Around line 212-242: The code currently requests only query.limit raw results
from client.search/get_all and then applies validate_mem0_result ->
mem0_result_to_entry -> apply_post_filters and exclude_agent, which can yield
fewer than query.limit results if early hits are filtered; change the logic
around the client.search/client.get_all call so you page/over-fetch until you
have at least query.limit post-filtered entries (or no more pages), i.e.
repeatedly call client.search/get_all with increasing offsets or next-page
tokens for SHARED_NAMESPACE, run validate_mem0_result + mem0_result_to_entry +
apply_post_filters + exclude_agent on each page, accumulate filtered entries,
stop when accumulated >= query.limit or no more raw results, then slice to
query.limit; adjust the code paths that use validate_mem0_result,
mem0_result_to_entry, apply_post_filters, and the exclude_agent filter
accordingly and add a regression test that simulates a first page whose all
items are filtered out to ensure later pages fill the result set.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 319031a5-a41f-4056-b1c1-0038fcf36921

📥 Commits

Reviewing files that changed from the base of the PR and between fc9fcb7 and 155d263.

📒 Files selected for processing (11)
  • CLAUDE.md
  • docs/design/memory.md
  • src/ai_company/memory/backends/mem0/adapter.py
  • src/ai_company/memory/backends/mem0/config.py
  • src/ai_company/memory/backends/mem0/mappers.py
  • src/ai_company/memory/backends/mem0/shared.py
  • src/ai_company/memory/factory.py
  • src/ai_company/observability/events/memory.py
  • tests/integration/memory/test_mem0_backend.py
  • tests/unit/memory/backends/mem0/test_adapter_crud.py
  • tests/unit/memory/backends/mem0/test_adapter_shared.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Greptile Review
  • GitHub Check: Test (Python 3.14)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Do NOT use from __future__ import annotations — Python 3.14 has PEP 649 native lazy annotations
Use except A, B: (no parentheses) for exception handling syntax per PEP 758 — ruff enforces this on Python 3.14

Files:

  • src/ai_company/memory/backends/mem0/config.py
  • tests/unit/memory/backends/mem0/test_adapter_crud.py
  • src/ai_company/memory/factory.py
  • src/ai_company/memory/backends/mem0/shared.py
  • src/ai_company/observability/events/memory.py
  • tests/integration/memory/test_mem0_backend.py
  • src/ai_company/memory/backends/mem0/adapter.py
  • tests/unit/memory/backends/mem0/test_adapter_shared.py
  • src/ai_company/memory/backends/mem0/mappers.py
src/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.py: Type hints: all public functions must have type hints, mypy strict mode
Docstrings: Google style, required on public classes/functions (enforced by ruff D rules)
Create new objects instead of mutating existing ones—never mutate existing objects. For non-Pydantic internal collections (registries, BaseTool), use copy.deepcopy() at construction + MappingProxyType wrapping for read-only enforcement.
For dict/list fields in frozen Pydantic models, rely on frozen=True for field reassignment prevention and use copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, serializing for persistence)
Config vs runtime state: use frozen Pydantic models for config/identity; use separate mutable-via-copy models (using model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Use Pydantic v2 (BaseModel, model_validator, computed_field, ConfigDict). Use @computed_field for derived values instead of storing + validating redundant fields. Use NotBlankStr (from core.types) for all identifier/name fields—including optional and tuple variants—instead of manual whitespace validators.
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code (e.g. multiple tool invocations, parallel agent calls). Prefer structured concurrency over bare create_task.
Line length: 88 characters (enforced by ruff)
Functions: < 50 lines, files < 800 lines
Handle errors explicitly, never silently swallow them
Validate at system boundaries (user input, external APIs, config files)
Every module with business logic MUST have: from ai_company.observability import get_logger then logger = get_logger(__name__)
Never use import logging / logging.getLogger() / print() in application code
Always use logger as the variable name (not _logger, not log)
Use event name constants from ai_company.observability.events domain-spe...

Files:

  • src/ai_company/memory/backends/mem0/config.py
  • src/ai_company/memory/factory.py
  • src/ai_company/memory/backends/mem0/shared.py
  • src/ai_company/observability/events/memory.py
  • src/ai_company/memory/backends/mem0/adapter.py
  • src/ai_company/memory/backends/mem0/mappers.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.e2e, @pytest.mark.slow for test markers
Prefer @pytest.mark.parametrize for testing similar cases

Files:

  • tests/unit/memory/backends/mem0/test_adapter_crud.py
  • tests/integration/memory/test_mem0_backend.py
  • tests/unit/memory/backends/mem0/test_adapter_shared.py
docs/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Docs source: docs/ (Markdown, built with Zensical). Design spec: docs/design/ (7 pages: index, agents, organization, communication, engine, memory, operations).

Files:

  • docs/design/memory.md
🧠 Learnings (12)
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to src/**/*.py : Validate at system boundaries (user input, external APIs, config files)

Applied to files:

  • src/ai_company/memory/backends/mem0/config.py
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to src/**/*.py : Use event name constants from `ai_company.observability.events` domain-specific modules (e.g. `PROVIDER_CALL_START` from `events.provider`, `BUDGET_RECORD_ADDED` from `events.budget`, etc.) instead of hardcoded string literals

Applied to files:

  • src/ai_company/observability/events/memory.py
  • CLAUDE.md
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to src/**/*.py : All error paths must log at WARNING or ERROR with context before raising

Applied to files:

  • src/ai_company/memory/backends/mem0/adapter.py
  • CLAUDE.md
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to **/*.py : Use `except A, B:` (no parentheses) for exception handling syntax per PEP 758 — ruff enforces this on Python 3.14

Applied to files:

  • src/ai_company/memory/backends/mem0/adapter.py
  • src/ai_company/memory/backends/mem0/mappers.py
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to src/**/*.py : Handle errors explicitly, never silently swallow them

Applied to files:

  • src/ai_company/memory/backends/mem0/adapter.py
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to docs/**/*.md : Docs source: `docs/` (Markdown, built with Zensical). Design spec: `docs/design/` (7 pages: index, agents, organization, communication, engine, memory, operations).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to src/**/*.py : Every module with business logic MUST have: `from ai_company.observability import get_logger` then `logger = get_logger(__name__)`

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to src/**/*.py : Always use structured logging kwargs: `logger.info(EVENT, key=value)` — never `logger.info("msg %s", val)`

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to src/**/*.py : Always use `logger` as the variable name (not `_logger`, not `log`)

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to src/**/*.py : Never use `import logging` / `logging.getLogger()` / `print()` in application code

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to src/**/*.py : All state transitions must log at INFO

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-13T06:54:28.702Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T06:54:28.702Z
Learning: Applies to pyproject.toml : Dependencies: all versions pinned with `==` in `pyproject.toml`. Groups: `test` and `dev` (includes test). Install via `uv sync`.

Applied to files:

  • CLAUDE.md
🧬 Code graph analysis (7)
src/ai_company/memory/backends/mem0/config.py (4)
src/ai_company/memory/config.py (1)
  • CompanyMemoryConfig (139-195)
src/ai_company/observability/_logger.py (1)
  • get_logger (8-28)
tests/integration/memory/test_mem0_backend.py (1)
  • backend (42-51)
tests/unit/memory/backends/mem0/conftest.py (1)
  • backend (41-49)
tests/unit/memory/backends/mem0/test_adapter_crud.py (3)
src/ai_company/memory/backends/mem0/mappers.py (1)
  • validate_mem0_result (564-616)
src/ai_company/memory/errors.py (3)
  • MemoryRetrievalError (25-26)
  • MemoryStoreError (21-22)
  • MemoryError (13-14)
src/ai_company/memory/models.py (1)
  • MemoryQuery (153-230)
src/ai_company/memory/factory.py (2)
src/ai_company/memory/config.py (1)
  • CompanyMemoryConfig (139-195)
src/ai_company/memory/backends/mem0/config.py (2)
  • Mem0EmbedderConfig (23-51)
  • build_config_from_company_config (151-202)
src/ai_company/memory/backends/mem0/shared.py (5)
src/ai_company/memory/backends/mem0/mappers.py (7)
  • apply_post_filters (420-479)
  • build_mem0_metadata (50-69)
  • extract_publisher (635-648)
  • mem0_result_to_entry (302-366)
  • resolve_publisher (619-632)
  • validate_add_result (485-525)
  • validate_mem0_result (564-616)
src/ai_company/memory/errors.py (3)
  • MemoryRetrievalError (25-26)
  • MemoryStoreError (21-22)
  • MemoryError (13-14)
src/ai_company/observability/_logger.py (1)
  • get_logger (8-28)
src/ai_company/memory/backends/mem0/adapter.py (8)
  • Mem0Client (77-84)
  • get (83-83)
  • get (467-556)
  • add (80-80)
  • search (81-81)
  • get_all (82-82)
  • delete (84-84)
  • delete (558-621)
src/ai_company/memory/models.py (3)
  • MemoryEntry (82-150)
  • MemoryQuery (153-230)
  • MemoryStoreRequest (55-79)
tests/integration/memory/test_mem0_backend.py (5)
src/ai_company/memory/backends/mem0/adapter.py (14)
  • Mem0MemoryBackend (90-794)
  • add (80-80)
  • search (81-81)
  • store (335-398)
  • retrieve (400-465)
  • publish (723-743)
  • search_shared (745-769)
  • get (83-83)
  • get (467-556)
  • delete (84-84)
  • delete (558-621)
  • retract (771-794)
  • get_all (82-82)
  • count (623-716)
src/ai_company/memory/backends/mem0/config.py (2)
  • Mem0BackendConfig (54-117)
  • Mem0EmbedderConfig (23-51)
src/ai_company/memory/models.py (2)
  • MemoryQuery (153-230)
  • MemoryStoreRequest (55-79)
src/ai_company/memory/retrieval_config.py (1)
  • MemoryRetrievalConfig (20-132)
src/ai_company/memory/retriever.py (1)
  • ContextInjectionStrategy (97-400)
src/ai_company/memory/backends/mem0/adapter.py (5)
src/ai_company/memory/backends/mem0/config.py (2)
  • Mem0BackendConfig (54-117)
  • build_mem0_config_dict (120-148)
src/ai_company/memory/backends/mem0/mappers.py (9)
  • apply_post_filters (420-479)
  • build_mem0_metadata (50-69)
  • check_delete_ownership (651-697)
  • extract_category (528-561)
  • mem0_result_to_entry (302-366)
  • query_to_mem0_getall_args (401-417)
  • query_to_mem0_search_args (369-398)
  • validate_add_result (485-525)
  • validate_mem0_result (564-616)
src/ai_company/memory/backends/mem0/shared.py (3)
  • publish_shared (114-178)
  • retract_shared (279-343)
  • search_shared_memories (181-276)
src/ai_company/memory/errors.py (4)
  • MemoryConnectionError (17-18)
  • MemoryRetrievalError (25-26)
  • MemoryStoreError (21-22)
  • MemoryError (13-14)
src/ai_company/memory/models.py (3)
  • MemoryEntry (82-150)
  • MemoryQuery (153-230)
  • MemoryStoreRequest (55-79)
src/ai_company/memory/backends/mem0/mappers.py (2)
src/ai_company/core/enums.py (1)
  • MemoryCategory (101-108)
src/ai_company/memory/models.py (4)
  • MemoryEntry (82-150)
  • MemoryMetadata (20-52)
  • MemoryQuery (153-230)
  • MemoryStoreRequest (55-79)
🪛 LanguageTool
docs/design/memory.md

[style] ~313-~313: Consider using the typographical ellipsis character here instead.
Context: ...g). All are frozen Pydantic models. The create_memory_backend(config, *, embedder=...) factory returns an isolated `MemoryBa...

(ELLIPSIS)

CLAUDE.md

[style] ~130-~130: A comma is missing here.
Context: ...nder ai_company.observability.events (e.g. PROVIDER_CALL_START from `events.prov...

(EG_NO_COMMA)

🔇 Additional comments (5)
src/ai_company/memory/backends/mem0/shared.py (1)

155-162: No changes needed—exception syntax is already correct for PEP 758.

All three locations (lines 155, 252, 318) correctly use except (builtins.MemoryError, RecursionError) as exc: with parentheses. Per PEP 758, parentheses are optional only when not using as; they remain required when using as. The current code is compliant.

			> Likely an incorrect or invalid review comment.
src/ai_company/memory/factory.py (1)

82-89: No changes needed. These handlers correctly follow PEP 758: the parenthesized form except (A, B) as exc: is required when using an as clause. PEP 758 allows omitting parentheses only when there is no as target (e.g., except A, B:). The code at lines 82–89 and 105–112 complies with the specification.

			> Likely an incorrect or invalid review comment.
tests/unit/memory/backends/mem0/test_adapter_shared.py (1)

28-447: Strong shared-knowledge coverage.

This suite validates success paths, ownership rules, namespace guards, and exception translation comprehensively for publish/search/retract.

docs/design/memory.md (1)

63-69: Mem0 config constraints are now clearly documented.

The docs now correctly communicate hardcoded Mem0 storage behavior and the embedder requirement in factory usage.

Also applies to: 295-296, 303-315

tests/integration/memory/test_mem0_backend.py (1)

54-289: Integration coverage is solid and objective-aligned.

These tests exercise the Mem0 adapter through the retrieval pipeline and shared-memory lifecycle with meaningful assertions across key public operations.

(storage paths/backends), and `MemoryOptionsConfig` (behaviour tuning). All are frozen
Pydantic models. The `create_memory_backend(config)` factory returns an isolated
`MemoryBackend` instance per company.
Pydantic models. The `create_memory_backend(config, *, embedder=...)` factory returns an
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use typographical ellipsis in prose for consistency.

Replace embedder=... with embedder=… in the sentence text (outside code blocks) to satisfy the style lint hint.

🧰 Tools
🪛 LanguageTool

[style] ~313-~313: Consider using the typographical ellipsis character here instead.
Context: ...g). All are frozen Pydantic models. The create_memory_backend(config, *, embedder=...) factory returns an isolated `MemoryBa...

(ELLIPSIS)

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

In `@docs/design/memory.md` at line 313, Replace the ASCII three-dot sequence in
the prose with a typographical ellipsis: change the prose instance of
"embedder=..." to "embedder=…" where it appears in the sentence describing the
create_memory_backend(config, *, embedder=...) factory (leave any code blocks or
inline code literals unchanged if they are intended to remain ASCII); ensure
only the prose text is updated and the rest of the sentence remains identical.

Comment on lines +464 to +478
if pre_count > 0 and post_count == 0:
logger.warning(
MEMORY_MODEL_INVALID,
field="post_filter",
reason="all entries filtered out by post-filters",
pre_filter_count=pre_count,
)
elif pre_count != post_count:
logger.debug(
MEMORY_MODEL_INVALID,
field="post_filter",
pre_filter_count=pre_count,
post_filter_count=post_count,
reason="entries filtered by post-filters",
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Don't log normal filter misses as MEMORY_MODEL_INVALID.

A restrictive category/tag/time query can legitimately filter every entry out, so warning on MEMORY_MODEL_INVALID here makes ordinary searches look like data corruption. This branch should use a filter-specific event such as MEMORY_FILTER_APPLIED and stay at DEBUG/INFO.

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

In `@src/ai_company/memory/backends/mem0/mappers.py` around lines 464 - 478, The
current branch logs legitimate post-filtering results as MEMORY_MODEL_INVALID;
change it to use a filter-specific event (e.g., MEMORY_FILTER_APPLIED) and lower
severity (DEBUG or INFO) instead of warning/invalid. Update the branch that
checks "if pre_count > 0 and post_count == 0" to call logger.debug or
logger.info with event MEMORY_FILTER_APPLIED (preserving context keys
field="post_filter", reason="all entries filtered out by post-filters",
pre_filter_count=pre_count) and leave the existing elif (pre_count !=
post_count) as debug but also switch its event to MEMORY_FILTER_APPLIED so
normal filter misses are not treated as model invalidation.

Copilot AI review requested due to automatic review settings March 13, 2026 12:15
@Aureliolo Aureliolo merged commit 2788db8 into main Mar 13, 2026
13 of 15 checks passed
@Aureliolo Aureliolo deleted the feat/mem0-adapter branch March 13, 2026 12:16
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 13, 2026 12:16 — with GitHub Actions Inactive
for entry in entries:
if entry.expires_at is not None and entry.expires_at <= now:
continue
if query.categories and entry.category not in query.categories:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Falsy frozenset bypasses category filter entirely

if query.categories evaluates to False for an empty frozenset(), which means a caller who explicitly passes categories=frozenset() (intending to match no categories) will instead receive all entries unfiltered — the opposite of the expected behavior. The equivalent guard for query.since/query.until correctly uses is not None checks; this filter should follow the same pattern.

Suggested change
if query.categories and entry.category not in query.categories:
if query.categories is not None and entry.category not in query.categories:
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/ai_company/memory/backends/mem0/mappers.py
Line: 449

Comment:
**Falsy frozenset bypasses category filter entirely**

`if query.categories` evaluates to `False` for an empty `frozenset()`, which means a caller who explicitly passes `categories=frozenset()` (intending to match no categories) will instead receive **all** entries unfiltered — the opposite of the expected behavior. The equivalent guard for `query.since`/`query.until` correctly uses `is not None` checks; this filter should follow the same pattern.

```suggestion
        if query.categories is not None and entry.category not in query.categories:
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements a concrete MemoryBackend for the memory subsystem by adding a Mem0-based adapter (plus config/mapping/shared-store support) and wiring it into the factory and public exports, along with extensive unit/integration test coverage and dependency/docs updates.

Changes:

  • Added Mem0 backend implementation (adapter.py), shared knowledge store ops (shared.py), and mapping utilities (mappers.py) with Mem0-specific config models (config.py).
  • Updated backend factory + memory exports to support backend="mem0" (and updated observability event constants accordingly).
  • Added/updated comprehensive tests and updated dependencies + documentation to reflect Mem0 as the implemented backend.

Reviewed changes

Copilot reviewed 82 out of 85 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
uv.lock Adds Mem0 and transitive dependencies to the lockfile.
pyproject.toml Pins mem0ai==1.0.5, adds mypy override for mem0.*, adjusts ruff test ignores.
src/ai_company/memory/factory.py Implements config-driven Mem0 backend creation with validation + logging.
src/ai_company/memory/backends/mem0/adapter.py Adds the main Mem0 backend adapter implementing lifecycle + CRUD + shared store delegation.
src/ai_company/memory/backends/mem0/shared.py Implements shared knowledge store operations (publish/search/retract).
src/ai_company/memory/backends/mem0/mappers.py Adds Mem0 <-> domain model mapping + validation + post-filtering helpers.
src/ai_company/memory/backends/mem0/config.py Adds Mem0BackendConfig / Mem0EmbedderConfig and config builders.
src/ai_company/memory/backends/mem0/init.py Exposes Mem0 backend/config objects from the backend package.
src/ai_company/memory/backends/init.py Exposes concrete backends at the memory.backends package level.
src/ai_company/memory/init.py Re-exports Mem0 backend/config from the top-level ai_company.memory API.
src/ai_company/memory/models.py Clarifies since semantics in docstring/field description.
src/ai_company/observability/events/memory.py Updates memory event constants (adds config/system/agent-id events; removes obsolete ones).
tests/unit/memory/test_factory.py Updates factory tests to assert Mem0 backend creation and error wrapping behavior.
tests/unit/memory/test_init.py Updates memory package export tests for new Mem0 exports.
tests/unit/memory/backends/mem0/conftest.py Adds shared fixtures for Mem0 backend unit tests.
tests/unit/memory/backends/mem0/test_adapter.py Adds unit tests for lifecycle, protocol conformance, and connection guards.
tests/unit/memory/backends/mem0/test_adapter_crud.py Adds unit tests for CRUD + count behavior and result validation.
tests/unit/memory/backends/mem0/test_adapter_shared.py Adds unit tests for publish/search_shared/retract ownership behavior.
tests/unit/memory/backends/mem0/test_config.py Adds unit tests for Mem0 config models and config builders.
tests/unit/memory/backends/mem0/test_mappers.py Adds unit tests for mapping and post-filter functions.
tests/integration/memory/test_mem0_backend.py Adds integration-style tests for adapter + retrieval pipeline flow using a mocked client.
tests/unit/observability/test_events.py Updates expected event constants list for memory events.
docs/design/memory.md Updates design doc to reflect Mem0 adapter is implemented and clarifies constraints (qdrant/sqlite + embedder passed programmatically).
docs/roadmap/index.md Updates roadmap to remove “Mem0 adapter” as a remaining item and reflect implementation.
README.md Updates status section to include Mem0 backend adapter as implemented.
CLAUDE.md Updates repo layout/docs and dependency note to include Mem0 adapter/backend.
.github/workflows/dependency-review.yml Adds allowed-license notes and allowlist entries for dependencies missing SPDX metadata in lockfile.
tests/unit/tools/sandbox/test_protocol.py Removes noqa: TC* markers after test lint config change.
tests/unit/tools/sandbox/conftest.py Removes noqa: TC* markers after test lint config change.
tests/unit/tools/git/test_git_sandbox_integration.py Removes noqa: TC* markers after test lint config change.
tests/unit/tools/git/conftest.py Removes noqa: TC* markers after test lint config change.
tests/unit/providers/test_protocol.py Removes noqa: TC* markers after test lint config change.
tests/unit/providers/conftest.py Removes noqa: TC* markers after test lint config change.
tests/unit/hr/test_registry.py Removes noqa: TC* markers after test lint config change.
tests/unit/hr/test_onboarding_service.py Removes noqa: TC* markers after test lint config change.
tests/unit/hr/test_offboarding_service.py Removes noqa: TC* markers after test lint config change.
tests/unit/hr/test_hiring_service.py Removes noqa: TC* markers after test lint config change.
tests/unit/hr/test_full_snapshot_strategy.py Removes noqa: TC* markers after test lint config change.
tests/unit/engine/test_task_engine_mutations.py Removes noqa: TC* markers after test lint config change.
tests/unit/engine/test_routing_models.py Removes noqa: TC* markers after test lint config change.
tests/unit/engine/test_react_loop.py Removes noqa: TC* markers after test lint config change.
tests/unit/engine/test_plan_execute_loop.py Removes noqa: TC* markers after test lint config change.
tests/unit/engine/test_metrics.py Removes noqa: TC* markers after test lint config change.
tests/unit/engine/test_loop_protocol.py Removes noqa: TC* markers after test lint config change.
tests/unit/engine/test_context.py Removes noqa: TC* markers after test lint config change.
tests/unit/engine/test_agent_engine_lifecycle.py Removes noqa: TC* markers after test lint config change.
tests/unit/engine/test_agent_engine_errors.py Removes noqa: TC* markers after test lint config change.
tests/unit/engine/test_agent_engine.py Removes noqa: TC* markers after test lint config change.
tests/unit/engine/task_engine_helpers.py Removes noqa: TC* markers after test lint config change.
tests/unit/communication/meeting/test_structured_phases.py Removes noqa: TC* markers after test lint config change.
tests/unit/communication/meeting/test_round_robin.py Removes noqa: TC* markers after test lint config change.
tests/unit/communication/meeting/test_protocol.py Removes noqa: TC* markers after test lint config change.
tests/unit/communication/meeting/test_position_papers.py Removes noqa: TC* markers after test lint config change.
tests/unit/communication/meeting/test_orchestrator.py Removes noqa: TC* markers after test lint config change.
tests/unit/communication/meeting/conftest.py Removes noqa: TC* markers after test lint config change.
tests/unit/communication/conflict_resolution/test_service.py Removes noqa: TC* markers after test lint config change.
tests/unit/communication/conflict_resolution/test_hybrid_strategy.py Removes noqa: TC* markers after test lint config change.
tests/unit/communication/conflict_resolution/test_helpers.py Removes noqa: TC* markers after test lint config change.
tests/unit/communication/conflict_resolution/test_debate_strategy.py Removes noqa: TC* markers after test lint config change.
tests/unit/communication/conflict_resolution/test_authority_strategy.py Removes noqa: TC* markers after test lint config change.
tests/unit/budget/test_category_analytics.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/test_middleware.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/test_health.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/test_guards.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/test_app.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/controllers/test_tasks.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/controllers/test_providers.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/controllers/test_projects.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/controllers/test_messages.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/controllers/test_meetings.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/controllers/test_departments.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/controllers/test_company.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/controllers/test_budget.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/controllers/test_autonomy.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/controllers/test_artifacts.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/controllers/test_approvals.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/controllers/test_analytics.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/controllers/test_agents.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/conftest.py Removes noqa: TC* markers after test lint config change.
tests/unit/api/auth/test_controller.py Removes noqa: TC* markers after test lint config change.
tests/integration/tools/test_sandbox_integration.py Removes noqa: TC* markers after test lint config change.
tests/integration/tools/conftest.py Removes noqa: TC* markers after test lint config change.
tests/integration/communication/test_meeting_integration.py Removes noqa: TC* markers after test lint config change.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +255 to +257
def backend_name(self) -> NotBlankStr:
"""Human-readable backend identifier."""
return NotBlankStr("mem0")
Comment on lines +204 to +209
valid: list[NotBlankStr] = []
for t in raw_tags:
stripped = str(t).strip() if t else ""
if stripped:
valid.append(NotBlankStr(stripped))
else:
Comment on lines +317 to +339
raw_id = raw.get("id")
if raw_id is None or not str(raw_id).strip():
msg = f"Mem0 result has missing or blank 'id': keys={list(raw.keys())}"
logger.warning(
MEMORY_MODEL_INVALID,
field="id",
raw_value=raw_id,
reason=msg,
)
raise MemoryRetrievalError(msg)
memory_id = NotBlankStr(str(raw_id))

raw_content = raw.get("memory") or raw.get("data")
if not raw_content or not str(raw_content).strip():
msg = f"Mem0 result {raw.get('id', '?')} has empty content"
logger.warning(
MEMORY_MODEL_INVALID,
field="content",
raw_value=raw_content,
reason=msg,
)
raise MemoryRetrievalError(msg)
content = NotBlankStr(str(raw_content))
Comment on lines +486 to +526
def validate_add_result(result: Any, *, context: str) -> NotBlankStr:
"""Extract and validate the memory ID from a Mem0 ``add`` result.

Args:
result: Raw result from ``Memory.add()`` (expected dict).
context: Human-readable context for error messages
(e.g. ``"store"`` or ``"shared publish"``).

Returns:
The backend-assigned memory ID.

Raises:
MemoryStoreError: If the result is missing or malformed.
"""
if not isinstance(result, dict):
msg = (
f"Mem0 add returned unexpected type for {context}: {type(result).__name__}"
)
logger.warning(MEMORY_ENTRY_STORE_FAILED, context=context, error=msg)
raise MemoryStoreError(msg)
results_list = result.get("results")
if not isinstance(results_list, list) or not results_list:
msg = f"Mem0 add returned no results for {context}"
logger.warning(MEMORY_ENTRY_STORE_FAILED, context=context, error=msg)
raise MemoryStoreError(msg)
first = results_list[0]
if not isinstance(first, dict):
msg = (
f"Mem0 add result item is not a dict for {context}: {type(first).__name__}"
)
logger.warning(MEMORY_ENTRY_STORE_FAILED, context=context, error=msg)
raise MemoryStoreError(msg)
raw_id = first.get("id")
if raw_id is None or not str(raw_id).strip():
msg = (
f"Mem0 add result has missing or blank 'id' for {context}: "
f"keys={list(first.keys())}"
)
logger.warning(MEMORY_ENTRY_STORE_FAILED, context=context, error=msg)
raise MemoryStoreError(msg)
return NotBlankStr(str(raw_id))
Comment on lines +636 to +649
def extract_publisher(raw: dict[str, Any]) -> NotBlankStr | None:
"""Extract the publisher agent ID from a shared memory dict.

Returns ``None`` if the publisher key is missing, non-dict
metadata, or the value is blank after coercion and stripping.
"""
metadata = raw.get("metadata", {})
if not metadata or not isinstance(metadata, dict):
return None
value = metadata.get(PUBLISHER_KEY)
if value is None:
return None
coerced = str(value).strip()
return NotBlankStr(coerced) if coerced else None
Comment on lines +233 to +235
NotBlankStr(
resolve_publisher(item),
),
Aureliolo added a commit that referenced this pull request Mar 13, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.1.3](v0.1.2...v0.1.3)
(2026-03-13)


### Features

* add Mem0 memory backend adapter
([#345](#345))
([2788db8](2788db8)),
closes [#206](#206)
* centralized single-writer TaskEngine with full CRUD API
([#328](#328))
([9c1a3e1](9c1a3e1))
* incremental AgentEngine → TaskEngine status sync
([#331](#331))
([7a68d34](7a68d34)),
closes [#323](#323)
* web dashboard pages — views, components, tests, and review fixes
([#354](#354))
([b165ec4](b165ec4))
* web dashboard with Vue 3 + PrimeVue + Tailwind CSS
([#347](#347))
([06416b1](06416b1))


### Bug Fixes

* harden coordination pipeline with validators, logging, and fail-fast
([#333](#333))
([2f10d49](2f10d49)),
closes [#205](#205)
* repo-wide security hardening from ZAP, Scorecard, and CodeQL audit
([#357](#357))
([27eb288](27eb288))


### CI/CD

* add pip-audit, hadolint, OSSF Scorecard, ZAP DAST, and pre-push hooks
([#350](#350))
([2802d20](2802d20))
* add workflow_dispatch trigger to PR Preview for Dependabot PRs
([#326](#326))
([4c7b6d9](4c7b6d9))
* bump astral-sh/setup-uv from 7.4.0 to 7.5.0 in the minor-and-patch
group ([#335](#335))
([98dd8ca](98dd8ca))


### Maintenance

* bump the minor-and-patch group across 1 directory with 3 updates
([#352](#352))
([031b1c9](031b1c9))
* **deps:** bump devalue from 5.6.3 to 5.6.4 in /site in the
npm_and_yarn group across 1 directory
([#324](#324))
([9a9c600](9a9c600))
* migrate docs build from MkDocs to Zensical
([#330](#330))
([fa8bf1d](fa8bf1d)),
closes [#329](#329)

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
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.

feat: implement concrete memory backend adapter

2 participants