Skip to content

feat(mongodb): add requested docs and minimal usage example#1127

Open
GanpatJangra wants to merge 9 commits intoVoltAgent:mainfrom
GanpatJangra:docs/mongodb-memory-updates
Open

feat(mongodb): add requested docs and minimal usage example#1127
GanpatJangra wants to merge 9 commits intoVoltAgent:mainfrom
GanpatJangra:docs/mongodb-memory-updates

Conversation

@GanpatJangra
Copy link

@GanpatJangra GanpatJangra commented Mar 3, 2026

Summary

This branch is based on the current head of #1000 and adds the remaining requested documentation updates so it is easier to review and merge as a complete MongoDB memory adapter contribution.

Base branch for this PR:

  • UmeshpJadhav:feat/mongodb-memory-storage from #1000

Additional commit on top of #1000:

  • 548468c6 docs: update MongoDB memory documentation and add new MongoDB adapter page

What was added

  • Added MongoDB to the memory overview provider table
  • Added a dedicated MongoDB memory docs page
  • Added MongoDB to the docs sidebar and memory index page
  • Added a minimal usage example to packages/mongodb/README.md
  • Updated website/static/llms.txt to mention the MongoDB adapter

Files

  • website/docs/agents/memory/overview.md
  • website/docs/agents/memory/mongodb.md
  • website/docs/agents/memory.md
  • website/sidebars.ts
  • packages/mongodb/README.md
  • website/static/llms.txt

Notes

This PR is intended to help complete the remaining requested docs work from #1000:

  • minimal usage example
  • docs update for the memory overview

If preferred, maintainers can also cherry-pick the docs commit from this branch onto #1000.


Summary by cubic

Adds a new MongoDB memory adapter with full implementation, tests, and docs. This enables persistent conversations, steps, workflow state, and working memory on self‑hosted MongoDB or Atlas.

  • New Features

    • New package: @voltagent/mongodb with MongoDBMemoryAdapter.
    • Persists messages, conversations, conversation steps, workflow states, and working memory.
    • Indexed collections and unique constraints for fast, safe queries.
    • Configurable database and collectionPrefix; optional debug logging.
    • Unit and Docker-backed integration tests; build and test configs included.
  • Docs

    • New MongoDB memory guide (agents/memory/mongodb.md) with minimal setup.
    • Added MongoDB to memory provider tables and overview; sidebar updated.
    • Minimal usage example in packages/mongodb/README.md.
    • Updated llms.txt to mention the MongoDB adapter.

Written for commit 548468c. Summary will update on new commits.

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced MongoDB memory storage adapter for persistent storage of conversations, messages, workflow state, and working memory. Supports both self-hosted MongoDB and MongoDB Atlas deployments with configurable collection prefixes and debug logging.
  • Documentation

    • Added comprehensive guides for MongoDB adapter setup, configuration options, and integration examples. Updated memory provider overview with MongoDB storage option.

@changeset-bot
Copy link

changeset-bot bot commented Mar 3, 2026

🦋 Changeset detected

Latest commit: 548468c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@voltagent/mongodb Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 3, 2026

📝 Walkthrough

Walkthrough

This pull request introduces a new MongoDB-based memory storage adapter package (@voltagent/mongodb) for VoltAgent. The package includes the MongoDBMemoryAdapter implementation for persisting conversations, messages, workflow state, and working memory to MongoDB, along with comprehensive unit and integration tests, build configuration, and documentation updates.

Changes

Cohort / File(s) Summary
MongoDB Adapter Implementation
packages/mongodb/src/memory-adapter.ts, packages/mongodb/src/index.ts
Introduces MongoDBMemoryAdapter class implementing StorageAdapter with 30+ methods for managing conversations, messages, workflow state, steps, and working memory. Handles MongoDB connection, index creation, and CRUD operations with pagination and filtering support.
Package Configuration & Build
packages/mongodb/package.json, packages/mongodb/tsconfig.json, packages/mongodb/tsup.config.ts, packages/mongodb/vitest*.mts
Configures the @voltagent/mongodb package with dependencies, exports, build targets (ESM/CJS), TypeScript compilation, and separate Vitest configurations for unit and integration tests.
Testing & Infrastructure
packages/mongodb/src/memory-adapter.spec.ts, packages/mongodb/src/index.integration.test.ts, packages/mongodb/docker-compose.test.yaml
Adds unit tests with mocked MongoDB client, comprehensive integration tests covering 650+ lines of adapter functionality (conversations, messages, workflow state, steps, working memory), and Docker Compose test infrastructure with MongoDB service.
Documentation & Metadata
.changeset/mongodb-feature-storage.md, packages/mongodb/README.md, website/docs/agents/memory*.md, website/sidebars.ts, website/static/llms.txt
Introduces changeset for feature release, package README with usage examples, new MongoDB memory documentation page, and updates to memory overview, sidebar navigation, and LLM reference text.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant Adapter as MongoDBMemoryAdapter
    participant Mongo as MongoDB

    App->>Adapter: new MongoDBMemoryAdapter(options)
    Adapter->>Mongo: connect(uri)
    Adapter->>Mongo: create indexes<br/>(conversations, messages, etc.)
    Adapter-->>App: initialized

    Note over App,Mongo: Typical Usage Flow
    App->>Adapter: createConversation(input)
    Adapter->>Mongo: insert conversation doc
    Mongo-->>Adapter: acknowledgment
    Adapter-->>App: Conversation object

    App->>Adapter: addMessage(message, userId, conversationId)
    Adapter->>Mongo: insert message doc
    Mongo-->>Adapter: acknowledgment
    Adapter-->>App: void

    App->>Adapter: getMessages(userId, conversationId)
    Adapter->>Mongo: query messages<br/>(with filters/pagination)
    Mongo-->>Adapter: message array
    Adapter-->>App: UIMessage[]
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

Possibly related PRs

Poem

🐰 A MongoDB warren, so deep and so wide,
With messages nested where conversations reside,
The adapter hops swiftly through collections with care,
Persisting the memories with storage to spare! 🌿

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding MongoDB documentation and a minimal usage example, which aligns with the PR's primary objectives.
Description check ✅ Passed The description covers the required sections: commit message guidelines reference, related issue linkage (#1000), test and docs additions, and changeset status. It clearly explains what was added and provides context for reviewers.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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

❤️ Share

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

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 18 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/mongodb/src/memory-adapter.ts">

<violation number="1" location="packages/mongodb/src/memory-adapter.ts:87">
P2: Initialization failure is sticky: one transient MongoDB startup failure leaves this adapter permanently unusable because `initPromise` is never reset/retried.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Add one-off context when rerunning by tagging @cubic-dev-ai with guidance or docs links (including llms.txt)
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

this.log("MongoDB Memory adapter initialized");

// Start initialization but don't await it
this.initPromise = this.initialize();
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 3, 2026

Choose a reason for hiding this comment

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

P2: Initialization failure is sticky: one transient MongoDB startup failure leaves this adapter permanently unusable because initPromise is never reset/retried.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/mongodb/src/memory-adapter.ts, line 87:

<comment>Initialization failure is sticky: one transient MongoDB startup failure leaves this adapter permanently unusable because `initPromise` is never reset/retried.</comment>

<file context>
@@ -0,0 +1,1024 @@
+    this.log("MongoDB Memory adapter initialized");
+
+    // Start initialization but don't await it
+    this.initPromise = this.initialize();
+  }
+
</file context>
Fix with Cubic

Copy link
Contributor

@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: 8

🧹 Nitpick comments (2)
packages/mongodb/package.json (1)

51-51: Replace fixed startup sleep with health-based readiness wait.
Line 51 uses a hardcoded delay, which is prone to flaky startup on slower runners.

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

In `@packages/mongodb/package.json` at line 51, The package.json script
"test:integration:setup" currently uses a fixed "sleep 10" which is flaky;
replace that sleep with a health-based readiness wait (either call an existing
wait-for utility or add a small script that polls container health/status) so
the command becomes: bring up compose with "docker compose -f
docker-compose.test.yaml up -d" and then block until the target service(s)
report healthy (poll via "docker compose ps" health status or TCP probe) before
exiting; update the "test:integration:setup" script to invoke that health-wait
mechanism instead of sleep.
packages/mongodb/src/index.integration.test.ts (1)

32-45: Ensure MongoClient is always closed in cleanup path.

If collection cleanup throws, Line 44 is skipped and the client can leak across tests. Wrap cleanup in try/finally.

Suggested change
     const { MongoClient } = await import("mongodb");
     const client = new MongoClient(MONGO_URI);
-    await client.connect();
-    const db = client.db(TEST_DATABASE);
-
-    const collections = await db.listCollections().toArray();
-    for (const collection of collections) {
-      if (collection.name.startsWith("test_memory_")) {
-        await db.collection(collection.name).deleteMany({});
-      }
-    }
-
-    await client.close();
+    try {
+      await client.connect();
+      const db = client.db(TEST_DATABASE);
+
+      const collections = await db.listCollections().toArray();
+      for (const collection of collections) {
+        if (collection.name.startsWith("test_memory_")) {
+          await db.collection(collection.name).deleteMany({});
+        }
+      }
+    } finally {
+      await client.close();
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/mongodb/src/index.integration.test.ts` around lines 32 - 45, The
cleanup loop that lists collections and calls db.collection(...).deleteMany(...)
can throw and currently may skip client.close(), so wrap the collection cleanup
in a try/finally around the MongoClient lifecycle: after creating and connecting
the MongoClient (MongoClient, client.connect(), MONGO_URI, TEST_DATABASE,
db.listCollections()), perform the deletion logic inside a try block and call
client.close() in the finally block to guarantee the client is always closed
even if deleteMany or listCollections throws.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/mongodb/docker-compose.test.yaml`:
- Around line 4-7: The docker-compose test file hardcodes container_name and
host port mapping (container_name: 'voltagent-mongodb-test' and ports: -
'27017:27017'), causing global collisions in concurrent/local CI runs; remove
the fixed container_name and avoid binding the container port to the host by
either deleting the container_name line and changing ports to expose only the
container port (e.g., "27017" or no host mapping) or make the host port
configurable using an env var (e.g., replace '27017:27017' with
"${MONGO_PORT:-27017}:27017" or use project-scoped names like
"${COMPOSE_PROJECT_NAME:-voltagent}-mongodb-test") so tests can run in parallel
without collisions.

In `@packages/mongodb/package.json`:
- Around line 49-53: The integration script currently uses "&&" so
test:integration:teardown only runs on successful tests; change test:integration
to run test:integration:setup, run the vitest command inside a shell that
captures its exit code, always runs npm run test:integration:teardown, then
exits with the original vitest code. Update the "test:integration" script
(referencing test:integration, test:integration:setup, and
test:integration:teardown) to wrap the vitest invocation so teardown always
executes even when tests fail and the process returns the original test exit
status.

In `@packages/mongodb/src/index.integration.test.ts`:
- Around line 26-28: Replace the fixed 1s sleep (the new Promise with
setTimeout) with a deterministic wait for the component to be ready: remove the
setTimeout-based wait and instead await a real readiness check — either call and
await the module's exported initializer (e.g., initializeMongo or connectMongo)
if available, or poll the Mongo client until a successful response (e.g., await
client.connect() or loop until client.db().admin().ping() succeeds) with a short
interval and timeout; update the test that contains the setTimeout promise to
use that deterministic await so the test only proceeds when the DB is actually
initialized.
- Around line 390-404: Tests currently use the unsafe any type for test fixtures
(e.g., the state object and conversation step arrays); import the proper types
from `@voltagent/core` (WorkflowStateEntry and ConversationStepRecord) and
annotate the test variables instead of any (or use the exported parameter types
like Parameters<MongoDBMemoryAdapter["setWorkflowState"]>[1] and
Parameters<MongoDBMemoryAdapter["saveConversationSteps"]>[0][number] if you
prefer). Update the declarations for the state fixture (previously typed as any)
to WorkflowStateEntry and the conversation step fixtures to
ConversationStepRecord, and add the corresponding import statements from
`@voltagent/core` so the integration tests maintain compile-time type safety.

In `@packages/mongodb/src/memory-adapter.spec.ts`:
- Around line 56-58: Remove the unnecessary private method call: delete the
explicit await (adapter as any).initialize() and instead rely on the
constructor-triggered initialization (this.initPromise = this.initialize()) —
either simply assert expect(MongoClient).toHaveBeenCalledTimes(1) after
instantiation, or if you need to wait for completion, await the adapter's
initialization promise (access via adapter.initPromise or
adapter['initPromise']) before asserting; this preserves type safety and avoids
casting to any.

In `@packages/mongodb/src/memory-adapter.ts`:
- Around line 203-207: Ensure we enforce conversation ownership before inserting
messages: after fetching the conversation via
this.getConversation(conversationId) (used in the insert message flow), verify
that conversation.userId === userId and if not, throw a suitable error (e.g.,
ConversationNotFoundError or an AuthorizationError) to prevent cross-user
writes; apply the same ownership check in the other analogous block around the
second getConversation call (the one referenced at 244-248) so both insertion
paths validate userId matches the conversation.userId before proceeding.
- Around line 381-443: The code uses many `any` casts (e.g.,
getCollection<any>("conversations"), insert/find results cast with `as any`,
filter declarations typed `: any`, map callbacks `(item: any)`, and update
result casts) which breaks TypeScript safety; replace these with concrete types
imported from `@voltagent/core` and mongodb: use
getCollection<ConversationRecord>("conversations") (and analogous
ConversationStepRecord, WorkflowStateEntry, etc.), use WithId<T> or Document
where appropriate for query results instead of `as any`, type filter objects as
Partial<ConversationRecord> or the exact filter shape, type map callbacks with
the correct record type, and use mongodb types like UpdateResult<T> for updates;
ensure the necessary types are imported and remove all `any` casts so
insertOne/findOne/countDocuments/updateOne usages and their mappings return
properly typed values (e.g., in createConversation, countConversations,
getConversation, update handlers, and workflow state queries).

In `@website/docs/agents/memory/mongodb.md`:
- Around line 41-57: Update the example to validate the required MONGODB_URI
before constructing MongoDBMemoryAdapter: check process.env.MONGODB_URI (used in
MongoDBMemoryAdapter) and throw or log a clear error if missing, or provide a
brief inline comment noting it is required; ensure the validation happens prior
to new Memory({ storage: new MongoDBMemoryAdapter(...) }) so Agent and Memory
construction use a guaranteed non-null connection string.

---

Nitpick comments:
In `@packages/mongodb/package.json`:
- Line 51: The package.json script "test:integration:setup" currently uses a
fixed "sleep 10" which is flaky; replace that sleep with a health-based
readiness wait (either call an existing wait-for utility or add a small script
that polls container health/status) so the command becomes: bring up compose
with "docker compose -f docker-compose.test.yaml up -d" and then block until the
target service(s) report healthy (poll via "docker compose ps" health status or
TCP probe) before exiting; update the "test:integration:setup" script to invoke
that health-wait mechanism instead of sleep.

In `@packages/mongodb/src/index.integration.test.ts`:
- Around line 32-45: The cleanup loop that lists collections and calls
db.collection(...).deleteMany(...) can throw and currently may skip
client.close(), so wrap the collection cleanup in a try/finally around the
MongoClient lifecycle: after creating and connecting the MongoClient
(MongoClient, client.connect(), MONGO_URI, TEST_DATABASE, db.listCollections()),
perform the deletion logic inside a try block and call client.close() in the
finally block to guarantee the client is always closed even if deleteMany or
listCollections throws.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9751245 and 548468c.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (17)
  • .changeset/mongodb-feature-storage.md
  • packages/mongodb/README.md
  • packages/mongodb/docker-compose.test.yaml
  • packages/mongodb/package.json
  • packages/mongodb/src/index.integration.test.ts
  • packages/mongodb/src/index.ts
  • packages/mongodb/src/memory-adapter.spec.ts
  • packages/mongodb/src/memory-adapter.ts
  • packages/mongodb/tsconfig.json
  • packages/mongodb/tsup.config.ts
  • packages/mongodb/vitest.config.mts
  • packages/mongodb/vitest.integration.config.mts
  • website/docs/agents/memory.md
  • website/docs/agents/memory/mongodb.md
  • website/docs/agents/memory/overview.md
  • website/sidebars.ts
  • website/static/llms.txt

Comment on lines +4 to +7
container_name: 'voltagent-mongodb-test'
ports:
- '27017:27017'
environment:
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid global container/port collisions in test compose setup.
Line 4 and Line 6 hardcode a shared container name and host port, which can break local/CI runs when MongoDB is already bound or jobs run concurrently.

Suggested adjustment
-    container_name: 'voltagent-mongodb-test'
     ports:
-      - '27017:27017'
+      - '${MONGODB_TEST_PORT:-27017}:27017'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
container_name: 'voltagent-mongodb-test'
ports:
- '27017:27017'
environment:
ports:
- '${MONGODB_TEST_PORT:-27017}:27017'
environment:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/mongodb/docker-compose.test.yaml` around lines 4 - 7, The
docker-compose test file hardcodes container_name and host port mapping
(container_name: 'voltagent-mongodb-test' and ports: - '27017:27017'), causing
global collisions in concurrent/local CI runs; remove the fixed container_name
and avoid binding the container port to the host by either deleting the
container_name line and changing ports to expose only the container port (e.g.,
"27017" or no host mapping) or make the host port configurable using an env var
(e.g., replace '27017:27017' with "${MONGO_PORT:-27017}:27017" or use
project-scoped names like "${COMPOSE_PROJECT_NAME:-voltagent}-mongodb-test") so
tests can run in parallel without collisions.

Comment on lines +49 to +53
"test:integration": "npm run test:integration:setup && vitest run --config vitest.integration.config.mts && npm run test:integration:teardown",
"test:integration:ci": "vitest run --config vitest.integration.config.mts",
"test:integration:setup": "docker compose -f docker-compose.test.yaml up -d && sleep 10",
"test:integration:teardown": "docker compose -f docker-compose.test.yaml down -v"
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Ensure integration teardown runs even when tests fail.
Line 49 currently skips teardown on test failure, leaving containers/volumes behind.

Suggested fix
-    "test:integration": "npm run test:integration:setup && vitest run --config vitest.integration.config.mts && npm run test:integration:teardown",
+    "test:integration": "sh -c 'npm run test:integration:setup; code=0; vitest run --config vitest.integration.config.mts || code=$?; npm run test:integration:teardown; exit $code'",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"test:integration": "npm run test:integration:setup && vitest run --config vitest.integration.config.mts && npm run test:integration:teardown",
"test:integration:ci": "vitest run --config vitest.integration.config.mts",
"test:integration:setup": "docker compose -f docker-compose.test.yaml up -d && sleep 10",
"test:integration:teardown": "docker compose -f docker-compose.test.yaml down -v"
},
"test:integration": "sh -c 'npm run test:integration:setup; code=0; vitest run --config vitest.integration.config.mts || code=$?; npm run test:integration:teardown; exit $code'",
"test:integration:ci": "vitest run --config vitest.integration.config.mts",
"test:integration:setup": "docker compose -f docker-compose.test.yaml up -d && sleep 10",
"test:integration:teardown": "docker compose -f docker-compose.test.yaml down -v"
},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/mongodb/package.json` around lines 49 - 53, The integration script
currently uses "&&" so test:integration:teardown only runs on successful tests;
change test:integration to run test:integration:setup, run the vitest command
inside a shell that captures its exit code, always runs npm run
test:integration:teardown, then exits with the original vitest code. Update the
"test:integration" script (referencing test:integration, test:integration:setup,
and test:integration:teardown) to wrap the vitest invocation so teardown always
executes even when tests fail and the process returns the original test exit
status.

Comment on lines +26 to +28
// Wait for initialization
await new Promise((resolve) => setTimeout(resolve, 1000));
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Replace fixed sleep with deterministic initialization.

Line 27 relies on timing (setTimeout(1000)), which makes integration tests flaky under slower CI environments.

Suggested change
-    // Wait for initialization
-    await new Promise((resolve) => setTimeout(resolve, 1000));
+    // Trigger a lightweight call that awaits internal initialization
+    await adapter.getConversation("__init_probe__");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Wait for initialization
await new Promise((resolve) => setTimeout(resolve, 1000));
});
// Trigger a lightweight call that awaits internal initialization
await adapter.getConversation("__init_probe__");
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/mongodb/src/index.integration.test.ts` around lines 26 - 28, Replace
the fixed 1s sleep (the new Promise with setTimeout) with a deterministic wait
for the component to be ready: remove the setTimeout-based wait and instead
await a real readiness check — either call and await the module's exported
initializer (e.g., initializeMongo or connectMongo) if available, or poll the
Mongo client until a successful response (e.g., await client.connect() or loop
until client.db().admin().ping() succeeds) with a short interval and timeout;
update the test that contains the setTimeout promise to use that deterministic
await so the test only proceeds when the DB is actually initialized.

Comment on lines +390 to +404
const state: any = {
id: "exec-1",
workflowId: "workflow-1",
workflowName: "Test Workflow",
status: "running",
suspension: null,
events: [],
output: null,
cancellation: null,
userId: "user-1",
conversationId: "conv-1",
metadata: {},
createdAt: new Date(),
updatedAt: new Date(),
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check if the file exists and get line count
wc -l packages/mongodb/src/index.integration.test.ts

Repository: VoltAgent/voltagent

Length of output: 113


🏁 Script executed:

# Read the specific sections with any usage mentioned
sed -n '385,580p' packages/mongodb/src/index.integration.test.ts

Repository: VoltAgent/voltagent

Length of output: 5641


🏁 Script executed:

# Find the MongoDBMemoryAdapter class definition
fd -t f "\.ts$" packages/mongodb/src | grep -v test | head -20

Repository: VoltAgent/voltagent

Length of output: 175


🏁 Script executed:

# Check the memory-adapter.ts file to see method signatures
wc -l packages/mongodb/src/memory-adapter.ts

Repository: VoltAgent/voltagent

Length of output: 106


🏁 Script executed:

# Search for the method signatures
rg "setWorkflowState|saveConversationSteps" packages/mongodb/src/memory-adapter.ts -A 3 -B 1

Repository: VoltAgent/voltagent

Length of output: 417


🏁 Script executed:

# Check the beginning of the test file to see imports
head -n 50 packages/mongodb/src/index.integration.test.ts

Repository: VoltAgent/voltagent

Length of output: 1612


🏁 Script executed:

# Check what's exported from memory-adapter.ts
rg "export.*WorkflowStateEntry|export.*ConversationStepRecord" packages/mongodb/src/memory-adapter.ts

Repository: VoltAgent/voltagent

Length of output: 45


🏁 Script executed:

# Search for type definitions in the file
rg "type WorkflowStateEntry|interface WorkflowStateEntry|type ConversationStepRecord|interface ConversationStepRecord" packages/mongodb/src/memory-adapter.ts -B 2

Repository: VoltAgent/voltagent

Length of output: 45


🏁 Script executed:

# Check the index.ts file for type exports
cat packages/mongodb/src/index.ts

Repository: VoltAgent/voltagent

Length of output: 181


🏁 Script executed:

# Search for WorkflowStateEntry and ConversationStepRecord types more broadly
rg "WorkflowStateEntry|ConversationStepRecord" packages/mongodb/src/memory-adapter.ts | head -20

Repository: VoltAgent/voltagent

Length of output: 619


🏁 Script executed:

# Check imports in memory-adapter.ts
head -n 30 packages/mongodb/src/memory-adapter.ts | grep -E "^import|^export"

Repository: VoltAgent/voltagent

Length of output: 326


🏁 Script executed:

# Get the first 50 lines to see all imports
sed -n '1,50p' packages/mongodb/src/memory-adapter.ts

Repository: VoltAgent/voltagent

Length of output: 1247


🏁 Script executed:

# Check if the types can be imported from `@voltagent/core`
rg "@voltagent/core" packages/mongodb/src/index.integration.test.ts

Repository: VoltAgent/voltagent

Length of output: 155


🏁 Script executed:

# Check if the types are publicly available from `@voltagent/core`
# Let's look for where they're exported
fd -t f "\.ts$" | xargs grep -l "export.*WorkflowStateEntry\|export.*ConversationStepRecord" | head -5

Repository: VoltAgent/voltagent

Length of output: 123


🏁 Script executed:

# Check what's exported from `@voltagent/core`
rg "export.*WorkflowStateEntry|export.*ConversationStepRecord" packages/core/src/index.ts

Repository: VoltAgent/voltagent

Length of output: 153


🏁 Script executed:

# Check for WorkflowStateEntry export
rg "export.*WorkflowStateEntry" packages/core/src/index.ts

Repository: VoltAgent/voltagent

Length of output: 45


Remove any from integration tests to preserve type safety.

Lines 390, 416, 449, 476, 508, 563, and 573 use any, which defeats compile-time type guarantees in a TypeScript-first codebase. Import WorkflowStateEntry and ConversationStepRecord from @voltagent/core and use them directly instead of relying on type assertions or the any type.

The suggested approach using Parameters<MongoDBMemoryAdapter["setWorkflowState"]>[1] and Parameters<MongoDBMemoryAdapter["saveConversationSteps"]>[0][number] is valid, but the types can be imported directly since they're already exported from @voltagent/core.

Suggested change
-import { ConversationAlreadyExistsError, ConversationNotFoundError } from "@voltagent/core";
+import { ConversationAlreadyExistsError, ConversationNotFoundError, WorkflowStateEntry, ConversationStepRecord } from "@voltagent/core";

-      const state: any = {
+      const state: WorkflowStateEntry = {
         id: "exec-1",
         ...
       };

-      const steps: any[] = [
+      const steps: ConversationStepRecord[] = [
         ...
       ];

-        } as any);
+        } satisfies WorkflowStateEntry);

-        } as any,
+        } satisfies ConversationStepRecord,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/mongodb/src/index.integration.test.ts` around lines 390 - 404, Tests
currently use the unsafe any type for test fixtures (e.g., the state object and
conversation step arrays); import the proper types from `@voltagent/core`
(WorkflowStateEntry and ConversationStepRecord) and annotate the test variables
instead of any (or use the exported parameter types like
Parameters<MongoDBMemoryAdapter["setWorkflowState"]>[1] and
Parameters<MongoDBMemoryAdapter["saveConversationSteps"]>[0][number] if you
prefer). Update the declarations for the state fixture (previously typed as any)
to WorkflowStateEntry and the conversation step fixtures to
ConversationStepRecord, and add the corresponding import statements from
`@voltagent/core` so the integration tests maintain compile-time type safety.

Comment on lines +56 to +58
it("should initialize correctly", async () => {
await (adapter as any).initialize();
expect(MongoClient).toHaveBeenCalledTimes(1);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify unsafe `any` usage and internal initialize access patterns in MongoDB tests.
rg -n --type=ts -C2 '\bas any\b|:\s*any\b' packages/mongodb/src

Repository: VoltAgent/voltagent

Length of output: 20865


🏁 Script executed:

#!/bin/bash
rg -n --type=ts -C2 '\binitialize\s*\(' packages/mongodb/src/memory-adapter.spec.ts packages/mongodb/src/memory-adapter.ts

Repository: VoltAgent/voltagent

Length of output: 1090


🏁 Script executed:

#!/bin/bash
# Get full context of the memory-adapter.spec.ts file around the flagged lines
cat -n packages/mongodb/src/memory-adapter.spec.ts | head -80

Repository: VoltAgent/voltagent

Length of output: 2305


🏁 Script executed:

#!/bin/bash
# Check the memory-adapter.ts implementation
head -100 packages/mongodb/src/memory-adapter.ts

Repository: VoltAgent/voltagent

Length of output: 2595


Remove unnecessary any cast—initialization is triggered automatically in constructor.

Line 57 unnecessarily casts to any to call the private initialize() method. Since the constructor already calls this.initPromise = this.initialize() (line 87 of memory-adapter.ts), the explicit call is redundant. The test can verify initialization simply by checking that MongoClient was called once after adapter instantiation, without bypassing type safety.

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

In `@packages/mongodb/src/memory-adapter.spec.ts` around lines 56 - 58, Remove the
unnecessary private method call: delete the explicit await (adapter as
any).initialize() and instead rely on the constructor-triggered initialization
(this.initPromise = this.initialize()) — either simply assert
expect(MongoClient).toHaveBeenCalledTimes(1) after instantiation, or if you need
to wait for completion, await the adapter's initialization promise (access via
adapter.initPromise or adapter['initPromise']) before asserting; this preserves
type safety and avoids casting to any.

Comment on lines +203 to +207
// Ensure conversation exists
const conversation = await this.getConversation(conversationId);
if (!conversation) {
throw new ConversationNotFoundError(conversationId);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Enforce conversation ownership before inserting messages.
Line 204 and Line 245 only check that the conversation exists. They should also verify conversation.userId === userId to prevent cross-user writes into another user’s conversation ID.

Suggested fix
-    const conversation = await this.getConversation(conversationId);
-    if (!conversation) {
+    const conversation = await this.getConversation(conversationId);
+    if (!conversation || conversation.userId !== userId) {
       throw new ConversationNotFoundError(conversationId);
     }

Also applies to: 244-248

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

In `@packages/mongodb/src/memory-adapter.ts` around lines 203 - 207, Ensure we
enforce conversation ownership before inserting messages: after fetching the
conversation via this.getConversation(conversationId) (used in the insert
message flow), verify that conversation.userId === userId and if not, throw a
suitable error (e.g., ConversationNotFoundError or an AuthorizationError) to
prevent cross-user writes; apply the same ownership check in the other analogous
block around the second getConversation call (the one referenced at 244-248) so
both insertion paths validate userId matches the conversation.userId before
proceeding.

Comment on lines +381 to +443
const conversationsCollection = this.getCollection<any>("conversations");

const now = new Date();
const conversation = {
_id: input.id,
resourceId: input.resourceId,
userId: input.userId,
title: input.title,
metadata: input.metadata || {},
createdAt: now,
updatedAt: now,
};

try {
await conversationsCollection.insertOne(conversation);
} catch (error: any) {
if (error.code === 11000) {
throw new ConversationAlreadyExistsError(input.id);
}
throw error;
}

this.log(`Created conversation ${input.id}`);

return {
id: conversation._id,
resourceId: conversation.resourceId,
userId: conversation.userId,
title: conversation.title,
metadata: conversation.metadata,
createdAt: conversation.createdAt.toISOString(),
updatedAt: conversation.updatedAt.toISOString(),
};
}

/**
* Count conversations based on filters
*/
async countConversations(options: ConversationQueryOptions): Promise<number> {
await this.initPromise;

const conversationsCollection = this.getCollection("conversations");
const filter: any = {};

if (options.userId) {
filter.userId = options.userId;
}

if (options.resourceId) {
filter.resourceId = options.resourceId;
}

return conversationsCollection.countDocuments(filter);
}

/**
* Get a conversation by ID
*/
async getConversation(id: string): Promise<Conversation | null> {
await this.initPromise;

const conversationsCollection = this.getCollection("conversations");
const conversation = await conversationsCollection.findOne({ _id: id } as any);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

rg -nP --type=ts '\bas\s+any\b|:\s*any\b|getCollection<any>' packages/mongodb/src/memory-adapter.ts | head -50

Repository: VoltAgent/voltagent

Length of output: 2767


🏁 Script executed:

wc -l packages/mongodb/src/memory-adapter.ts

Repository: VoltAgent/voltagent

Length of output: 106


🏁 Script executed:

sed -n '381,443p' packages/mongodb/src/memory-adapter.ts

Repository: VoltAgent/voltagent

Length of output: 1767


🏁 Script executed:

sed -n '545,585p' packages/mongodb/src/memory-adapter.ts

Repository: VoltAgent/voltagent

Length of output: 1111


🏁 Script executed:

sed -n '668,702p' packages/mongodb/src/memory-adapter.ts

Repository: VoltAgent/voltagent

Length of output: 1006


🏁 Script executed:

sed -n '839,915p' packages/mongodb/src/memory-adapter.ts

Repository: VoltAgent/voltagent

Length of output: 2174


🏁 Script executed:

rg -nP 'import.*(?:Conversation|Message|Step|WorkflowState|type)' packages/mongodb/src/memory-adapter.ts | head -20

Repository: VoltAgent/voltagent

Length of output: 296


🏁 Script executed:

rg -n 'JSON\.stringify' packages/mongodb/src/memory-adapter.ts

Repository: VoltAgent/voltagent

Length of output: 45


🏁 Script executed:

head -80 packages/mongodb/src/memory-adapter.ts

Repository: VoltAgent/voltagent

Length of output: 2176


🏁 Script executed:

grep -n 'interface\|type' packages/mongodb/src/memory-adapter.ts | head -20

Repository: VoltAgent/voltagent

Length of output: 306


Remove any type usage to preserve type safety across adapter methods.

The file contains 48+ instances of any usage (via getCollection<any>, as any casts, and : any annotations) that undermine compile-time safety, despite proper type definitions being imported from @voltagent/core (Conversation, ConversationStepRecord, WorkflowStateEntry, etc.) and mongodb library. This violates the coding guideline for TypeScript-first codebases.

Affected locations:

  • Line 381: getCollection<any>("conversations")
  • Lines 443, 450-456: Query results and object mapping with as any/(result as any) casts
  • Line 423, 501, 545: Filter objects with : any annotations
  • Lines 468, 472, 684: Map callbacks with (item: any) parameters
  • Lines 566, 578-584: Multiple casts on update results
  • Lines 840, 847-848: Workflow state queries with redundant as any casts

Replace with properly typed generics and mapped types to ensure schema consistency and catch mismatches at compile time.

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

In `@packages/mongodb/src/memory-adapter.ts` around lines 381 - 443, The code uses
many `any` casts (e.g., getCollection<any>("conversations"), insert/find results
cast with `as any`, filter declarations typed `: any`, map callbacks `(item:
any)`, and update result casts) which breaks TypeScript safety; replace these
with concrete types imported from `@voltagent/core` and mongodb: use
getCollection<ConversationRecord>("conversations") (and analogous
ConversationStepRecord, WorkflowStateEntry, etc.), use WithId<T> or Document
where appropriate for query results instead of `as any`, type filter objects as
Partial<ConversationRecord> or the exact filter shape, type map callbacks with
the correct record type, and use mongodb types like UpdateResult<T> for updates;
ensure the necessary types are imported and remove all `any` casts so
insertOne/findOne/countDocuments/updateOne usages and their mappings return
properly typed values (e.g., in createConversation, countConversations,
getConversation, update handlers, and workflow state queries).

Comment on lines +41 to +57
```ts
import { Agent, Memory } from "@voltagent/core";
import { MongoDBMemoryAdapter } from "@voltagent/mongodb";

const memory = new Memory({
storage: new MongoDBMemoryAdapter({
connection: process.env.MONGODB_URI!,
database: process.env.MONGODB_DATABASE ?? "voltagent",
}),
});

const agent = new Agent({
name: "Assistant",
model: "openai/gpt-4o-mini",
memory,
});
```
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Consider adding validation for required environment variable.

The code example uses process.env.MONGODB_URI! with a non-null assertion (line 47), which will silently pass undefined to the adapter if the environment variable isn't set, potentially causing a confusing runtime error. While this keeps the example concise, consider one of these approaches for better user experience:

  1. Add inline validation with a clear error message
  2. Add a comment indicating this variable is required
  3. Demonstrate basic error handling

This would help users understand the requirement upfront rather than encountering cryptic connection errors.

💡 Example with validation
+if (!process.env.MONGODB_URI) {
+  throw new Error("MONGODB_URI environment variable is required");
+}
+
 const memory = new Memory({
   storage: new MongoDBMemoryAdapter({
-    connection: process.env.MONGODB_URI!,
+    connection: process.env.MONGODB_URI,
     database: process.env.MONGODB_DATABASE ?? "voltagent",
   }),
 });

Or at minimum, add a comment:

 const memory = new Memory({
   storage: new MongoDBMemoryAdapter({
+    // MONGODB_URI must be set in environment variables
     connection: process.env.MONGODB_URI!,
     database: process.env.MONGODB_DATABASE ?? "voltagent",
   }),
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/docs/agents/memory/mongodb.md` around lines 41 - 57, Update the
example to validate the required MONGODB_URI before constructing
MongoDBMemoryAdapter: check process.env.MONGODB_URI (used in
MongoDBMemoryAdapter) and throw or log a clear error if missing, or provide a
brief inline comment noting it is required; ensure the validation happens prior
to new Memory({ storage: new MongoDBMemoryAdapter(...) }) so Agent and Memory
construction use a guaranteed non-null connection string.

@GanpatJangra
Copy link
Author

@omeraplak Please can you please take a look and merge it.
Thank you.

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.

2 participants