docs: update memory tool list, CLI usage, and config file reading logic (#4861)
Co-authored-by: Livia Ellen <liviaellen@msn.com>
This commit is contained in:
@@ -4,6 +4,19 @@ description: "Release notes for the OpenClaw plugin and agent harness."
|
|||||||
mode: "wide"
|
mode: "wide"
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<Update label="2026-04-20" description="v1.0.7">
|
||||||
|
|
||||||
|
**New Features:**
|
||||||
|
- **Chat-Based Setup:** Added chat-based Platform setup flow — users can now configure the plugin conversationally instead of editing config files manually
|
||||||
|
- **Installation Docs Rewrite:** Rewrote README and integration docs with chat-first setup, numbered manual steps.
|
||||||
|
|
||||||
|
**Improvements:**
|
||||||
|
- **SDK Upgrade:** Bumped `mem0ai` dependency to 3.0.1 for V3 API compatibility
|
||||||
|
- **Config Cleanup:** Dropped deprecated `orgId`, `projectId`, `enableGraph` config options; updated CLI prompts ([#4734](https://github.com/mem0ai/mem0/pull/4734), [#4764](https://github.com/mem0ai/mem0/pull/4764))
|
||||||
|
- **Noise Filtering:** Expanded noise patterns in memory add tool; handle leading text in JSON extraction
|
||||||
|
|
||||||
|
</Update>
|
||||||
|
|
||||||
<Update label="2026-04-11" description="v1.0.6">
|
<Update label="2026-04-11" description="v1.0.6">
|
||||||
|
|
||||||
**Bug Fixes:**
|
**Bug Fixes:**
|
||||||
|
|||||||
+215
-42
@@ -14,16 +14,37 @@ Add long-term memory to [OpenClaw](https://github.com/openclaw/openclaw) agents
|
|||||||
The plugin provides:
|
The plugin provides:
|
||||||
1. **Auto-Recall** — Before the agent responds, memories matching the current message are injected into context
|
1. **Auto-Recall** — Before the agent responds, memories matching the current message are injected into context
|
||||||
2. **Auto-Capture** — After the agent responds, the exchange is sent to Mem0 which decides what's worth keeping
|
2. **Auto-Capture** — After the agent responds, the exchange is sent to Mem0 which decides what's worth keeping
|
||||||
3. **Agent Tools** — Five tools for explicit memory operations during conversations
|
3. **Agent Tools** — Eight tools for explicit memory operations during conversations
|
||||||
|
|
||||||
Both auto-recall and auto-capture run silently with no manual configuration required.
|
Both auto-recall and auto-capture run silently with no manual configuration required.
|
||||||
|
|
||||||
## Installation
|
## Requirements
|
||||||
|
|
||||||
|
Check your OpenClaw version:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
openclaw plugins install @mem0/openclaw-mem0
|
openclaw --version
|
||||||
|
# OpenClaw 2026.4.15 (041266a)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
| OpenClaw Version | Plugin Support |
|
||||||
|
|------------------|----------------|
|
||||||
|
| `>= 2026.4.15` | Fully supported |
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
The fastest way is to install directly from your OpenClaw chat, no CLI or config editing needed.
|
||||||
|
|
||||||
|
**Copy and paste this into your OpenClaw chat**; Telegram, WhatsApp, default chat, or any channel where your agent lives:
|
||||||
|
|
||||||
|
```
|
||||||
|
Setup Mem0 from mem0.ai/claw-setup
|
||||||
|
```
|
||||||
|
|
||||||
|
OpenClaw installs the plugin, prompts you for your email, and connects your Mem0 account with OTP verification. See [Chat Setup](#option-1-chat-setup-recommended) below for the full walkthrough.
|
||||||
|
|
||||||
|
If you prefer the OpenClaw CLI, or are setting up self-hosted / open-source mode, see [Manual Config](#option-2-manual-config) and [Open-Source Mode](#open-source-mode-self-hosted) below.
|
||||||
|
|
||||||
## Setup and Configuration
|
## Setup and Configuration
|
||||||
|
|
||||||
### Understanding `userId`
|
### Understanding `userId`
|
||||||
@@ -36,37 +57,113 @@ Pick any stable, unique identifier for the user. Common choices:
|
|||||||
- A UUID (e.g. `"550e8400-e29b-41d4-a716-446655440000"`)
|
- A UUID (e.g. `"550e8400-e29b-41d4-a716-446655440000"`)
|
||||||
- A simple username (e.g. `"alice"`)
|
- A simple username (e.g. `"alice"`)
|
||||||
|
|
||||||
All memories are scoped to this `userId` — different values create separate memory namespaces. If you don't set it, it defaults to `"default"`, which means all users share the same memory space.
|
All memories are scoped to this `userId` — different values create separate memory namespaces. If you don't set it, it defaults to your OS username.
|
||||||
|
|
||||||
<Tip>In a multi-user application, set `userId` dynamically per user (e.g. from your auth system) rather than hardcoding a single value.</Tip>
|
<Tip>In a multi-user application, set `userId` dynamically per user (e.g. from your auth system) rather than hardcoding a single value.</Tip>
|
||||||
|
|
||||||
### Platform Mode (Mem0 Cloud)
|
### Platform Mode (Mem0 Cloud)
|
||||||
|
|
||||||
<Note>Get your API key from <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a>.</Note>
|
There are two ways to set up `@mem0/openclaw-mem0` on the Mem0 platform:
|
||||||
|
|
||||||
Add to your `openclaw.json`:
|
- **Chat setup (recommended)** — run the setup inside any OpenClaw chat. No config editing, no API key handling.
|
||||||
|
- **Manual config** — edit `openclaw.json` directly.
|
||||||
|
|
||||||
```json5
|
#### Option 1: Chat Setup (Recommended)
|
||||||
// plugins.entries
|
|
||||||
"openclaw-mem0": {
|
You no longer need manual config editing to get started. Everything happens inside the OpenClaw chat itself.
|
||||||
"enabled": true,
|
|
||||||
"config": {
|
<Steps>
|
||||||
"apiKey": "${MEM0_API_KEY}",
|
<Step title="Send the setup command to your OpenClaw agent">
|
||||||
"userId": "alice" // any unique identifier you choose for this user
|
Open any OpenClaw channel — Telegram, WhatsApp, your default chat, wherever your agent lives. Paste and send this command:
|
||||||
}
|
|
||||||
}
|
```
|
||||||
```
|
Setup Mem0 from mem0.ai/claw-setup
|
||||||
|
```
|
||||||
|
|
||||||
|
OpenClaw responds with a Mem0 setup card and immediately asks:
|
||||||
|
|
||||||
|
> "What's your email address? I'll send you a verification code to connect your Mem0 account."
|
||||||
|
</Step>
|
||||||
|
|
||||||
|
<Step title="Enter your email">
|
||||||
|
Type your email address and send it. Mem0 sends back:
|
||||||
|
|
||||||
|
> "Check your email for a 6-digit code and paste it here."
|
||||||
|
</Step>
|
||||||
|
|
||||||
|
<Step title="Paste the OTP">
|
||||||
|
Copy the 6-digit code from your email inbox and paste it into the chat.
|
||||||
|
|
||||||
|
You'll see the confirmation:
|
||||||
|
|
||||||
|
> "Connected to Mem0."
|
||||||
|
</Step>
|
||||||
|
</Steps>
|
||||||
|
|
||||||
|
That's it. No API key, no config file editing, no environment variables. The plugin is now active and auto-capture and auto-recall are running on every turn.
|
||||||
|
|
||||||
|
<Note>The chat flow uses the same underlying config as manual setup — it writes `apiKey` and `userId` into `openclaw.json` for you. You can still open the file to inspect or override values afterward.</Note>
|
||||||
|
|
||||||
|
#### Option 2: Manual Config
|
||||||
|
|
||||||
|
<Steps>
|
||||||
|
<Step title="Install the plugin via the OpenClaw CLI">
|
||||||
|
```bash
|
||||||
|
openclaw plugins install @mem0/openclaw-mem0
|
||||||
|
```
|
||||||
|
</Step>
|
||||||
|
|
||||||
|
<Step title="Get your API key">
|
||||||
|
Get your API key from <a href="https://app.mem0.ai?utm_source=mem0-docs" rel="nofollow">app.mem0.ai</a>.
|
||||||
|
</Step>
|
||||||
|
|
||||||
|
<Step title="Select the plugin as your memory backend in `openclaw.json`">
|
||||||
|
Add the full config to your `openclaw.json`:
|
||||||
|
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
"plugins": {
|
||||||
|
"slots": {
|
||||||
|
"memory": "openclaw-mem0"
|
||||||
|
},
|
||||||
|
"entries": {
|
||||||
|
"openclaw-mem0": {
|
||||||
|
"enabled": true,
|
||||||
|
"config": {
|
||||||
|
"apiKey": "${MEM0_API_KEY}",
|
||||||
|
"userId": "alice" // any unique identifier you choose for this user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</Step>
|
||||||
|
</Steps>
|
||||||
|
|
||||||
|
<Warning>
|
||||||
|
OpenClaw treats memory plugins as an exclusive slot. Installing the plugin alone does **not** activate it — you must also set `plugins.slots.memory` as shown above.
|
||||||
|
</Warning>
|
||||||
|
|
||||||
### Open-Source Mode (Self-hosted)
|
### Open-Source Mode (Self-hosted)
|
||||||
|
|
||||||
No Mem0 key needed. Requires `OPENAI_API_KEY` for default embeddings/LLM.
|
No Mem0 key needed. Requires `OPENAI_API_KEY` for default embeddings/LLM.
|
||||||
|
|
||||||
```json5
|
```json5
|
||||||
"openclaw-mem0": {
|
{
|
||||||
"enabled": true,
|
"plugins": {
|
||||||
"config": {
|
"slots": {
|
||||||
"mode": "open-source",
|
"memory": "openclaw-mem0"
|
||||||
"userId": "alice" // any unique identifier you choose for this user
|
},
|
||||||
|
"entries": {
|
||||||
|
"openclaw-mem0": {
|
||||||
|
"enabled": true,
|
||||||
|
"config": {
|
||||||
|
"mode": "open-source",
|
||||||
|
"userId": "alice" // any unique identifier you choose for this user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -74,13 +171,25 @@ No Mem0 key needed. Requires `OPENAI_API_KEY` for default embeddings/LLM.
|
|||||||
Sensible defaults work out of the box. To customize the embedder, vector store, or LLM:
|
Sensible defaults work out of the box. To customize the embedder, vector store, or LLM:
|
||||||
|
|
||||||
```json5
|
```json5
|
||||||
"config": {
|
{
|
||||||
"mode": "open-source",
|
"plugins": {
|
||||||
"userId": "your-user-id",
|
"slots": {
|
||||||
"oss": {
|
"memory": "openclaw-mem0"
|
||||||
"embedder": { "provider": "openai", "config": { "model": "text-embedding-3-small" } },
|
},
|
||||||
"vectorStore": { "provider": "qdrant", "config": { "host": "localhost", "port": 6333 } },
|
"entries": {
|
||||||
"llm": { "provider": "openai", "config": { "model": "gpt-4o" } }
|
"openclaw-mem0": {
|
||||||
|
"enabled": true,
|
||||||
|
"config": {
|
||||||
|
"mode": "open-source",
|
||||||
|
"userId": "your-user-id",
|
||||||
|
"oss": {
|
||||||
|
"embedder": { "provider": "openai", "config": { "model": "text-embedding-3-small" } },
|
||||||
|
"vectorStore": { "provider": "qdrant", "config": { "host": "localhost", "port": 6333 } },
|
||||||
|
"llm": { "provider": "openai", "config": { "model": "gpt-4o" } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -93,23 +202,26 @@ Memories are organized into two scopes:
|
|||||||
|
|
||||||
- **Session (short-term)** — Auto-capture stores memories scoped to the current session via Mem0's `run_id` / `runId` parameter. These are contextual to the ongoing conversation.
|
- **Session (short-term)** — Auto-capture stores memories scoped to the current session via Mem0's `run_id` / `runId` parameter. These are contextual to the ongoing conversation.
|
||||||
|
|
||||||
- **User (long-term)** — The agent can explicitly store long-term memories using the `memory_store` tool (with `longTerm: true`, the default). These persist across all sessions for the user.
|
- **User (long-term)** — The agent can explicitly store long-term memories using the `memory_add` tool (with `longTerm: true`, the default). These persist across all sessions for the user.
|
||||||
|
|
||||||
During **auto-recall**, the plugin searches both scopes and presents them separately — long-term memories first, then session memories — so the agent has full context.
|
During **auto-recall**, the plugin searches both scopes and presents them separately — long-term memories first, then session memories — so the agent has full context.
|
||||||
|
|
||||||
## Agent Tools
|
## Agent Tools
|
||||||
|
|
||||||
The agent gets five tools it can call during conversations:
|
The agent gets eight tools it can call during conversations:
|
||||||
|
|
||||||
| Tool | Description |
|
| Tool | Description |
|
||||||
|------|-------------|
|
|------|-------------|
|
||||||
| `memory_search` | Search memories by natural language |
|
| `memory_search` | Search memories by natural language query. Supports `scope`, `categories`, `filters`. |
|
||||||
| `memory_list` | List all stored memories for a user |
|
| `memory_add` | Store facts. Accepts `text` or `facts` array, `category`, `importance`, `metadata`. |
|
||||||
| `memory_store` | Explicitly save a fact |
|
| `memory_get` | Retrieve a single memory by ID |
|
||||||
| `memory_get` | Retrieve a memory by ID |
|
| `memory_list` | List all memories. Filter by `userId`, `agentId`, `scope`. |
|
||||||
| `memory_forget` | Delete by ID or by query |
|
| `memory_update` | Update a memory's text in place. Preserves history. |
|
||||||
|
| `memory_delete` | Delete by `memoryId`, `query` (search-and-delete), or `all: true`. |
|
||||||
|
| `memory_event_list` | List recent background processing events (platform mode only). |
|
||||||
|
| `memory_event_status` | Get status of a specific event by ID (platform mode only). |
|
||||||
|
|
||||||
The `memory_search` and `memory_list` tools accept a `scope` parameter (`"session"`, `"long-term"`, or `"all"`) to control which memories are queried. The `memory_store` tool accepts a `longTerm` boolean (default: `true`) to choose where to store.
|
The `memory_search` and `memory_list` tools accept a `scope` parameter (`"session"`, `"long-term"`, or `"all"`) to control which memories are queried.
|
||||||
|
|
||||||
## CLI Commands
|
## CLI Commands
|
||||||
|
|
||||||
@@ -123,8 +235,9 @@ openclaw mem0 search "what languages does the user know" --scope long-term
|
|||||||
# Search only session/short-term memories
|
# Search only session/short-term memories
|
||||||
openclaw mem0 search "what languages does the user know" --scope session
|
openclaw mem0 search "what languages does the user know" --scope session
|
||||||
|
|
||||||
# View stats
|
# List all memories
|
||||||
openclaw mem0 stats
|
openclaw mem0 list
|
||||||
|
openclaw mem0 list --user-id alice --top-k 20
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
@@ -134,7 +247,7 @@ openclaw mem0 stats
|
|||||||
| Key | Type | Default | Description |
|
| Key | Type | Default | Description |
|
||||||
|-----|------|---------|-------------|
|
|-----|------|---------|-------------|
|
||||||
| `mode` | `"platform"` \| `"open-source"` | `"platform"` | Which backend to use |
|
| `mode` | `"platform"` \| `"open-source"` | `"platform"` | Which backend to use |
|
||||||
| `userId` | `string` | `"default"` | Scope memories per user |
|
| `userId` | `string` | OS username | Scope memories per user |
|
||||||
| `autoRecall` | `boolean` | `true` | Inject memories before each turn |
|
| `autoRecall` | `boolean` | `true` | Inject memories before each turn |
|
||||||
| `autoCapture` | `boolean` | `true` | Store facts after each turn |
|
| `autoCapture` | `boolean` | `true` | Store facts after each turn |
|
||||||
| `topK` | `number` | `5` | Max memories per recall |
|
| `topK` | `number` | `5` | Max memories per recall |
|
||||||
@@ -145,8 +258,6 @@ openclaw mem0 stats
|
|||||||
| Key | Type | Default | Description |
|
| Key | Type | Default | Description |
|
||||||
|-----|------|---------|-------------|
|
|-----|------|---------|-------------|
|
||||||
| `apiKey` | `string` | — | **Required.** Mem0 API key (supports `${MEM0_API_KEY}`) |
|
| `apiKey` | `string` | — | **Required.** Mem0 API key (supports `${MEM0_API_KEY}`) |
|
||||||
| `orgId` | `string` | — | Organization ID |
|
|
||||||
| `projectId` | `string` | — | Project ID |
|
|
||||||
| `customInstructions` | `string` | *(built-in)* | Extraction rules — what to store, how to format |
|
| `customInstructions` | `string` | *(built-in)* | Extraction rules — what to store, how to format |
|
||||||
| `customCategories` | `object` | *(12 defaults)* | Category name → description map for tagging |
|
| `customCategories` | `object` | *(12 defaults)* | Category name → description map for tagging |
|
||||||
|
|
||||||
@@ -162,15 +273,77 @@ openclaw mem0 stats
|
|||||||
| `oss.llm.provider` | `string` | `"openai"` | LLM provider (`"openai"`, `"anthropic"`, `"ollama"`, etc.) |
|
| `oss.llm.provider` | `string` | `"openai"` | LLM provider (`"openai"`, `"anthropic"`, `"ollama"`, etc.) |
|
||||||
| `oss.llm.config` | `object` | — | Provider config: `apiKey`, `model`, `baseURL`, `temperature` |
|
| `oss.llm.config` | `object` | — | Provider config: `apiKey`, `model`, `baseURL`, `temperature` |
|
||||||
| `oss.historyDbPath` | `string` | — | SQLite path for memory edit history |
|
| `oss.historyDbPath` | `string` | — | SQLite path for memory edit history |
|
||||||
|
| `oss.disableHistory` | `boolean` | `false` | Disable memory edit history tracking |
|
||||||
|
|
||||||
Everything inside `oss` is optional — defaults use OpenAI embeddings (`text-embedding-3-small`), in-memory vector store, and OpenAI LLM.
|
Everything inside `oss` is optional — defaults use OpenAI embeddings (`text-embedding-3-small`), in-memory vector store, and OpenAI LLM.
|
||||||
|
|
||||||
|
## Plugin Management
|
||||||
|
|
||||||
|
### Updating the Plugin
|
||||||
|
|
||||||
|
```bash
|
||||||
|
openclaw plugins update @mem0/openclaw-mem0
|
||||||
|
```
|
||||||
|
|
||||||
|
<Note>Use the npm package name (`@mem0/openclaw-mem0`) for plugin management commands, not the plugin ID (`openclaw-mem0`).</Note>
|
||||||
|
|
||||||
|
### Checking Plugin Status
|
||||||
|
|
||||||
|
```bash
|
||||||
|
openclaw plugins list
|
||||||
|
openclaw plugins inspect openclaw-mem0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### "plugins.allow excludes mem0" Error
|
||||||
|
|
||||||
|
If you see an error like:
|
||||||
|
|
||||||
|
```
|
||||||
|
[openclaw] Failed to start CLI: Error: The `openclaw mem0` command is unavailable
|
||||||
|
because `plugins.allow` excludes "mem0". Add "mem0" to `plugins.allow` if you want
|
||||||
|
that bundled plugin CLI surface.
|
||||||
|
```
|
||||||
|
|
||||||
|
Add `mem0` to your `plugins.allow` list in `openclaw.json`:
|
||||||
|
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
"plugins": {
|
||||||
|
"allow": ["mem0"],
|
||||||
|
"slots": {
|
||||||
|
"memory": "openclaw-mem0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Plugin Not Activating
|
||||||
|
|
||||||
|
If the plugin installs but doesn't work:
|
||||||
|
|
||||||
|
1. Verify `plugins.slots.memory` is set to `"openclaw-mem0"` (not the npm package name)
|
||||||
|
2. Check `openclaw plugins list --enabled` to confirm the plugin is loaded
|
||||||
|
3. Run `openclaw mem0 status` to verify configuration
|
||||||
|
|
||||||
|
### Plugin Update Not Working
|
||||||
|
|
||||||
|
If `openclaw plugins update` fails:
|
||||||
|
|
||||||
|
1. Use the full npm package name: `openclaw plugins update @mem0/openclaw-mem0`
|
||||||
|
2. If that fails, uninstall and reinstall:
|
||||||
|
```bash
|
||||||
|
openclaw plugins uninstall openclaw-mem0
|
||||||
|
openclaw plugins install @mem0/openclaw-mem0
|
||||||
|
```
|
||||||
|
|
||||||
## Key Features
|
## Key Features
|
||||||
|
|
||||||
1. **Zero Configuration** — Auto-recall and auto-capture work out of the box with no prompting required
|
1. **Zero Configuration** — Auto-recall and auto-capture work out of the box with no prompting required
|
||||||
2. **Dual Memory Scopes** — Session-scoped short-term and user-scoped long-term memories
|
2. **Dual Memory Scopes** — Session-scoped short-term and user-scoped long-term memories
|
||||||
3. **Flexible Backend** — Use Mem0 Cloud for managed service or self-host with open-source mode
|
3. **Flexible Backend** — Use Mem0 Cloud for managed service or self-host with open-source mode
|
||||||
4. **Rich Tool Suite** — Five agent tools for explicit memory operations when needed
|
4. **Rich Tool Suite** — Eight agent tools for explicit memory operations when needed
|
||||||
|
|
||||||
## Conclusion
|
## Conclusion
|
||||||
|
|
||||||
|
|||||||
@@ -883,38 +883,160 @@ export function removeCodeBlocks(text: string): string {
|
|||||||
/**
|
/**
|
||||||
* Extracts a JSON object from text that may be wrapped in explanation text.
|
* Extracts a JSON object from text that may be wrapped in explanation text.
|
||||||
*
|
*
|
||||||
* Some LLMs (especially local models like Ollama/LM Studio) return JSON
|
* Some LLMs (especially local models like Ollama/LM Studio, or OpenRouter)
|
||||||
* wrapped in conversational text without code fences, e.g.:
|
* return JSON wrapped in conversational text without code fences, e.g.:
|
||||||
*
|
*
|
||||||
* "Here are the facts I extracted:\n{\"facts\": [\"fact1\"]}\nI hope this helps!"
|
* "Here are the facts I extracted:\n{\"facts\": [\"fact1\"]}\nI hope this helps!"
|
||||||
*
|
*
|
||||||
* This function first tries `removeCodeBlocks` for code-fence-wrapped JSON,
|
* This function:
|
||||||
* then falls back to locating the first `{` and last `}` to extract the
|
* 1. Strips known noise tokens from OpenRouter and other providers
|
||||||
* outermost JSON object.
|
* 2. Removes code fences and <think> blocks
|
||||||
|
* 3. Tries to find a valid JSON object by testing each `{` as a starting point
|
||||||
|
* 4. Falls back to first/last brace matching if validation isn't possible
|
||||||
*
|
*
|
||||||
* @param text - The raw LLM response text
|
* @param text - The raw LLM response text
|
||||||
* @returns The extracted JSON string, or the original text if no JSON object
|
* @returns The extracted JSON string, or the original text if no JSON object
|
||||||
* boundaries are found
|
* boundaries are found
|
||||||
*/
|
*/
|
||||||
export function extractJson(text: string): string {
|
export function extractJson(text: string): string {
|
||||||
// Step 1: Strip code fences if present
|
// Step 1: Strip known noise tokens from OpenRouter/local models
|
||||||
const cleaned = removeCodeBlocks(text);
|
let cleaned = text
|
||||||
|
.replace(/<\|end_of_text\|>/g, "")
|
||||||
|
.replace(/<\|eot_id\|>/g, "")
|
||||||
|
.replace(/<\|im_end\|>/g, "")
|
||||||
|
.replace(/<\|im_start\|>/g, "")
|
||||||
|
.replace(/<\|endoftext\|>/g, "");
|
||||||
|
|
||||||
|
// Step 2: Strip code fences and <think> blocks
|
||||||
|
cleaned = removeCodeBlocks(cleaned);
|
||||||
const trimmed = cleaned.trim();
|
const trimmed = cleaned.trim();
|
||||||
|
|
||||||
// Step 2: Try to locate a JSON object by first `{` and last `}` boundaries
|
if (!trimmed) return "";
|
||||||
|
|
||||||
|
// Step 3: Try to find valid JSON object by testing each `{` as potential start
|
||||||
|
// This handles cases like "Here's the {formatted} output: {...actual json...}"
|
||||||
|
const braceIndices: number[] = [];
|
||||||
|
for (let i = 0; i < trimmed.length; i++) {
|
||||||
|
if (trimmed[i] === "{") braceIndices.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const start of braceIndices) {
|
||||||
|
// Find the matching closing brace by tracking depth
|
||||||
|
let depth = 0;
|
||||||
|
let inString = false;
|
||||||
|
let escapeNext = false;
|
||||||
|
|
||||||
|
for (let i = start; i < trimmed.length; i++) {
|
||||||
|
const char = trimmed[i];
|
||||||
|
|
||||||
|
if (escapeNext) {
|
||||||
|
escapeNext = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (char === "\\") {
|
||||||
|
escapeNext = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (char === '"' && !escapeNext) {
|
||||||
|
inString = !inString;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inString) continue;
|
||||||
|
|
||||||
|
if (char === "{") depth++;
|
||||||
|
else if (char === "}") {
|
||||||
|
depth--;
|
||||||
|
if (depth === 0) {
|
||||||
|
const candidate = trimmed.substring(start, i + 1);
|
||||||
|
try {
|
||||||
|
JSON.parse(candidate);
|
||||||
|
return candidate; // Valid JSON found
|
||||||
|
} catch {
|
||||||
|
// Not valid JSON, try next starting brace
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Fallback - try first/last brace (original behavior for edge cases)
|
||||||
|
// Only use this if it produces valid JSON
|
||||||
const firstBrace = trimmed.indexOf("{");
|
const firstBrace = trimmed.indexOf("{");
|
||||||
const lastBrace = trimmed.lastIndexOf("}");
|
const lastBrace = trimmed.lastIndexOf("}");
|
||||||
if (firstBrace !== -1 && lastBrace > firstBrace) {
|
if (firstBrace !== -1 && lastBrace > firstBrace) {
|
||||||
return trimmed.substring(firstBrace, lastBrace + 1);
|
const candidate = trimmed.substring(firstBrace, lastBrace + 1);
|
||||||
|
try {
|
||||||
|
JSON.parse(candidate);
|
||||||
|
return candidate;
|
||||||
|
} catch {
|
||||||
|
// Not valid JSON, continue to array extraction
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3: Try to locate a JSON array by first `[` and last `]` boundaries
|
// Step 5: Try to locate a JSON array by testing each `[` as potential start
|
||||||
|
const bracketIndices: number[] = [];
|
||||||
|
for (let i = 0; i < trimmed.length; i++) {
|
||||||
|
if (trimmed[i] === "[") bracketIndices.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const start of bracketIndices) {
|
||||||
|
let depth = 0;
|
||||||
|
let inString = false;
|
||||||
|
let escapeNext = false;
|
||||||
|
|
||||||
|
for (let i = start; i < trimmed.length; i++) {
|
||||||
|
const char = trimmed[i];
|
||||||
|
|
||||||
|
if (escapeNext) {
|
||||||
|
escapeNext = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (char === "\\") {
|
||||||
|
escapeNext = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (char === '"' && !escapeNext) {
|
||||||
|
inString = !inString;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inString) continue;
|
||||||
|
|
||||||
|
if (char === "[") depth++;
|
||||||
|
else if (char === "]") {
|
||||||
|
depth--;
|
||||||
|
if (depth === 0) {
|
||||||
|
const candidate = trimmed.substring(start, i + 1);
|
||||||
|
try {
|
||||||
|
JSON.parse(candidate);
|
||||||
|
return candidate;
|
||||||
|
} catch {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback for arrays - validate before returning
|
||||||
const firstBracket = trimmed.indexOf("[");
|
const firstBracket = trimmed.indexOf("[");
|
||||||
const lastBracket = trimmed.lastIndexOf("]");
|
const lastBracket = trimmed.lastIndexOf("]");
|
||||||
if (firstBracket !== -1 && lastBracket > firstBracket) {
|
if (firstBracket !== -1 && lastBracket > firstBracket) {
|
||||||
return trimmed.substring(firstBracket, lastBracket + 1);
|
const candidate = trimmed.substring(firstBracket, lastBracket + 1);
|
||||||
|
try {
|
||||||
|
JSON.parse(candidate);
|
||||||
|
return candidate;
|
||||||
|
} catch {
|
||||||
|
// Not valid JSON
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No JSON boundaries found — return as-is and let the caller handle the error
|
// No valid JSON found — return as-is and let the caller handle the error
|
||||||
return trimmed;
|
return trimmed;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,4 +148,85 @@ That's all I found.`;
|
|||||||
const result = extractJson(input);
|
const result = extractJson(input);
|
||||||
expect(JSON.parse(result)).toEqual({ facts: ["test"] });
|
expect(JSON.parse(result)).toEqual({ facts: ["test"] });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("strips <|end_of_text|> tokens from OpenRouter responses", () => {
|
||||||
|
const input = '{"facts": ["test"]}<|end_of_text|>';
|
||||||
|
const result = extractJson(input);
|
||||||
|
expect(JSON.parse(result)).toEqual({ facts: ["test"] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("strips <|eot_id|> tokens from OpenRouter responses", () => {
|
||||||
|
const input = '{"facts": ["hello"]}<|eot_id|>';
|
||||||
|
const result = extractJson(input);
|
||||||
|
expect(JSON.parse(result)).toEqual({ facts: ["hello"] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("strips <|im_end|> tokens from ChatML responses", () => {
|
||||||
|
const input = '{"memory": [{"text": "test"}]}<|im_end|>';
|
||||||
|
const result = extractJson(input);
|
||||||
|
expect(JSON.parse(result)).toEqual({ memory: [{ text: "test" }] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("strips multiple noise tokens", () => {
|
||||||
|
const input =
|
||||||
|
'<|im_start|>assistant\n{"facts": ["data"]}<|im_end|><|end_of_text|>';
|
||||||
|
const result = extractJson(input);
|
||||||
|
expect(JSON.parse(result)).toEqual({ facts: ["data"] });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Issue #4737: Leading text with braces that aren't JSON
|
||||||
|
it("handles leading text containing braces before actual JSON", () => {
|
||||||
|
const input = 'Here\'s the {formatted} output: {"facts": ["real data"]}';
|
||||||
|
const result = extractJson(input);
|
||||||
|
expect(JSON.parse(result)).toEqual({ facts: ["real data"] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("handles multiple fake braces in leading text", () => {
|
||||||
|
const input =
|
||||||
|
"I'll format this {nicely} with {proper} structure:\n" +
|
||||||
|
'{"memory": [{"id": "1", "text": "actual memory"}]}';
|
||||||
|
const result = extractJson(input);
|
||||||
|
expect(JSON.parse(result)).toEqual({
|
||||||
|
memory: [{ id: "1", text: "actual memory" }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("handles incomplete JSON-like structures in leading text", () => {
|
||||||
|
const input =
|
||||||
|
"Based on {user preferences} I found:\n" +
|
||||||
|
'{"facts": ["User likes TypeScript"]}';
|
||||||
|
const result = extractJson(input);
|
||||||
|
expect(JSON.parse(result)).toEqual({ facts: ["User likes TypeScript"] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validates JSON and skips malformed candidates", () => {
|
||||||
|
const input = 'The result is {broken and {"facts": ["valid"]} is here';
|
||||||
|
const result = extractJson(input);
|
||||||
|
expect(JSON.parse(result)).toEqual({ facts: ["valid"] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("handles deeply nested valid JSON after invalid starts", () => {
|
||||||
|
const input =
|
||||||
|
"Here {is some {context}} for you:\n" +
|
||||||
|
'{"memory": [{"nested": {"deep": "value"}}]}';
|
||||||
|
const result = extractJson(input);
|
||||||
|
expect(JSON.parse(result)).toEqual({
|
||||||
|
memory: [{ nested: { deep: "value" } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("handles JSON with escaped quotes correctly", () => {
|
||||||
|
const input =
|
||||||
|
'Output: {"facts": ["User said \\"hello\\"", "Has a \\"test\\" project"]}';
|
||||||
|
const result = extractJson(input);
|
||||||
|
expect(JSON.parse(result)).toEqual({
|
||||||
|
facts: ['User said "hello"', 'Has a "test" project'],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("handles arrays with leading brace-like text", () => {
|
||||||
|
const input = 'Here\'s {some context}. The array is: ["fact1", "fact2"]';
|
||||||
|
const result = extractJson(input);
|
||||||
|
expect(JSON.parse(result)).toEqual(["fact1", "fact2"]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
package-lock.json
|
package-lock.json
|
||||||
*.db
|
*.db
|
||||||
|
.claude/
|
||||||
|
.claude-*/
|
||||||
+97
-21
@@ -4,31 +4,98 @@ Long-term memory for [OpenClaw](https://github.com/openclaw/openclaw) agents, po
|
|||||||
|
|
||||||
Your agent forgets everything between sessions. This plugin fixes that — it watches conversations, extracts what matters, and brings it back when relevant. Automatically.
|
Your agent forgets everything between sessions. This plugin fixes that — it watches conversations, extracts what matters, and brings it back when relevant. Automatically.
|
||||||
|
|
||||||
## Quick Start
|
## Requirements
|
||||||
|
|
||||||
|
Check your OpenClaw version:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
openclaw plugins install @mem0/openclaw-mem0
|
openclaw --version
|
||||||
|
# OpenClaw 2026.4.15 (041266a)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
| OpenClaw Version | Plugin Support |
|
||||||
|
|------------------|----------------|
|
||||||
|
| `>= 2026.4.15` | Fully supported |
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
The fastest way is to install directly from your OpenClaw chat — no CLI or config editing needed.
|
||||||
|
|
||||||
|
Copy and paste this into your OpenClaw chat (Telegram, WhatsApp, default chat, or any channel where your agent lives):
|
||||||
|
|
||||||
|
```
|
||||||
|
Setup Mem0 from mem0.ai/claw-setup
|
||||||
|
```
|
||||||
|
|
||||||
|
OpenClaw installs the plugin, prompts you for your email, and connects your Mem0 account with OTP verification. See [Chat Setup](#chat-setup-recommended) below for the full walkthrough.
|
||||||
|
|
||||||
|
If you prefer the OpenClaw CLI, or are setting up self-hosted / open-source mode, see [Manual Config](#manual-config) and [Open-Source (Self-hosted)](#open-source-self-hosted) below.
|
||||||
|
|
||||||
### Platform (Mem0 Cloud)
|
### Platform (Mem0 Cloud)
|
||||||
|
|
||||||
Get an API key from [app.mem0.ai](https://app.mem0.ai/dashboard/api-keys):
|
There are two ways to set up `@mem0/openclaw-mem0` on the Mem0 platform:
|
||||||
|
|
||||||
```bash
|
- **Chat setup (recommended)** — run the setup inside any OpenClaw chat. No config editing, no API key handling.
|
||||||
openclaw mem0 init --api-key <your-key> --user-id <your-user-id>
|
- **Manual config** — edit `openclaw.json` directly.
|
||||||
```
|
|
||||||
|
|
||||||
Or configure manually in `openclaw.json`:
|
#### Chat Setup (Recommended)
|
||||||
|
|
||||||
```json5
|
You no longer need manual config editing to get started. Everything happens inside the OpenClaw chat itself.
|
||||||
"openclaw-mem0": {
|
|
||||||
"enabled": true,
|
1. **Send the setup command to your OpenClaw agent.** Open any OpenClaw channel and paste:
|
||||||
"config": {
|
|
||||||
"apiKey": "${MEM0_API_KEY}",
|
```
|
||||||
"userId": "alice"
|
Setup Mem0 from mem0.ai/claw-setup
|
||||||
}
|
```
|
||||||
}
|
|
||||||
```
|
OpenClaw responds with a Mem0 setup card and asks: *"What's your email address? I'll send you a verification code to connect your Mem0 account."*
|
||||||
|
|
||||||
|
2. **Enter your email.** Type your email address and send it. Mem0 replies: *"Check your email for a 6-digit code and paste it here."*
|
||||||
|
|
||||||
|
3. **Paste the OTP.** Copy the 6-digit code from your email inbox and paste it into the chat. You'll see: *"Connected to Mem0."*
|
||||||
|
|
||||||
|
That's it. No API key, no config file editing, no environment variables. The plugin is now active and auto-capture and auto-recall are running on every turn.
|
||||||
|
|
||||||
|
> The chat flow uses the same underlying config as manual setup — it writes `apiKey` and `userId` into `openclaw.json` for you. You can still open the file to inspect or override values afterward.
|
||||||
|
|
||||||
|
#### Manual Config
|
||||||
|
|
||||||
|
1. **Install the plugin via the OpenClaw CLI:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
openclaw plugins install @mem0/openclaw-mem0
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Get your API key** from [app.mem0.ai](https://app.mem0.ai/dashboard/api-keys).
|
||||||
|
|
||||||
|
3. **Select the plugin as your memory backend in `openclaw.json`.** Either initialize via the CLI:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
openclaw mem0 init --api-key <your-key> --user-id <your-user-id>
|
||||||
|
```
|
||||||
|
|
||||||
|
Or add the full config to your `openclaw.json`:
|
||||||
|
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
"plugins": {
|
||||||
|
"slots": {
|
||||||
|
"memory": "openclaw-mem0"
|
||||||
|
},
|
||||||
|
"entries": {
|
||||||
|
"openclaw-mem0": {
|
||||||
|
"enabled": true,
|
||||||
|
"config": {
|
||||||
|
"apiKey": "${MEM0_API_KEY}",
|
||||||
|
"userId": "alice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note:** OpenClaw memory plugins load through an exclusive slot, so install alone does not activate the plugin. You must set `plugins.slots.memory` as shown above.
|
||||||
|
|
||||||
### Open-Source (Self-hosted)
|
### Open-Source (Self-hosted)
|
||||||
|
|
||||||
@@ -37,11 +104,20 @@ No Mem0 key needed. Requires `OPENAI_API_KEY` for default embeddings and LLM. Ve
|
|||||||
Defaults: `text-embedding-3-small` for embeddings, `gpt-5.4` for fact extraction.
|
Defaults: `text-embedding-3-small` for embeddings, `gpt-5.4` for fact extraction.
|
||||||
|
|
||||||
```json5
|
```json5
|
||||||
"openclaw-mem0": {
|
{
|
||||||
"enabled": true,
|
"plugins": {
|
||||||
"config": {
|
"slots": {
|
||||||
"mode": "open-source",
|
"memory": "openclaw-mem0"
|
||||||
"userId": "alice"
|
},
|
||||||
|
"entries": {
|
||||||
|
"openclaw-mem0": {
|
||||||
|
"enabled": true,
|
||||||
|
"config": {
|
||||||
|
"mode": "open-source",
|
||||||
|
"userId": "alice"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -10,9 +10,7 @@ export interface AddOptions {
|
|||||||
appId?: string;
|
appId?: string;
|
||||||
runId?: string;
|
runId?: string;
|
||||||
metadata?: Record<string, unknown>;
|
metadata?: Record<string, unknown>;
|
||||||
immutable?: boolean;
|
|
||||||
infer?: boolean;
|
infer?: boolean;
|
||||||
expires?: string;
|
|
||||||
categories?: string[];
|
categories?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +22,6 @@ export interface SearchOptions {
|
|||||||
topK?: number;
|
topK?: number;
|
||||||
threshold?: number;
|
threshold?: number;
|
||||||
rerank?: boolean;
|
rerank?: boolean;
|
||||||
keyword?: boolean;
|
|
||||||
filters?: Record<string, unknown>;
|
filters?: Record<string, unknown>;
|
||||||
fields?: string[];
|
fields?: string[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,9 +107,7 @@ export class PlatformBackend implements Backend {
|
|||||||
if (opts.appId) payload.app_id = opts.appId;
|
if (opts.appId) payload.app_id = opts.appId;
|
||||||
if (opts.runId) payload.run_id = opts.runId;
|
if (opts.runId) payload.run_id = opts.runId;
|
||||||
if (opts.metadata) payload.metadata = opts.metadata;
|
if (opts.metadata) payload.metadata = opts.metadata;
|
||||||
if (opts.immutable) payload.immutable = true;
|
|
||||||
if (opts.infer === false) payload.infer = false;
|
if (opts.infer === false) payload.infer = false;
|
||||||
if (opts.expires) payload.expiration_date = opts.expires;
|
|
||||||
if (opts.categories) payload.categories = opts.categories;
|
if (opts.categories) payload.categories = opts.categories;
|
||||||
|
|
||||||
return (await this._request("POST", "/v1/memories/", {
|
return (await this._request("POST", "/v1/memories/", {
|
||||||
@@ -168,7 +166,6 @@ export class PlatformBackend implements Backend {
|
|||||||
});
|
});
|
||||||
if (apiFilters) payload.filters = apiFilters;
|
if (apiFilters) payload.filters = apiFilters;
|
||||||
if (opts.rerank) payload.rerank = true;
|
if (opts.rerank) payload.rerank = true;
|
||||||
if (opts.keyword) payload.keyword_search = true;
|
|
||||||
if (opts.fields) payload.fields = opts.fields;
|
if (opts.fields) payload.fields = opts.fields;
|
||||||
|
|
||||||
const result = (await this._request("POST", "/v2/memories/search/", {
|
const result = (await this._request("POST", "/v2/memories/search/", {
|
||||||
|
|||||||
+125
-22
@@ -19,6 +19,7 @@ export const OPENCLAW_CONFIG_FILE = join(OPENCLAW_CONFIG_DIR, "openclaw.json");
|
|||||||
export const DEFAULT_BASE_URL = "https://api.mem0.ai";
|
export const DEFAULT_BASE_URL = "https://api.mem0.ai";
|
||||||
|
|
||||||
const PLUGIN_ID = "openclaw-mem0";
|
const PLUGIN_ID = "openclaw-mem0";
|
||||||
|
const NPM_PACKAGE = "@mem0/openclaw-mem0";
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Types
|
// Types
|
||||||
@@ -41,16 +42,38 @@ export interface PluginAuthConfig {
|
|||||||
// OpenClaw config read/write
|
// OpenClaw config read/write
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
/** Read the full ~/.openclaw/openclaw.json */
|
/**
|
||||||
|
* Read the full ~/.openclaw/openclaw.json.
|
||||||
|
*
|
||||||
|
* Returns {} only when the file doesn't exist (first-time setup).
|
||||||
|
* Throws on parse errors to prevent writes from destroying existing config.
|
||||||
|
*/
|
||||||
function readFullConfig(): Record<string, unknown> {
|
function readFullConfig(): Record<string, unknown> {
|
||||||
if (exists(OPENCLAW_CONFIG_FILE)) {
|
if (!exists(OPENCLAW_CONFIG_FILE)) {
|
||||||
try {
|
return {};
|
||||||
return JSON.parse(readText(OPENCLAW_CONFIG_FILE));
|
}
|
||||||
} catch {
|
|
||||||
/* ignore parse errors */
|
const text = readText(OPENCLAW_CONFIG_FILE);
|
||||||
}
|
|
||||||
|
// Handle empty or whitespace-only files as first-time setup
|
||||||
|
if (!text.trim()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(text);
|
||||||
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
||||||
|
throw new Error("Config is not a JSON object");
|
||||||
|
}
|
||||||
|
return parsed;
|
||||||
|
} catch (err) {
|
||||||
|
// Fail closed: throw so writes don't proceed with empty config
|
||||||
|
const msg = err instanceof Error ? err.message : String(err);
|
||||||
|
throw new Error(
|
||||||
|
`[openclaw-mem0] Failed to parse ${OPENCLAW_CONFIG_FILE}: ${msg}\n` +
|
||||||
|
`Fix the JSON syntax error manually before running config commands.`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Write the full ~/.openclaw/openclaw.json (preserves all non-plugin config) */
|
/** Write the full ~/.openclaw/openclaw.json (preserves all non-plugin config) */
|
||||||
@@ -87,15 +110,7 @@ export function readPluginAuth(): PluginAuthConfig {
|
|||||||
export function writePluginAuth(auth: PluginAuthConfig): void {
|
export function writePluginAuth(auth: PluginAuthConfig): void {
|
||||||
const full = readFullConfig() as any;
|
const full = readFullConfig() as any;
|
||||||
|
|
||||||
// Ensure nested structure exists
|
ensurePluginStructure(full);
|
||||||
if (!full.plugins) full.plugins = {};
|
|
||||||
if (!full.plugins.entries) full.plugins.entries = {};
|
|
||||||
if (!full.plugins.entries[PLUGIN_ID]) {
|
|
||||||
full.plugins.entries[PLUGIN_ID] = { enabled: true, config: {} };
|
|
||||||
}
|
|
||||||
if (!full.plugins.entries[PLUGIN_ID].config) {
|
|
||||||
full.plugins.entries[PLUGIN_ID].config = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const cfg = full.plugins.entries[PLUGIN_ID].config;
|
const cfg = full.plugins.entries[PLUGIN_ID].config;
|
||||||
|
|
||||||
@@ -107,12 +122,81 @@ export function writePluginAuth(auth: PluginAuthConfig): void {
|
|||||||
writeFullConfig(full);
|
writeFullConfig(full);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function writePluginConfigField(
|
/**
|
||||||
path: string[],
|
* Ensure the plugin has a valid install record and is in plugins.allow.
|
||||||
value: unknown,
|
*
|
||||||
): void {
|
* OpenClaw's `plugins update` command requires a `plugins.installs.<id>`
|
||||||
const full = readFullConfig() as any;
|
* record with `source: "npm"` and `spec` to know how to update. Without
|
||||||
|
* this, `openclaw plugins update` prints "No install record" and skips.
|
||||||
|
*
|
||||||
|
* Similarly, if `plugins.allow` exists as an array, the plugin ID must
|
||||||
|
* be in it or OpenClaw treats the plugin as untrusted.
|
||||||
|
*
|
||||||
|
* This is safe to call multiple times — it only writes missing fields.
|
||||||
|
*/
|
||||||
|
export function ensureInstallRecord(): void {
|
||||||
|
try {
|
||||||
|
const full = readFullConfig() as any;
|
||||||
|
|
||||||
|
const entry = full?.plugins?.entries?.[PLUGIN_ID];
|
||||||
|
const record = full?.plugins?.installs?.[PLUGIN_ID];
|
||||||
|
const allow = full?.plugins?.allow;
|
||||||
|
if (
|
||||||
|
entry?.enabled === true &&
|
||||||
|
record?.source &&
|
||||||
|
record?.spec &&
|
||||||
|
Array.isArray(allow) &&
|
||||||
|
allow.includes(PLUGIN_ID)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ensurePluginStructure(full);
|
||||||
|
|
||||||
|
let changed = false;
|
||||||
|
|
||||||
|
// Ensure install record exists for `openclaw plugins update` support
|
||||||
|
if (!full.plugins.installs) full.plugins.installs = {};
|
||||||
|
if (!full.plugins.installs[PLUGIN_ID]) {
|
||||||
|
full.plugins.installs[PLUGIN_ID] = {
|
||||||
|
source: "npm",
|
||||||
|
spec: `${NPM_PACKAGE}@latest`,
|
||||||
|
resolvedName: NPM_PACKAGE,
|
||||||
|
installedAt: new Date().toISOString(),
|
||||||
|
};
|
||||||
|
changed = true;
|
||||||
|
} else {
|
||||||
|
const record = full.plugins.installs[PLUGIN_ID];
|
||||||
|
if (!record.source) {
|
||||||
|
record.source = "npm";
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (!record.spec) {
|
||||||
|
record.spec = `${NPM_PACKAGE}@latest`;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (!record.resolvedName) {
|
||||||
|
record.resolvedName = NPM_PACKAGE;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Array.isArray(full.plugins.allow)) {
|
||||||
|
full.plugins.allow = [PLUGIN_ID];
|
||||||
|
changed = true;
|
||||||
|
} else if (!full.plugins.allow.includes(PLUGIN_ID)) {
|
||||||
|
full.plugins.allow.push(PLUGIN_ID);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed) writeFullConfig(full);
|
||||||
|
} catch {
|
||||||
|
// Best-effort — don't break plugin loading if config is unreadable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ensure the nested plugin entry structure exists in the config object. */
|
||||||
|
function ensurePluginStructure(full: any): void {
|
||||||
if (!full.plugins) full.plugins = {};
|
if (!full.plugins) full.plugins = {};
|
||||||
if (!full.plugins.entries) full.plugins.entries = {};
|
if (!full.plugins.entries) full.plugins.entries = {};
|
||||||
if (!full.plugins.entries[PLUGIN_ID]) {
|
if (!full.plugins.entries[PLUGIN_ID]) {
|
||||||
@@ -121,6 +205,15 @@ export function writePluginConfigField(
|
|||||||
if (!full.plugins.entries[PLUGIN_ID].config) {
|
if (!full.plugins.entries[PLUGIN_ID].config) {
|
||||||
full.plugins.entries[PLUGIN_ID].config = {};
|
full.plugins.entries[PLUGIN_ID].config = {};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function writePluginConfigField(
|
||||||
|
path: string[],
|
||||||
|
value: unknown,
|
||||||
|
): void {
|
||||||
|
const full = readFullConfig() as any;
|
||||||
|
|
||||||
|
ensurePluginStructure(full);
|
||||||
|
|
||||||
let target = full.plugins.entries[PLUGIN_ID].config;
|
let target = full.plugins.entries[PLUGIN_ID].config;
|
||||||
for (let i = 0; i < path.length - 1; i++) {
|
for (let i = 0; i < path.length - 1; i++) {
|
||||||
@@ -139,3 +232,13 @@ export function getBaseUrl(): string {
|
|||||||
const auth = readPluginAuth();
|
const auth = readPluginAuth();
|
||||||
return auth.baseUrl || DEFAULT_BASE_URL;
|
return auth.baseUrl || DEFAULT_BASE_URL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Remove anonymousTelemetryId from config (after PostHog aliasing) */
|
||||||
|
export function clearAnonymousTelemetryId(): void {
|
||||||
|
const full = readFullConfig() as any;
|
||||||
|
const cfg = full?.plugins?.entries?.[PLUGIN_ID]?.config;
|
||||||
|
if (cfg && "anonymousTelemetryId" in cfg) {
|
||||||
|
delete cfg.anonymousTelemetryId;
|
||||||
|
writeFullConfig(full);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+4
-5
@@ -233,20 +233,19 @@ export const mem0ConfigSchema = {
|
|||||||
})(),
|
})(),
|
||||||
autoCapture: cfg.autoCapture !== false,
|
autoCapture: cfg.autoCapture !== false,
|
||||||
autoRecall: cfg.autoRecall !== false,
|
autoRecall: cfg.autoRecall !== false,
|
||||||
|
// v3.0.0: customPrompt renamed to customInstructions (backwards-compat: accept either)
|
||||||
customInstructions:
|
customInstructions:
|
||||||
typeof cfg.customInstructions === "string"
|
typeof cfg.customInstructions === "string"
|
||||||
? cfg.customInstructions
|
? cfg.customInstructions
|
||||||
: DEFAULT_CUSTOM_INSTRUCTIONS,
|
: typeof cfg.customPrompt === "string"
|
||||||
|
? cfg.customPrompt
|
||||||
|
: DEFAULT_CUSTOM_INSTRUCTIONS,
|
||||||
customCategories:
|
customCategories:
|
||||||
cfg.customCategories &&
|
cfg.customCategories &&
|
||||||
typeof cfg.customCategories === "object" &&
|
typeof cfg.customCategories === "object" &&
|
||||||
!Array.isArray(cfg.customCategories)
|
!Array.isArray(cfg.customCategories)
|
||||||
? (cfg.customCategories as Record<string, string>)
|
? (cfg.customCategories as Record<string, string>)
|
||||||
: DEFAULT_CUSTOM_CATEGORIES,
|
: DEFAULT_CUSTOM_CATEGORIES,
|
||||||
customPrompt:
|
|
||||||
typeof cfg.customPrompt === "string"
|
|
||||||
? cfg.customPrompt
|
|
||||||
: DEFAULT_CUSTOM_INSTRUCTIONS,
|
|
||||||
searchThreshold:
|
searchThreshold:
|
||||||
typeof cfg.searchThreshold === "number" ? cfg.searchThreshold : 0.5,
|
typeof cfg.searchThreshold === "number" ? cfg.searchThreshold : 0.5,
|
||||||
topK: typeof cfg.topK === "number" ? cfg.topK : 5,
|
topK: typeof cfg.topK === "number" ? cfg.topK : 5,
|
||||||
|
|||||||
+75
-2
@@ -14,9 +14,41 @@ const NOISE_MESSAGE_PATTERNS: RegExp[] = [
|
|||||||
/^(HEARTBEAT_OK|NO_REPLY)$/i,
|
/^(HEARTBEAT_OK|NO_REPLY)$/i,
|
||||||
/^Current time:.*\d{4}/,
|
/^Current time:.*\d{4}/,
|
||||||
/^Pre-compaction memory flush/i,
|
/^Pre-compaction memory flush/i,
|
||||||
/^(ok|yes|no|sir|sure|thanks|done|good|nice|cool|got it|it's on|continue)$/i,
|
/^(ok|yes|no|sir|sure|thanks|done|good|nice|cool|got it|it's on|continue|alright|okay|yep|nope|uh-huh|mm-hmm|hmm)$/i,
|
||||||
/^System: \[.*\] (Slack message edited|Gateway restart|Exec (failed|completed))/,
|
/^System: \[.*\] (Slack message edited|Gateway restart|Exec (failed|completed))/,
|
||||||
/^System: \[.*\] ⚠️ Post-Compaction Audit:/,
|
/^System: \[.*\] ⚠️ Post-Compaction Audit:/,
|
||||||
|
// JSON-only messages (tool results, metadata)
|
||||||
|
/^[\s]*\{[\s\S]*\}[\s]*$/,
|
||||||
|
/^[\s]*\[[\s\S]*\][\s]*$/,
|
||||||
|
// Empty or whitespace-only after trimming
|
||||||
|
/^[\s\n\r]*$/,
|
||||||
|
// Technical noise patterns
|
||||||
|
/^(Error|Warning|Info|Debug):/i,
|
||||||
|
/^(Loading|Loaded|Fetching|Fetched|Processing|Processed)\b/i,
|
||||||
|
/^\[[\d:T\-\.Z]+\]/, // Timestamps like [2024-01-01T12:00:00.000Z]
|
||||||
|
/^(SUCCESS|FAILURE|PENDING|COMPLETED|FAILED)$/i,
|
||||||
|
// Tool/function call noise
|
||||||
|
/^(Calling|Called|Invoking|Invoked|Executing|Executed)\s+(function|tool|method)/i,
|
||||||
|
/^Tool (call|result|output):/i,
|
||||||
|
// Single emoji or very short messages
|
||||||
|
/^[\p{Emoji}\s]{1,5}$/u,
|
||||||
|
];
|
||||||
|
|
||||||
|
/** Patterns for session-specific technical content that should not be stored as memories. */
|
||||||
|
const SESSION_SPECIFIC_PATTERNS: RegExp[] = [
|
||||||
|
// Tool availability discussions
|
||||||
|
/tools?\s+(are|is)\s+(not\s+)?(exposed|available|accessible)/i,
|
||||||
|
/plugin\s+(does not|doesn't)\s+expose/i,
|
||||||
|
/I\s+(do not|don't)\s+(currently\s+)?see\s+.*tools?\s+exposed/i,
|
||||||
|
/memory_(search|get|add|update|delete|list)\s+(tool|is|are)/i,
|
||||||
|
// Session-specific capability statements
|
||||||
|
/in\s+this\s+session/i,
|
||||||
|
/my\s+(live\s+)?callable\s+tool\s+registry/i,
|
||||||
|
/tools?\s+I\s+(have|currently have)\s+access\s+to/i,
|
||||||
|
// Plugin/capability status statements
|
||||||
|
/openclaw-mem0\s+plugin/i,
|
||||||
|
/memory\s+wiki.*capability/i,
|
||||||
|
/workspace\s+memory\s+files/i,
|
||||||
];
|
];
|
||||||
|
|
||||||
/** Content fragments that should be stripped from otherwise-valid messages. */
|
/** Content fragments that should be stripped from otherwise-valid messages. */
|
||||||
@@ -50,6 +82,31 @@ const NOISE_CONTENT_PATTERNS: Array<{ pattern: RegExp; replacement: string }> =
|
|||||||
/Replied message \(untrusted, for context\):\s*```json[\s\S]*?```/g,
|
/Replied message \(untrusted, for context\):\s*```json[\s\S]*?```/g,
|
||||||
replacement: "",
|
replacement: "",
|
||||||
},
|
},
|
||||||
|
// Strip embedded JSON blocks that might contain metadata
|
||||||
|
{
|
||||||
|
pattern: /```json\s*\{[\s\S]*?\}\s*```/g,
|
||||||
|
replacement: "",
|
||||||
|
},
|
||||||
|
// Strip code blocks that are just tool outputs
|
||||||
|
{
|
||||||
|
pattern: /```(?:text|output|result|log)\s*[\s\S]*?```/gi,
|
||||||
|
replacement: "",
|
||||||
|
},
|
||||||
|
// Strip inline tool call IDs
|
||||||
|
{
|
||||||
|
pattern: /\[tool_call_id:[^\]]+\]/g,
|
||||||
|
replacement: "",
|
||||||
|
},
|
||||||
|
// Strip memory IDs from responses
|
||||||
|
{
|
||||||
|
pattern: /\(id:\s*[a-f0-9-]+\)/gi,
|
||||||
|
replacement: "",
|
||||||
|
},
|
||||||
|
// Strip session/run IDs
|
||||||
|
{
|
||||||
|
pattern: /(?:session|run|agent)[_-]?(?:id|key)?:\s*[a-zA-Z0-9_:-]+/gi,
|
||||||
|
replacement: "",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const MAX_MESSAGE_LENGTH = 2000;
|
const MAX_MESSAGE_LENGTH = 2000;
|
||||||
@@ -81,6 +138,20 @@ export function isNoiseMessage(content: string): boolean {
|
|||||||
return NOISE_MESSAGE_PATTERNS.some((p) => p.test(trimmed));
|
return NOISE_MESSAGE_PATTERNS.some((p) => p.test(trimmed));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a message contains session-specific technical content
|
||||||
|
* that should not be stored (tool availability discussions, plugin
|
||||||
|
* capability statements, etc.). These are facts about the current session
|
||||||
|
* that have no value in future sessions.
|
||||||
|
*/
|
||||||
|
export function isSessionSpecificContent(content: string): boolean {
|
||||||
|
const trimmed = content.trim();
|
||||||
|
if (!trimmed) return false;
|
||||||
|
// Check if multiple session-specific patterns match (more confident filtering)
|
||||||
|
const matches = SESSION_SPECIFIC_PATTERNS.filter((p) => p.test(trimmed));
|
||||||
|
return matches.length >= 2;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether an assistant message is a generic acknowledgment with no
|
* Check whether an assistant message is a generic acknowledgment with no
|
||||||
* extractable facts (e.g. "I see you've shared an update. How can I help?").
|
* extractable facts (e.g. "I see you've shared an update. How can I help?").
|
||||||
@@ -120,7 +191,7 @@ function truncateMessage(content: string): string {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Full pre-extraction pipeline: drop noise messages, strip noise fragments,
|
* Full pre-extraction pipeline: drop noise messages, strip noise fragments,
|
||||||
* and truncate remaining messages to a reasonable length.
|
* filter session-specific content, and truncate remaining messages.
|
||||||
*/
|
*/
|
||||||
export function filterMessagesForExtraction(
|
export function filterMessagesForExtraction(
|
||||||
messages: Array<{ role: string; content: string }>,
|
messages: Array<{ role: string; content: string }>,
|
||||||
@@ -131,6 +202,8 @@ export function filterMessagesForExtraction(
|
|||||||
// Drop generic assistant acknowledgments that contain no facts
|
// Drop generic assistant acknowledgments that contain no facts
|
||||||
if (msg.role === "assistant" && isGenericAssistantMessage(msg.content))
|
if (msg.role === "assistant" && isGenericAssistantMessage(msg.content))
|
||||||
continue;
|
continue;
|
||||||
|
// Drop session-specific technical content (tool availability, plugin capabilities)
|
||||||
|
if (isSessionSpecificContent(msg.content)) continue;
|
||||||
const cleaned = stripNoiseFromContent(msg.content);
|
const cleaned = stripNoiseFromContent(msg.content);
|
||||||
if (!cleaned) continue;
|
if (!cleaned) continue;
|
||||||
filtered.push({ role: msg.role, content: truncateMessage(cleaned) });
|
filtered.push({ role: msg.role, content: truncateMessage(cleaned) });
|
||||||
|
|||||||
+27
-9
@@ -28,6 +28,7 @@ import type {
|
|||||||
import { createProvider, providerToBackend } from "./providers.ts";
|
import { createProvider, providerToBackend } from "./providers.ts";
|
||||||
import { mem0ConfigSchema } from "./config.ts";
|
import { mem0ConfigSchema } from "./config.ts";
|
||||||
import type { FileConfig } from "./config.ts";
|
import type { FileConfig } from "./config.ts";
|
||||||
|
import { createPublicArtifactsProvider } from "./public-artifacts.ts";
|
||||||
import { filterMessagesForExtraction } from "./filtering.ts";
|
import { filterMessagesForExtraction } from "./filtering.ts";
|
||||||
import {
|
import {
|
||||||
effectiveUserId,
|
effectiveUserId,
|
||||||
@@ -53,13 +54,14 @@ import {
|
|||||||
import { PlatformBackend } from "./backend/platform.ts";
|
import { PlatformBackend } from "./backend/platform.ts";
|
||||||
import type { Backend } from "./backend/base.ts";
|
import type { Backend } from "./backend/base.ts";
|
||||||
import { registerCliCommands } from "./cli/commands.ts";
|
import { registerCliCommands } from "./cli/commands.ts";
|
||||||
import { readPluginAuth } from "./cli/config-file.ts";
|
import { readPluginAuth, ensureInstallRecord } from "./cli/config-file.ts";
|
||||||
import { registerAllTools } from "./tools/index.ts";
|
import { registerAllTools } from "./tools/index.ts";
|
||||||
import type { ToolDeps } from "./tools/index.ts";
|
import type { ToolDeps } from "./tools/index.ts";
|
||||||
import { captureEvent } from "./telemetry.ts";
|
import { captureEvent } from "./telemetry.ts";
|
||||||
import { bootstrapTelemetryFlag } from "./fs-safe.ts";
|
import { bootstrapTelemetryFlag } from "./fs-safe.ts";
|
||||||
|
|
||||||
bootstrapTelemetryFlag();
|
bootstrapTelemetryFlag();
|
||||||
|
ensureInstallRecord();
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Re-exports (for tests and external consumers)
|
// Re-exports (for tests and external consumers)
|
||||||
@@ -76,6 +78,7 @@ export {
|
|||||||
export {
|
export {
|
||||||
isNoiseMessage,
|
isNoiseMessage,
|
||||||
isGenericAssistantMessage,
|
isGenericAssistantMessage,
|
||||||
|
isSessionSpecificContent,
|
||||||
stripNoiseFromContent,
|
stripNoiseFromContent,
|
||||||
filterMessagesForExtraction,
|
filterMessagesForExtraction,
|
||||||
} from "./filtering.ts";
|
} from "./filtering.ts";
|
||||||
@@ -191,24 +194,43 @@ const memoryPlugin = definePluginEntry({
|
|||||||
`openclaw-mem0: registered (mode: ${cfg.mode}, user: ${cfg.userId}, autoRecall: ${cfg.autoRecall}, autoCapture: ${cfg.autoCapture}, skills: ${skillsActive})`,
|
`openclaw-mem0: registered (mode: ${cfg.mode}, user: ${cfg.userId}, autoRecall: ${cfg.autoRecall}, autoCapture: ${cfg.autoCapture}, skills: ${skillsActive})`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Public Artifacts (for memory-wiki bridge mode)
|
||||||
|
// ========================================================================
|
||||||
|
if (typeof api.registerMemoryCapability === "function") {
|
||||||
|
api.registerMemoryCapability({
|
||||||
|
publicArtifacts: createPublicArtifactsProvider({
|
||||||
|
provider,
|
||||||
|
cfg,
|
||||||
|
get stateDir() {
|
||||||
|
return pluginStateDir;
|
||||||
|
},
|
||||||
|
effectiveUserId: _effectiveUserId,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
api.logger.debug("openclaw-mem0: publicArtifacts capability registered");
|
||||||
|
}
|
||||||
|
|
||||||
// Helper: build add options
|
// Helper: build add options
|
||||||
function buildAddOptions(
|
function buildAddOptions(
|
||||||
userIdOverride?: string,
|
userIdOverride?: string,
|
||||||
runId?: string,
|
runId?: string,
|
||||||
sessionKey?: string,
|
sessionKey?: string,
|
||||||
): AddOptions {
|
): AddOptions {
|
||||||
|
// v3.0.0: removed output_format, customPrompt renamed to customInstructions
|
||||||
const opts: AddOptions = {
|
const opts: AddOptions = {
|
||||||
user_id: userIdOverride || _effectiveUserId(sessionKey),
|
user_id: userIdOverride || _effectiveUserId(sessionKey),
|
||||||
source: "OPENCLAW",
|
source: "OPENCLAW",
|
||||||
};
|
};
|
||||||
if (runId) opts.run_id = runId;
|
if (runId) opts.run_id = runId;
|
||||||
if (cfg.mode === "platform") {
|
// Pass customInstructions and customCategories to control what Mem0 extracts
|
||||||
opts.output_format = "v1.1";
|
if (cfg.customInstructions) opts.custom_instructions = cfg.customInstructions;
|
||||||
}
|
if (cfg.customCategories) opts.custom_categories = cfg.customCategories;
|
||||||
return opts;
|
return opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper: build search options (skills config overrides legacy defaults)
|
// Helper: build search options (skills config overrides legacy defaults)
|
||||||
|
// v3.0.0: removed keyword_search, reranking, filter_memories, limit
|
||||||
function buildSearchOptions(
|
function buildSearchOptions(
|
||||||
userIdOverride?: string,
|
userIdOverride?: string,
|
||||||
limit?: number,
|
limit?: number,
|
||||||
@@ -219,13 +241,9 @@ const memoryPlugin = definePluginEntry({
|
|||||||
const opts: SearchOptions = {
|
const opts: SearchOptions = {
|
||||||
user_id: userIdOverride || _effectiveUserId(sessionKey),
|
user_id: userIdOverride || _effectiveUserId(sessionKey),
|
||||||
top_k: limit ?? cfg.topK,
|
top_k: limit ?? cfg.topK,
|
||||||
limit: limit ?? cfg.topK,
|
|
||||||
threshold: recallCfg?.threshold ?? cfg.searchThreshold,
|
threshold: recallCfg?.threshold ?? cfg.searchThreshold,
|
||||||
keyword_search: recallCfg?.keywordSearch !== false,
|
|
||||||
reranking: recallCfg?.rerank !== false,
|
|
||||||
source: "OPENCLAW",
|
source: "OPENCLAW",
|
||||||
};
|
};
|
||||||
if (recallCfg?.filterMemories) opts.filter_memories = true;
|
|
||||||
if (runId) opts.run_id = runId;
|
if (runId) opts.run_id = runId;
|
||||||
return opts;
|
return opts;
|
||||||
}
|
}
|
||||||
@@ -950,7 +968,7 @@ function registerHooks(
|
|||||||
content: `Current date: ${timestamp}. The user is identified as "${cfg.userId}". Extract durable facts from this conversation. Include this date when storing time-sensitive information.`,
|
content: `Current date: ${timestamp}. The user is identified as "${cfg.userId}". Extract durable facts from this conversation. Include this date when storing time-sensitive information.`,
|
||||||
});
|
});
|
||||||
|
|
||||||
const addOpts = buildAddOptions(undefined, sessionId, sessionId);
|
const addOpts = buildAddOptions(undefined, undefined, sessionId);
|
||||||
const captureStart = Date.now();
|
const captureStart = Date.now();
|
||||||
provider
|
provider
|
||||||
.add(formattedMessages, addOpts)
|
.add(formattedMessages, addOpts)
|
||||||
|
|||||||
Vendored
+26
@@ -1,4 +1,29 @@
|
|||||||
declare module "openclaw/plugin-sdk" {
|
declare module "openclaw/plugin-sdk" {
|
||||||
|
export interface MemoryArtifact {
|
||||||
|
id: string;
|
||||||
|
type: "memory" | "dream" | "digest" | "entity";
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
metadata?: Record<string, unknown>;
|
||||||
|
createdAt?: string;
|
||||||
|
updatedAt?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PublicArtifactsProvider {
|
||||||
|
listArtifacts(options?: {
|
||||||
|
userId?: string;
|
||||||
|
types?: string[];
|
||||||
|
limit?: number;
|
||||||
|
}): Promise<MemoryArtifact[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MemoryCapabilityConfig {
|
||||||
|
promptBuilder?: (ctx: any) => Promise<string | null>;
|
||||||
|
flushPlanResolver?: (ctx: any) => Promise<any>;
|
||||||
|
runtime?: Record<string, unknown>;
|
||||||
|
publicArtifacts?: PublicArtifactsProvider;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OpenClawPluginApi {
|
export interface OpenClawPluginApi {
|
||||||
pluginConfig: Record<string, unknown>;
|
pluginConfig: Record<string, unknown>;
|
||||||
logger: {
|
logger: {
|
||||||
@@ -32,6 +57,7 @@ declare module "openclaw/plugin-sdk" {
|
|||||||
start: (...args: any[]) => void;
|
start: (...args: any[]) => void;
|
||||||
stop: () => void;
|
stop: () => void;
|
||||||
}): void;
|
}): void;
|
||||||
|
registerMemoryCapability?(config: MemoryCapabilityConfig): void;
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
{
|
{
|
||||||
"id": "openclaw-mem0",
|
"id": "openclaw-mem0",
|
||||||
"name": "Memory (Mem0)",
|
"name": "Memory (Mem0)",
|
||||||
"description": "Mem0 memory backend for OpenClaw — platform or self-hosted open-source. Injects recalled memories into agent context (auto-recall) and extracts facts after each turn (auto-capture). Both configurable via autoRecall/autoCapture settings.",
|
"description": "Mem0 memory backend for OpenClaw — platform or self-hosted open-source. PLATFORM MODE: Sends conversation data to mem0.ai cloud (requires MEM0_API_KEY). OPEN-SOURCE MODE: Stores vectors locally (~/.mem0/history.db) but uses external APIs for embeddings/LLM (default: OpenAI, requires OPENAI_API_KEY). Auto-recall injects memories before agent turns; auto-capture extracts facts after turns. Both configurable via autoRecall/autoCapture settings. Config stored in ~/.openclaw/openclaw.json.",
|
||||||
"version": "1.0.5",
|
"version": "1.0.7",
|
||||||
"kind": "memory",
|
"kind": "memory",
|
||||||
"skills": ["skills"],
|
"skills": ["skills"],
|
||||||
|
"commandAliases": [
|
||||||
|
{
|
||||||
|
"name": "mem0",
|
||||||
|
"cliCommand": "mem0",
|
||||||
|
"description": "Mem0 memory plugin commands"
|
||||||
|
}
|
||||||
|
],
|
||||||
"contracts": {
|
"contracts": {
|
||||||
"tools": [
|
"tools": [
|
||||||
"memory_search", "memory_add", "memory_get", "memory_list",
|
"memory_search", "memory_add", "memory_get", "memory_list",
|
||||||
@@ -13,7 +20,7 @@
|
|||||||
},
|
},
|
||||||
"providerAuthEnvVars": {
|
"providerAuthEnvVars": {
|
||||||
"mem0": ["MEM0_API_KEY"],
|
"mem0": ["MEM0_API_KEY"],
|
||||||
"openclaw-mem0-oss": ["OPENAI_API_KEY"]
|
"openclaw-mem0-oss": ["OPENAI_API_KEY", "ANTHROPIC_API_KEY", "AZURE_OPENAI_API_KEY", "COHERE_API_KEY"]
|
||||||
},
|
},
|
||||||
"providerAuthChoices": [
|
"providerAuthChoices": [
|
||||||
{
|
{
|
||||||
@@ -176,6 +183,9 @@
|
|||||||
},
|
},
|
||||||
"historyDbPath": {
|
"historyDbPath": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"disableHistory": {
|
||||||
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@mem0/openclaw-mem0",
|
"name": "@mem0/openclaw-mem0",
|
||||||
"version": "1.0.6",
|
"version": "1.0.7",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Mem0 memory backend for OpenClaw — platform or self-hosted open-source",
|
"description": "Mem0 memory backend for OpenClaw — platform or self-hosted open-source",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sinclair/typebox": "0.34.47",
|
"@sinclair/typebox": "0.34.47",
|
||||||
"mem0ai": "2.4.5"
|
"mem0ai": "3.0.1"
|
||||||
},
|
},
|
||||||
"openclaw": {
|
"openclaw": {
|
||||||
"extensions": [
|
"extensions": [
|
||||||
@@ -48,6 +48,9 @@
|
|||||||
"build": {
|
"build": {
|
||||||
"openclawVersion": "2026.4.1",
|
"openclawVersion": "2026.4.1",
|
||||||
"pluginSdkVersion": "2026.4.1"
|
"pluginSdkVersion": "2026.4.1"
|
||||||
|
},
|
||||||
|
"install": {
|
||||||
|
"npmSpec": "@mem0/openclaw-mem0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
Generated
+338
-118
@@ -12,8 +12,8 @@ importers:
|
|||||||
specifier: 0.34.47
|
specifier: 0.34.47
|
||||||
version: 0.34.47
|
version: 0.34.47
|
||||||
mem0ai:
|
mem0ai:
|
||||||
specifier: 2.4.5
|
specifier: 3.0.1
|
||||||
version: 2.4.5(@anthropic-ai/sdk@0.40.1)(@azure/identity@4.13.0)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260313.1)(@google/genai@1.45.0)(@langchain/core@0.3.80(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(@mistralai/mistralai@1.15.1)(@qdrant/js-client-rest@1.13.0(typescript@5.9.3))(@supabase/supabase-js@2.99.1)(@types/jest@29.5.14)(@types/pg@8.11.0)(better-sqlite3@12.8.0)(cloudflare@4.5.0)(groq-sdk@0.3.0)(neo4j-driver@5.28.3)(ollama@0.5.18)(pg@8.11.3)(redis@4.7.1)(ws@8.19.0)
|
version: 3.0.1(@anthropic-ai/sdk@0.40.1)(@azure/identity@4.13.0)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260313.1)(@google/genai@1.45.0)(@langchain/core@0.3.80(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(@mistralai/mistralai@1.15.1)(@qdrant/js-client-rest@1.13.0(typescript@5.9.3))(@supabase/supabase-js@2.99.1)(@types/jest@29.5.14)(@types/pg@8.11.0)(better-sqlite3@12.8.0)(cloudflare@4.5.0)(compromise@14.15.0)(groq-sdk@0.3.0)(natural@8.1.1)(ollama@0.5.18)(pg@8.20.0)(redis@5.12.1)(ws@8.19.0)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.15.0
|
specifier: ^22.15.0
|
||||||
@@ -340,6 +340,9 @@ packages:
|
|||||||
'@mistralai/mistralai@1.15.1':
|
'@mistralai/mistralai@1.15.1':
|
||||||
resolution: {integrity: sha512-fb995eiz3r0KsBGtRjFV+/iLbX+UpfalxpF+YitT3R6ukrPD4PN+FGwwmYcRFhNAzVzDUtTVxQYnjQWEnwV5nw==}
|
resolution: {integrity: sha512-fb995eiz3r0KsBGtRjFV+/iLbX+UpfalxpF+YitT3R6ukrPD4PN+FGwwmYcRFhNAzVzDUtTVxQYnjQWEnwV5nw==}
|
||||||
|
|
||||||
|
'@mongodb-js/saslprep@1.4.8':
|
||||||
|
resolution: {integrity: sha512-kpjr2jy2w71w0oqAMI8oibBmiF9lXxWkEQs5gMkW4hVE48bsqINGLxnCSYW62ck/NHXJQpQEfA9WlJ1sY0eqBg==}
|
||||||
|
|
||||||
'@napi-rs/wasm-runtime@1.1.1':
|
'@napi-rs/wasm-runtime@1.1.1':
|
||||||
resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==}
|
resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==}
|
||||||
|
|
||||||
@@ -394,34 +397,41 @@ packages:
|
|||||||
resolution: {integrity: sha512-oQG/FejNpItrxRHoyctYvT3rwGZOnK4jr3JdppO/c78ktDvkWiPXPHNsrDf33K9sZdRb6PR7gi4noIapu5q4HA==}
|
resolution: {integrity: sha512-oQG/FejNpItrxRHoyctYvT3rwGZOnK4jr3JdppO/c78ktDvkWiPXPHNsrDf33K9sZdRb6PR7gi4noIapu5q4HA==}
|
||||||
engines: {node: '>=18.0.0', pnpm: '>=8'}
|
engines: {node: '>=18.0.0', pnpm: '>=8'}
|
||||||
|
|
||||||
'@redis/bloom@1.2.0':
|
'@redis/bloom@5.12.1':
|
||||||
resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==}
|
resolution: {integrity: sha512-PUUfv+ms7jgPSBVoo/DN4AkPHj4D5TZSd6SbJX7egzBplkYUcKmHRE8RKia7UtZ8bSQbLguLvxVO+asKtQfZWA==}
|
||||||
|
engines: {node: '>= 18.19.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@redis/client': ^1.0.0
|
'@redis/client': ^5.12.1
|
||||||
|
|
||||||
'@redis/client@1.6.1':
|
'@redis/client@5.12.1':
|
||||||
resolution: {integrity: sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==}
|
resolution: {integrity: sha512-7aPGWeqA3uFm43o19umzdl16CEjK/JQGtSXVPevplTaOU3VJA/rseBC1QvYUz9lLDIMBimc4SW/zrW4S89BaCA==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>= 18.19.0'}
|
||||||
|
|
||||||
'@redis/graph@1.1.1':
|
|
||||||
resolution: {integrity: sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==}
|
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@redis/client': ^1.0.0
|
'@node-rs/xxhash': ^1.1.0
|
||||||
|
'@opentelemetry/api': '>=1 <2'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@node-rs/xxhash':
|
||||||
|
optional: true
|
||||||
|
'@opentelemetry/api':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@redis/json@1.0.7':
|
'@redis/json@5.12.1':
|
||||||
resolution: {integrity: sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==}
|
resolution: {integrity: sha512-eOze75esLve4vfqDel7aMX08CNaiLLQS2fV8mpRN9NxPe1rVR4vQyYiW/OgtGUysF6QOr9ANhfxABKNOJfXdKg==}
|
||||||
|
engines: {node: '>= 18.19.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@redis/client': ^1.0.0
|
'@redis/client': ^5.12.1
|
||||||
|
|
||||||
'@redis/search@1.2.0':
|
'@redis/search@5.12.1':
|
||||||
resolution: {integrity: sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==}
|
resolution: {integrity: sha512-ItlxbxC9cKI6IU1TLWoczwJCRb6TdmkEpWv05UrPawqaAnWGRu3rcIqsc5vN483T2fSociuyV1UkWIL5I4//2w==}
|
||||||
|
engines: {node: '>= 18.19.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@redis/client': ^1.0.0
|
'@redis/client': ^5.12.1
|
||||||
|
|
||||||
'@redis/time-series@1.1.0':
|
'@redis/time-series@5.12.1':
|
||||||
resolution: {integrity: sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==}
|
resolution: {integrity: sha512-c6JL6E3EcZJuNqKFz+KM+l9l5mpcQiKvTwgA3blt5glWJ8hjDk0yeHN3beE/MpqYIQ8UEX44ItQzgkE/gCBELQ==}
|
||||||
|
engines: {node: '>= 18.19.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@redis/client': ^1.0.0
|
'@redis/client': ^5.12.1
|
||||||
|
|
||||||
'@rolldown/binding-android-arm64@1.0.0-rc.9':
|
'@rolldown/binding-android-arm64@1.0.0-rc.9':
|
||||||
resolution: {integrity: sha512-lcJL0bN5hpgJfSIz/8PIf02irmyL43P+j1pTCfbD1DbLkmGRuFIA4DD3B3ZOvGqG0XiVvRznbKtN0COQVaKUTg==}
|
resolution: {integrity: sha512-lcJL0bN5hpgJfSIz/8PIf02irmyL43P+j1pTCfbD1DbLkmGRuFIA4DD3B3ZOvGqG0XiVvRznbKtN0COQVaKUTg==}
|
||||||
@@ -724,6 +734,12 @@ packages:
|
|||||||
'@types/uuid@10.0.0':
|
'@types/uuid@10.0.0':
|
||||||
resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==}
|
resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==}
|
||||||
|
|
||||||
|
'@types/webidl-conversions@7.0.3':
|
||||||
|
resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==}
|
||||||
|
|
||||||
|
'@types/whatwg-url@13.0.0':
|
||||||
|
resolution: {integrity: sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==}
|
||||||
|
|
||||||
'@types/ws@8.18.1':
|
'@types/ws@8.18.1':
|
||||||
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
|
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
|
||||||
|
|
||||||
@@ -784,6 +800,12 @@ packages:
|
|||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
afinn-165-financialmarketnews@3.0.0:
|
||||||
|
resolution: {integrity: sha512-0g9A1S3ZomFIGDTzZ0t6xmv4AuokBvBmpes8htiyHpH7N4xDmvSQL6UxL/Zcs2ypRb3VwgCscaD8Q3zEawKYhw==}
|
||||||
|
|
||||||
|
afinn-165@2.0.2:
|
||||||
|
resolution: {integrity: sha512-mJ/RLUfpXfQA6bzugv+bBsc/QYkVrKaLYeS8fWBpKbTCsonv4iuV9ET0fgReEunm9vKLkaNgnekuSNlTC3WQ1Q==}
|
||||||
|
|
||||||
agent-base@7.1.4:
|
agent-base@7.1.4:
|
||||||
resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
|
resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
@@ -815,6 +837,10 @@ packages:
|
|||||||
any-promise@1.3.0:
|
any-promise@1.3.0:
|
||||||
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
|
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
|
||||||
|
|
||||||
|
apparatus@0.0.10:
|
||||||
|
resolution: {integrity: sha512-KLy/ugo33KZA7nugtQ7O0E1c8kQ52N3IvD/XgIh4w/Nr28ypfkwDfA67F1ev4N1m5D+BOk1+b2dEJDfpj/VvZg==}
|
||||||
|
engines: {node: '>=0.2.6'}
|
||||||
|
|
||||||
assertion-error@2.0.1:
|
assertion-error@2.0.1:
|
||||||
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
|
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@@ -857,19 +883,16 @@ packages:
|
|||||||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
bson@7.2.0:
|
||||||
|
resolution: {integrity: sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
buffer-equal-constant-time@1.0.1:
|
buffer-equal-constant-time@1.0.1:
|
||||||
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
|
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
|
||||||
|
|
||||||
buffer-writer@2.0.0:
|
|
||||||
resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==}
|
|
||||||
engines: {node: '>=4'}
|
|
||||||
|
|
||||||
buffer@5.7.1:
|
buffer@5.7.1:
|
||||||
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
|
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
|
||||||
|
|
||||||
buffer@6.0.3:
|
|
||||||
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
|
|
||||||
|
|
||||||
bundle-name@4.1.0:
|
bundle-name@4.1.0:
|
||||||
resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
|
resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -936,6 +959,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
|
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
|
compromise@14.15.0:
|
||||||
|
resolution: {integrity: sha512-YEMv5JGWyqRJw5hdZqDVQF3MMlHA6TRiXreR8IYffk6xB7GA5p/8DeDzvg0Jy2tHNGpD+qJGl0+oJwA+5R/sVA==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
confbox@0.1.8:
|
confbox@0.1.8:
|
||||||
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
|
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
|
||||||
|
|
||||||
@@ -1008,6 +1035,10 @@ packages:
|
|||||||
digest-fetch@1.3.0:
|
digest-fetch@1.3.0:
|
||||||
resolution: {integrity: sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==}
|
resolution: {integrity: sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==}
|
||||||
|
|
||||||
|
dotenv@17.4.2:
|
||||||
|
resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
dunder-proto@1.0.1:
|
dunder-proto@1.0.1:
|
||||||
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -1018,6 +1049,10 @@ packages:
|
|||||||
ecdsa-sig-formatter@1.0.11:
|
ecdsa-sig-formatter@1.0.11:
|
||||||
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
|
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
|
||||||
|
|
||||||
|
efrt@2.7.0:
|
||||||
|
resolution: {integrity: sha512-/RInbCy1d4P6Zdfa+TMVsf/ufZVotat5hCw3QXmWtjU+3pFEOvOQ7ibo3aIxyCJw2leIeAMjmPj+1SLJiCpdrQ==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
emoji-regex@8.0.0:
|
emoji-regex@8.0.0:
|
||||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||||
|
|
||||||
@@ -1154,10 +1189,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==}
|
resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
generic-pool@3.9.0:
|
|
||||||
resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==}
|
|
||||||
engines: {node: '>= 4'}
|
|
||||||
|
|
||||||
get-intrinsic@1.3.0:
|
get-intrinsic@1.3.0:
|
||||||
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
|
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -1189,6 +1220,10 @@ packages:
|
|||||||
graceful-fs@4.2.11:
|
graceful-fs@4.2.11:
|
||||||
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
||||||
|
|
||||||
|
grad-school@0.0.5:
|
||||||
|
resolution: {integrity: sha512-rXunEHF9M9EkMydTBux7+IryYXEZinRk6g8OBOGDBzo/qWJjhTxy86i5q7lQYpCLHN8Sqv1XX3OIOc7ka2gtvQ==}
|
||||||
|
engines: {node: '>=8.0.0'}
|
||||||
|
|
||||||
groq-sdk@0.3.0:
|
groq-sdk@0.3.0:
|
||||||
resolution: {integrity: sha512-Cdgjh4YoSBE2X4S9sxPGXaAy1dlN4bRtAaDZ3cnq+XsxhhN9WSBeHF64l7LWwuD5ntmw7YC5Vf4Ff1oHCg1LOg==}
|
resolution: {integrity: sha512-Cdgjh4YoSBE2X4S9sxPGXaAy1dlN4bRtAaDZ3cnq+XsxhhN9WSBeHF64l7LWwuD5ntmw7YC5Vf4Ff1oHCg1LOg==}
|
||||||
|
|
||||||
@@ -1324,6 +1359,10 @@ packages:
|
|||||||
jws@4.0.1:
|
jws@4.0.1:
|
||||||
resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==}
|
resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==}
|
||||||
|
|
||||||
|
kareem@3.2.0:
|
||||||
|
resolution: {integrity: sha512-VS8MWZz/cT+SqBCpVfNN4zoVz5VskR3N4+sTmUXme55e9avQHntpwpNq0yjnosISXqwJ3AQVjlbI4Dyzv//JtA==}
|
||||||
|
engines: {node: '>=18.0.0'}
|
||||||
|
|
||||||
langsmith@0.3.87:
|
langsmith@0.3.87:
|
||||||
resolution: {integrity: sha512-XXR1+9INH8YX96FKWc5tie0QixWz6tOqAsAKfcJyPkE0xPep+NDz0IQLR32q4bn10QK3LqD2HN6T3n6z1YLW7Q==}
|
resolution: {integrity: sha512-XXR1+9INH8YX96FKWc5tie0QixWz6tOqAsAKfcJyPkE0xPep+NDz0IQLR32q4bn10QK3LqD2HN6T3n6z1YLW7Q==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1466,8 +1505,8 @@ packages:
|
|||||||
md5@2.3.0:
|
md5@2.3.0:
|
||||||
resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==}
|
resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==}
|
||||||
|
|
||||||
mem0ai@2.4.5:
|
mem0ai@3.0.1:
|
||||||
resolution: {integrity: sha512-0XMRe5/KKZXkSJDb2YDqgWdIfJpL2cn8Lelx9pvDPJOvBfXx8uHjtSc80jyGyb9C/1wW2uPcaE+WS+Rs/2phCg==}
|
resolution: {integrity: sha512-6phM544/3NRcCg7n5DBNRc9uUEMqGTe7sksULM2KM/FTihH27yTl5nPms8cnNpSKM5/ZKJ9jnkpzwGlvYYbtBQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@anthropic-ai/sdk': ^0.40.1
|
'@anthropic-ai/sdk': ^0.40.1
|
||||||
@@ -1483,12 +1522,20 @@ packages:
|
|||||||
'@types/pg': 8.11.0
|
'@types/pg': 8.11.0
|
||||||
better-sqlite3: ^12.6.2
|
better-sqlite3: ^12.6.2
|
||||||
cloudflare: ^4.2.0
|
cloudflare: ^4.2.0
|
||||||
|
compromise: ^14.0.0
|
||||||
groq-sdk: 0.3.0
|
groq-sdk: 0.3.0
|
||||||
neo4j-driver: ^5.28.1
|
natural: ^8.0.1
|
||||||
ollama: ^0.5.14
|
ollama: ^0.5.14
|
||||||
pg: 8.11.3
|
pg: 8.11.3
|
||||||
redis: ^4.6.13
|
redis: ^4.6.13
|
||||||
|
|
||||||
|
memjs@1.3.2:
|
||||||
|
resolution: {integrity: sha512-qUEg2g8vxPe+zPn09KidjIStHPtoBO8Cttm8bgJFWWabbsjQ9Av9Ky+6UcvKx6ue0LLb/LEhtcyQpRyKfzeXcg==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
memory-pager@1.5.0:
|
||||||
|
resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==}
|
||||||
|
|
||||||
micromatch@4.0.8:
|
micromatch@4.0.8:
|
||||||
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
||||||
engines: {node: '>=8.6'}
|
engines: {node: '>=8.6'}
|
||||||
@@ -1522,6 +1569,49 @@ packages:
|
|||||||
mlly@1.8.1:
|
mlly@1.8.1:
|
||||||
resolution: {integrity: sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==}
|
resolution: {integrity: sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==}
|
||||||
|
|
||||||
|
mongodb-connection-string-url@7.0.1:
|
||||||
|
resolution: {integrity: sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
|
mongodb@7.1.1:
|
||||||
|
resolution: {integrity: sha512-067DXiMjcpYQl6bGjWQoTUEE9UoRViTtKFcoqX7z08I+iDZv/emH1g8XEFiO3qiDfXAheT5ozl1VffDTKhIW/w==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@aws-sdk/credential-providers': ^3.806.0
|
||||||
|
'@mongodb-js/zstd': ^7.0.0
|
||||||
|
gcp-metadata: ^7.0.1
|
||||||
|
kerberos: ^7.0.0
|
||||||
|
mongodb-client-encryption: '>=7.0.0 <7.1.0'
|
||||||
|
snappy: ^7.3.2
|
||||||
|
socks: ^2.8.6
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@aws-sdk/credential-providers':
|
||||||
|
optional: true
|
||||||
|
'@mongodb-js/zstd':
|
||||||
|
optional: true
|
||||||
|
gcp-metadata:
|
||||||
|
optional: true
|
||||||
|
kerberos:
|
||||||
|
optional: true
|
||||||
|
mongodb-client-encryption:
|
||||||
|
optional: true
|
||||||
|
snappy:
|
||||||
|
optional: true
|
||||||
|
socks:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
mongoose@9.4.1:
|
||||||
|
resolution: {integrity: sha512-4rFBWa+/wdBQSfvnOPJBpiSG6UCEbhSQh865dEdaH9Y8WfHBUC+I2XT28dp0IBIGrEwmh+gzrgZgea5PbmrHWA==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
|
mpath@0.9.0:
|
||||||
|
resolution: {integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==}
|
||||||
|
engines: {node: '>=4.0.0'}
|
||||||
|
|
||||||
|
mquery@6.0.0:
|
||||||
|
resolution: {integrity: sha512-b2KQNsmgtkscfeDgkYMcWGn9vZI9YoXh802VDEwE6qc50zxBFQ0Oo8ROkawbPAsXCY1/Z1yp0MagqsZStPWJjw==}
|
||||||
|
engines: {node: '>=20.19.0'}
|
||||||
|
|
||||||
ms@2.1.3:
|
ms@2.1.3:
|
||||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||||
|
|
||||||
@@ -1540,14 +1630,9 @@ packages:
|
|||||||
napi-build-utils@2.0.0:
|
napi-build-utils@2.0.0:
|
||||||
resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==}
|
resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==}
|
||||||
|
|
||||||
neo4j-driver-bolt-connection@5.28.3:
|
natural@8.1.1:
|
||||||
resolution: {integrity: sha512-wqHBYcU0FVRDmdsoZ+Fk0S/InYmu9/4BT6fPYh45Jimg/J7vQBUcdkiHGU7nop7HRb1ZgJmL305mJb6g5Bv35Q==}
|
resolution: {integrity: sha512-Ucb+lsUcGxUqu3rn8cwHjT6gJQosO63nIX/aBQXB3+IDkNbFV7PuviysO+Rzz3aKn7PZhPj3bNF4PS9gDVjYCQ==}
|
||||||
|
engines: {node: '>=0.4.10'}
|
||||||
neo4j-driver-core@5.28.3:
|
|
||||||
resolution: {integrity: sha512-Jk+hAmjFmO5YzVH/U7FyKXigot9zmIfLz6SZQy0xfr4zfTE/S8fOYFOGqKQTHBE86HHOWH2RbTslbxIb+XtU2g==}
|
|
||||||
|
|
||||||
neo4j-driver@5.28.3:
|
|
||||||
resolution: {integrity: sha512-k7c0wEh3HoONv1v5AyLp9/BDAbYHJhz2TZvzWstSEU3g3suQcXmKEaYBfrK2UMzxcy3bCT0DrnfRbzsOW5G/Ag==}
|
|
||||||
|
|
||||||
node-abi@3.88.0:
|
node-abi@3.88.0:
|
||||||
resolution: {integrity: sha512-At6b4UqIEVudaqPsXjmUO1r/N5BUr4yhDGs5PkBE8/oG5+TfLPhFechiskFsnT6Ql0VfUXbalUUCbfXxtj7K+w==}
|
resolution: {integrity: sha512-At6b4UqIEVudaqPsXjmUO1r/N5BUr4yhDGs5PkBE8/oG5+TfLPhFechiskFsnT6Ql0VfUXbalUUCbfXxtj7K+w==}
|
||||||
@@ -1622,9 +1707,6 @@ packages:
|
|||||||
package-json-from-dist@1.0.1:
|
package-json-from-dist@1.0.1:
|
||||||
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
|
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
|
||||||
|
|
||||||
packet-reader@1.0.0:
|
|
||||||
resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==}
|
|
||||||
|
|
||||||
path-key@3.1.1:
|
path-key@3.1.1:
|
||||||
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -1666,9 +1748,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-o2XFanIMy/3+mThw69O8d4n1E5zsLhdO+OPqswezu7Z5ekP4hYDqlDjlmOpYMbzY2Br0ufCwJLdDIXeNVwcWFg==}
|
resolution: {integrity: sha512-o2XFanIMy/3+mThw69O8d4n1E5zsLhdO+OPqswezu7Z5ekP4hYDqlDjlmOpYMbzY2Br0ufCwJLdDIXeNVwcWFg==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
pg@8.11.3:
|
pg@8.20.0:
|
||||||
resolution: {integrity: sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==}
|
resolution: {integrity: sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==}
|
||||||
engines: {node: '>= 8.0.0'}
|
engines: {node: '>= 16.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
pg-native: '>=3.0.1'
|
pg-native: '>=3.0.1'
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
@@ -1773,6 +1855,10 @@ packages:
|
|||||||
pump@3.0.4:
|
pump@3.0.4:
|
||||||
resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==}
|
resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==}
|
||||||
|
|
||||||
|
punycode@2.3.1:
|
||||||
|
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
rc@1.2.8:
|
rc@1.2.8:
|
||||||
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -1788,8 +1874,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
|
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
|
||||||
engines: {node: '>= 14.18.0'}
|
engines: {node: '>= 14.18.0'}
|
||||||
|
|
||||||
redis@4.7.1:
|
redis@5.12.1:
|
||||||
resolution: {integrity: sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==}
|
resolution: {integrity: sha512-LDsoVvb/CpoV9EN3FXvgvSHNJWuCIzl9MiO3ppOevuGLpSGJhwfQjpEwfFJcQvNSddHADDdZaWx0HnmMxRXG7g==}
|
||||||
|
engines: {node: '>= 18.19.0'}
|
||||||
|
|
||||||
resolve-from@5.0.0:
|
resolve-from@5.0.0:
|
||||||
resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
|
resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
|
||||||
@@ -1817,12 +1904,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==}
|
resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
rxjs@7.8.2:
|
|
||||||
resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==}
|
|
||||||
|
|
||||||
safe-buffer@5.2.1:
|
safe-buffer@5.2.1:
|
||||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||||
|
|
||||||
|
safe-stable-stringify@2.5.0:
|
||||||
|
resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
semver@7.7.4:
|
semver@7.7.4:
|
||||||
resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
|
resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -1836,6 +1924,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
sift@17.1.3:
|
||||||
|
resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==}
|
||||||
|
|
||||||
siginfo@2.0.0:
|
siginfo@2.0.0:
|
||||||
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
|
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
|
||||||
|
|
||||||
@@ -1864,6 +1955,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==}
|
resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==}
|
||||||
engines: {node: '>= 12'}
|
engines: {node: '>= 12'}
|
||||||
|
|
||||||
|
sparse-bitfield@3.0.3:
|
||||||
|
resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==}
|
||||||
|
|
||||||
split2@4.2.0:
|
split2@4.2.0:
|
||||||
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
|
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
|
||||||
engines: {node: '>= 10.x'}
|
engines: {node: '>= 10.x'}
|
||||||
@@ -1878,6 +1972,10 @@ packages:
|
|||||||
std-env@4.0.0:
|
std-env@4.0.0:
|
||||||
resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==}
|
resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==}
|
||||||
|
|
||||||
|
stopwords-iso@1.1.0:
|
||||||
|
resolution: {integrity: sha512-I6GPS/E0zyieHehMRPQcqkiBMJKGgLta+1hREixhoLPqEA0AlVFiC43dl8uPpmkkeRdDMzYRWFWk5/l9x7nmNg==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
string-width@4.2.3:
|
string-width@4.2.3:
|
||||||
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -1906,10 +2004,17 @@ packages:
|
|||||||
engines: {node: '>=16 || 14 >=14.17'}
|
engines: {node: '>=16 || 14 >=14.17'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
suffix-thumb@5.0.2:
|
||||||
|
resolution: {integrity: sha512-I5PWXAFKx3FYnI9a+dQMWNqTxoRt6vdBdb0O+BJ1sxXCWtSoQCusc13E58f+9p4MYx/qCnEMkD5jac6K2j3dgA==}
|
||||||
|
|
||||||
supports-color@7.2.0:
|
supports-color@7.2.0:
|
||||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
sylvester@0.0.21:
|
||||||
|
resolution: {integrity: sha512-yUT0ukFkFEt4nb+NY+n2ag51aS/u9UHXoZw+A4jgD77/jzZsBoSDHuqysrVCBC4CYR4TYvUJq54ONpXgDBH8tA==}
|
||||||
|
engines: {node: '>=0.2.6'}
|
||||||
|
|
||||||
tar-fs@2.1.4:
|
tar-fs@2.1.4:
|
||||||
resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==}
|
resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==}
|
||||||
|
|
||||||
@@ -1949,6 +2054,10 @@ packages:
|
|||||||
tr46@0.0.3:
|
tr46@0.0.3:
|
||||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||||
|
|
||||||
|
tr46@5.1.1:
|
||||||
|
resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
tree-kill@1.2.2:
|
tree-kill@1.2.2:
|
||||||
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
|
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -1989,6 +2098,9 @@ packages:
|
|||||||
ufo@1.6.3:
|
ufo@1.6.3:
|
||||||
resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==}
|
resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==}
|
||||||
|
|
||||||
|
underscore@1.13.8:
|
||||||
|
resolution: {integrity: sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==}
|
||||||
|
|
||||||
undici-types@5.26.5:
|
undici-types@5.26.5:
|
||||||
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
|
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
|
||||||
|
|
||||||
@@ -2006,6 +2118,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
|
resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
uuid@13.0.0:
|
||||||
|
resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
uuid@8.3.2:
|
uuid@8.3.2:
|
||||||
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
|
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -2103,9 +2219,17 @@ packages:
|
|||||||
webidl-conversions@3.0.1:
|
webidl-conversions@3.0.1:
|
||||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||||
|
|
||||||
|
webidl-conversions@7.0.0:
|
||||||
|
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
whatwg-fetch@3.6.20:
|
whatwg-fetch@3.6.20:
|
||||||
resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==}
|
resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==}
|
||||||
|
|
||||||
|
whatwg-url@14.2.0:
|
||||||
|
resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
whatwg-url@5.0.0:
|
whatwg-url@5.0.0:
|
||||||
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
||||||
|
|
||||||
@@ -2119,6 +2243,10 @@ packages:
|
|||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
wordnet-db@3.1.14:
|
||||||
|
resolution: {integrity: sha512-zVyFsvE+mq9MCmwXUWHIcpfbrHHClZWZiVOzKSxNJruIcFn2RbY55zkhiAMMxM8zCVSmtNiViq8FsAZSFpMYag==}
|
||||||
|
engines: {node: '>=0.6.0'}
|
||||||
|
|
||||||
wrap-ansi@7.0.0:
|
wrap-ansi@7.0.0:
|
||||||
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -2150,9 +2278,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
|
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
|
||||||
engines: {node: '>=0.4'}
|
engines: {node: '>=0.4'}
|
||||||
|
|
||||||
yallist@4.0.0:
|
|
||||||
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
|
|
||||||
|
|
||||||
zod-to-json-schema@3.25.1:
|
zod-to-json-schema@3.25.1:
|
||||||
resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==}
|
resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2487,6 +2612,10 @@ snapshots:
|
|||||||
- bufferutil
|
- bufferutil
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
|
|
||||||
|
'@mongodb-js/saslprep@1.4.8':
|
||||||
|
dependencies:
|
||||||
|
sparse-bitfield: 3.0.3
|
||||||
|
|
||||||
'@napi-rs/wasm-runtime@1.1.1':
|
'@napi-rs/wasm-runtime@1.1.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@emnapi/core': 1.9.0
|
'@emnapi/core': 1.9.0
|
||||||
@@ -2533,31 +2662,25 @@ snapshots:
|
|||||||
|
|
||||||
'@qdrant/openapi-typescript-fetch@1.2.6': {}
|
'@qdrant/openapi-typescript-fetch@1.2.6': {}
|
||||||
|
|
||||||
'@redis/bloom@1.2.0(@redis/client@1.6.1)':
|
'@redis/bloom@5.12.1(@redis/client@5.12.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@redis/client': 1.6.1
|
'@redis/client': 5.12.1
|
||||||
|
|
||||||
'@redis/client@1.6.1':
|
'@redis/client@5.12.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
cluster-key-slot: 1.1.2
|
cluster-key-slot: 1.1.2
|
||||||
generic-pool: 3.9.0
|
|
||||||
yallist: 4.0.0
|
|
||||||
|
|
||||||
'@redis/graph@1.1.1(@redis/client@1.6.1)':
|
'@redis/json@5.12.1(@redis/client@5.12.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@redis/client': 1.6.1
|
'@redis/client': 5.12.1
|
||||||
|
|
||||||
'@redis/json@1.0.7(@redis/client@1.6.1)':
|
'@redis/search@5.12.1(@redis/client@5.12.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@redis/client': 1.6.1
|
'@redis/client': 5.12.1
|
||||||
|
|
||||||
'@redis/search@1.2.0(@redis/client@1.6.1)':
|
'@redis/time-series@5.12.1(@redis/client@5.12.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@redis/client': 1.6.1
|
'@redis/client': 5.12.1
|
||||||
|
|
||||||
'@redis/time-series@1.1.0(@redis/client@1.6.1)':
|
|
||||||
dependencies:
|
|
||||||
'@redis/client': 1.6.1
|
|
||||||
|
|
||||||
'@rolldown/binding-android-arm64@1.0.0-rc.9':
|
'@rolldown/binding-android-arm64@1.0.0-rc.9':
|
||||||
optional: true
|
optional: true
|
||||||
@@ -2785,6 +2908,12 @@ snapshots:
|
|||||||
|
|
||||||
'@types/uuid@10.0.0': {}
|
'@types/uuid@10.0.0': {}
|
||||||
|
|
||||||
|
'@types/webidl-conversions@7.0.3': {}
|
||||||
|
|
||||||
|
'@types/whatwg-url@13.0.0':
|
||||||
|
dependencies:
|
||||||
|
'@types/webidl-conversions': 7.0.3
|
||||||
|
|
||||||
'@types/ws@8.18.1':
|
'@types/ws@8.18.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 22.19.15
|
'@types/node': 22.19.15
|
||||||
@@ -2864,6 +2993,10 @@ snapshots:
|
|||||||
|
|
||||||
acorn@8.16.0: {}
|
acorn@8.16.0: {}
|
||||||
|
|
||||||
|
afinn-165-financialmarketnews@3.0.0: {}
|
||||||
|
|
||||||
|
afinn-165@2.0.2: {}
|
||||||
|
|
||||||
agent-base@7.1.4: {}
|
agent-base@7.1.4: {}
|
||||||
|
|
||||||
agentkeepalive@4.6.0:
|
agentkeepalive@4.6.0:
|
||||||
@@ -2884,6 +3017,10 @@ snapshots:
|
|||||||
|
|
||||||
any-promise@1.3.0: {}
|
any-promise@1.3.0: {}
|
||||||
|
|
||||||
|
apparatus@0.0.10:
|
||||||
|
dependencies:
|
||||||
|
sylvester: 0.0.21
|
||||||
|
|
||||||
assertion-error@2.0.1: {}
|
assertion-error@2.0.1: {}
|
||||||
|
|
||||||
ast-v8-to-istanbul@1.0.0:
|
ast-v8-to-istanbul@1.0.0:
|
||||||
@@ -2933,20 +3070,15 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fill-range: 7.1.1
|
fill-range: 7.1.1
|
||||||
|
|
||||||
|
bson@7.2.0: {}
|
||||||
|
|
||||||
buffer-equal-constant-time@1.0.1: {}
|
buffer-equal-constant-time@1.0.1: {}
|
||||||
|
|
||||||
buffer-writer@2.0.0: {}
|
|
||||||
|
|
||||||
buffer@5.7.1:
|
buffer@5.7.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
base64-js: 1.5.1
|
base64-js: 1.5.1
|
||||||
ieee754: 1.2.1
|
ieee754: 1.2.1
|
||||||
|
|
||||||
buffer@6.0.3:
|
|
||||||
dependencies:
|
|
||||||
base64-js: 1.5.1
|
|
||||||
ieee754: 1.2.1
|
|
||||||
|
|
||||||
bundle-name@4.1.0:
|
bundle-name@4.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
run-applescript: 7.1.0
|
run-applescript: 7.1.0
|
||||||
@@ -3008,6 +3140,12 @@ snapshots:
|
|||||||
|
|
||||||
commander@4.1.1: {}
|
commander@4.1.1: {}
|
||||||
|
|
||||||
|
compromise@14.15.0:
|
||||||
|
dependencies:
|
||||||
|
efrt: 2.7.0
|
||||||
|
grad-school: 0.0.5
|
||||||
|
suffix-thumb: 5.0.2
|
||||||
|
|
||||||
confbox@0.1.8: {}
|
confbox@0.1.8: {}
|
||||||
|
|
||||||
consola@3.4.2: {}
|
consola@3.4.2: {}
|
||||||
@@ -3060,6 +3198,8 @@ snapshots:
|
|||||||
base-64: 0.1.0
|
base-64: 0.1.0
|
||||||
md5: 2.3.0
|
md5: 2.3.0
|
||||||
|
|
||||||
|
dotenv@17.4.2: {}
|
||||||
|
|
||||||
dunder-proto@1.0.1:
|
dunder-proto@1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind-apply-helpers: 1.0.2
|
call-bind-apply-helpers: 1.0.2
|
||||||
@@ -3072,6 +3212,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer: 5.2.1
|
safe-buffer: 5.2.1
|
||||||
|
|
||||||
|
efrt@2.7.0: {}
|
||||||
|
|
||||||
emoji-regex@8.0.0: {}
|
emoji-regex@8.0.0: {}
|
||||||
|
|
||||||
emoji-regex@9.2.2: {}
|
emoji-regex@9.2.2: {}
|
||||||
@@ -3223,8 +3365,6 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
generic-pool@3.9.0: {}
|
|
||||||
|
|
||||||
get-intrinsic@1.3.0:
|
get-intrinsic@1.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind-apply-helpers: 1.0.2
|
call-bind-apply-helpers: 1.0.2
|
||||||
@@ -3271,6 +3411,8 @@ snapshots:
|
|||||||
|
|
||||||
graceful-fs@4.2.11: {}
|
graceful-fs@4.2.11: {}
|
||||||
|
|
||||||
|
grad-school@0.0.5: {}
|
||||||
|
|
||||||
groq-sdk@0.3.0:
|
groq-sdk@0.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 18.19.130
|
'@types/node': 18.19.130
|
||||||
@@ -3437,6 +3579,8 @@ snapshots:
|
|||||||
jwa: 2.0.1
|
jwa: 2.0.1
|
||||||
safe-buffer: 5.2.1
|
safe-buffer: 5.2.1
|
||||||
|
|
||||||
|
kareem@3.2.0: {}
|
||||||
|
|
||||||
langsmith@0.3.87(openai@4.104.0(ws@8.19.0)(zod@3.25.76)):
|
langsmith@0.3.87(openai@4.104.0(ws@8.19.0)(zod@3.25.76)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/uuid': 10.0.0
|
'@types/uuid': 10.0.0
|
||||||
@@ -3543,7 +3687,7 @@ snapshots:
|
|||||||
crypt: 0.0.2
|
crypt: 0.0.2
|
||||||
is-buffer: 1.1.6
|
is-buffer: 1.1.6
|
||||||
|
|
||||||
mem0ai@2.4.5(@anthropic-ai/sdk@0.40.1)(@azure/identity@4.13.0)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260313.1)(@google/genai@1.45.0)(@langchain/core@0.3.80(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(@mistralai/mistralai@1.15.1)(@qdrant/js-client-rest@1.13.0(typescript@5.9.3))(@supabase/supabase-js@2.99.1)(@types/jest@29.5.14)(@types/pg@8.11.0)(better-sqlite3@12.8.0)(cloudflare@4.5.0)(groq-sdk@0.3.0)(neo4j-driver@5.28.3)(ollama@0.5.18)(pg@8.11.3)(redis@4.7.1)(ws@8.19.0):
|
mem0ai@3.0.1(@anthropic-ai/sdk@0.40.1)(@azure/identity@4.13.0)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260313.1)(@google/genai@1.45.0)(@langchain/core@0.3.80(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(@mistralai/mistralai@1.15.1)(@qdrant/js-client-rest@1.13.0(typescript@5.9.3))(@supabase/supabase-js@2.99.1)(@types/jest@29.5.14)(@types/pg@8.11.0)(better-sqlite3@12.8.0)(cloudflare@4.5.0)(compromise@14.15.0)(groq-sdk@0.3.0)(natural@8.1.1)(ollama@0.5.18)(pg@8.20.0)(redis@5.12.1)(ws@8.19.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@anthropic-ai/sdk': 0.40.1
|
'@anthropic-ai/sdk': 0.40.1
|
||||||
'@azure/identity': 4.13.0
|
'@azure/identity': 4.13.0
|
||||||
@@ -3559,12 +3703,13 @@ snapshots:
|
|||||||
axios: 1.13.6
|
axios: 1.13.6
|
||||||
better-sqlite3: 12.8.0
|
better-sqlite3: 12.8.0
|
||||||
cloudflare: 4.5.0
|
cloudflare: 4.5.0
|
||||||
|
compromise: 14.15.0
|
||||||
groq-sdk: 0.3.0
|
groq-sdk: 0.3.0
|
||||||
neo4j-driver: 5.28.3
|
natural: 8.1.1
|
||||||
ollama: 0.5.18
|
ollama: 0.5.18
|
||||||
openai: 4.104.0(ws@8.19.0)(zod@3.25.76)
|
openai: 4.104.0(ws@8.19.0)(zod@3.25.76)
|
||||||
pg: 8.11.3
|
pg: 8.20.0
|
||||||
redis: 4.7.1
|
redis: 5.12.1
|
||||||
uuid: 9.0.1
|
uuid: 9.0.1
|
||||||
zod: 3.25.76
|
zod: 3.25.76
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -3572,6 +3717,10 @@ snapshots:
|
|||||||
- encoding
|
- encoding
|
||||||
- ws
|
- ws
|
||||||
|
|
||||||
|
memjs@1.3.2: {}
|
||||||
|
|
||||||
|
memory-pager@1.5.0: {}
|
||||||
|
|
||||||
micromatch@4.0.8:
|
micromatch@4.0.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
braces: 3.0.3
|
braces: 3.0.3
|
||||||
@@ -3602,6 +3751,38 @@ snapshots:
|
|||||||
pkg-types: 1.3.1
|
pkg-types: 1.3.1
|
||||||
ufo: 1.6.3
|
ufo: 1.6.3
|
||||||
|
|
||||||
|
mongodb-connection-string-url@7.0.1:
|
||||||
|
dependencies:
|
||||||
|
'@types/whatwg-url': 13.0.0
|
||||||
|
whatwg-url: 14.2.0
|
||||||
|
|
||||||
|
mongodb@7.1.1:
|
||||||
|
dependencies:
|
||||||
|
'@mongodb-js/saslprep': 1.4.8
|
||||||
|
bson: 7.2.0
|
||||||
|
mongodb-connection-string-url: 7.0.1
|
||||||
|
|
||||||
|
mongoose@9.4.1:
|
||||||
|
dependencies:
|
||||||
|
kareem: 3.2.0
|
||||||
|
mongodb: 7.1.1
|
||||||
|
mpath: 0.9.0
|
||||||
|
mquery: 6.0.0
|
||||||
|
ms: 2.1.3
|
||||||
|
sift: 17.1.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@aws-sdk/credential-providers'
|
||||||
|
- '@mongodb-js/zstd'
|
||||||
|
- gcp-metadata
|
||||||
|
- kerberos
|
||||||
|
- mongodb-client-encryption
|
||||||
|
- snappy
|
||||||
|
- socks
|
||||||
|
|
||||||
|
mpath@0.9.0: {}
|
||||||
|
|
||||||
|
mquery@6.0.0: {}
|
||||||
|
|
||||||
ms@2.1.3: {}
|
ms@2.1.3: {}
|
||||||
|
|
||||||
mustache@4.2.0: {}
|
mustache@4.2.0: {}
|
||||||
@@ -3616,19 +3797,33 @@ snapshots:
|
|||||||
|
|
||||||
napi-build-utils@2.0.0: {}
|
napi-build-utils@2.0.0: {}
|
||||||
|
|
||||||
neo4j-driver-bolt-connection@5.28.3:
|
natural@8.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
buffer: 6.0.3
|
afinn-165: 2.0.2
|
||||||
neo4j-driver-core: 5.28.3
|
afinn-165-financialmarketnews: 3.0.0
|
||||||
string_decoder: 1.3.0
|
apparatus: 0.0.10
|
||||||
|
dotenv: 17.4.2
|
||||||
neo4j-driver-core@5.28.3: {}
|
memjs: 1.3.2
|
||||||
|
mongoose: 9.4.1
|
||||||
neo4j-driver@5.28.3:
|
pg: 8.20.0
|
||||||
dependencies:
|
redis: 5.12.1
|
||||||
neo4j-driver-bolt-connection: 5.28.3
|
safe-stable-stringify: 2.5.0
|
||||||
neo4j-driver-core: 5.28.3
|
stopwords-iso: 1.1.0
|
||||||
rxjs: 7.8.2
|
sylvester: 0.0.21
|
||||||
|
underscore: 1.13.8
|
||||||
|
uuid: 13.0.0
|
||||||
|
wordnet-db: 3.1.14
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@aws-sdk/credential-providers'
|
||||||
|
- '@mongodb-js/zstd'
|
||||||
|
- '@node-rs/xxhash'
|
||||||
|
- '@opentelemetry/api'
|
||||||
|
- gcp-metadata
|
||||||
|
- kerberos
|
||||||
|
- mongodb-client-encryption
|
||||||
|
- pg-native
|
||||||
|
- snappy
|
||||||
|
- socks
|
||||||
|
|
||||||
node-abi@3.88.0:
|
node-abi@3.88.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3700,8 +3895,6 @@ snapshots:
|
|||||||
|
|
||||||
package-json-from-dist@1.0.1: {}
|
package-json-from-dist@1.0.1: {}
|
||||||
|
|
||||||
packet-reader@1.0.0: {}
|
|
||||||
|
|
||||||
path-key@3.1.1: {}
|
path-key@3.1.1: {}
|
||||||
|
|
||||||
path-scurry@1.11.1:
|
path-scurry@1.11.1:
|
||||||
@@ -3720,9 +3913,9 @@ snapshots:
|
|||||||
|
|
||||||
pg-numeric@1.0.2: {}
|
pg-numeric@1.0.2: {}
|
||||||
|
|
||||||
pg-pool@3.13.0(pg@8.11.3):
|
pg-pool@3.13.0(pg@8.20.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
pg: 8.11.3
|
pg: 8.20.0
|
||||||
|
|
||||||
pg-protocol@1.13.0: {}
|
pg-protocol@1.13.0: {}
|
||||||
|
|
||||||
@@ -3744,12 +3937,10 @@ snapshots:
|
|||||||
postgres-interval: 3.0.0
|
postgres-interval: 3.0.0
|
||||||
postgres-range: 1.1.4
|
postgres-range: 1.1.4
|
||||||
|
|
||||||
pg@8.11.3:
|
pg@8.20.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
buffer-writer: 2.0.0
|
|
||||||
packet-reader: 1.0.0
|
|
||||||
pg-connection-string: 2.12.0
|
pg-connection-string: 2.12.0
|
||||||
pg-pool: 3.13.0(pg@8.11.3)
|
pg-pool: 3.13.0(pg@8.20.0)
|
||||||
pg-protocol: 1.13.0
|
pg-protocol: 1.13.0
|
||||||
pg-types: 2.2.0
|
pg-types: 2.2.0
|
||||||
pgpass: 1.0.5
|
pgpass: 1.0.5
|
||||||
@@ -3851,6 +4042,8 @@ snapshots:
|
|||||||
end-of-stream: 1.4.5
|
end-of-stream: 1.4.5
|
||||||
once: 1.4.0
|
once: 1.4.0
|
||||||
|
|
||||||
|
punycode@2.3.1: {}
|
||||||
|
|
||||||
rc@1.2.8:
|
rc@1.2.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
deep-extend: 0.6.0
|
deep-extend: 0.6.0
|
||||||
@@ -3868,14 +4061,16 @@ snapshots:
|
|||||||
|
|
||||||
readdirp@4.1.2: {}
|
readdirp@4.1.2: {}
|
||||||
|
|
||||||
redis@4.7.1:
|
redis@5.12.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@redis/bloom': 1.2.0(@redis/client@1.6.1)
|
'@redis/bloom': 5.12.1(@redis/client@5.12.1)
|
||||||
'@redis/client': 1.6.1
|
'@redis/client': 5.12.1
|
||||||
'@redis/graph': 1.1.1(@redis/client@1.6.1)
|
'@redis/json': 5.12.1(@redis/client@5.12.1)
|
||||||
'@redis/json': 1.0.7(@redis/client@1.6.1)
|
'@redis/search': 5.12.1(@redis/client@5.12.1)
|
||||||
'@redis/search': 1.2.0(@redis/client@1.6.1)
|
'@redis/time-series': 5.12.1(@redis/client@5.12.1)
|
||||||
'@redis/time-series': 1.1.0(@redis/client@1.6.1)
|
transitivePeerDependencies:
|
||||||
|
- '@node-rs/xxhash'
|
||||||
|
- '@opentelemetry/api'
|
||||||
|
|
||||||
resolve-from@5.0.0: {}
|
resolve-from@5.0.0: {}
|
||||||
|
|
||||||
@@ -3939,12 +4134,10 @@ snapshots:
|
|||||||
|
|
||||||
run-applescript@7.1.0: {}
|
run-applescript@7.1.0: {}
|
||||||
|
|
||||||
rxjs@7.8.2:
|
|
||||||
dependencies:
|
|
||||||
tslib: 2.8.1
|
|
||||||
|
|
||||||
safe-buffer@5.2.1: {}
|
safe-buffer@5.2.1: {}
|
||||||
|
|
||||||
|
safe-stable-stringify@2.5.0: {}
|
||||||
|
|
||||||
semver@7.7.4: {}
|
semver@7.7.4: {}
|
||||||
|
|
||||||
shebang-command@2.0.0:
|
shebang-command@2.0.0:
|
||||||
@@ -3953,6 +4146,8 @@ snapshots:
|
|||||||
|
|
||||||
shebang-regex@3.0.0: {}
|
shebang-regex@3.0.0: {}
|
||||||
|
|
||||||
|
sift@17.1.3: {}
|
||||||
|
|
||||||
siginfo@2.0.0: {}
|
siginfo@2.0.0: {}
|
||||||
|
|
||||||
signal-exit@4.1.0: {}
|
signal-exit@4.1.0: {}
|
||||||
@@ -3973,6 +4168,10 @@ snapshots:
|
|||||||
|
|
||||||
source-map@0.7.6: {}
|
source-map@0.7.6: {}
|
||||||
|
|
||||||
|
sparse-bitfield@3.0.3:
|
||||||
|
dependencies:
|
||||||
|
memory-pager: 1.5.0
|
||||||
|
|
||||||
split2@4.2.0: {}
|
split2@4.2.0: {}
|
||||||
|
|
||||||
stack-utils@2.0.6:
|
stack-utils@2.0.6:
|
||||||
@@ -3983,6 +4182,8 @@ snapshots:
|
|||||||
|
|
||||||
std-env@4.0.0: {}
|
std-env@4.0.0: {}
|
||||||
|
|
||||||
|
stopwords-iso@1.1.0: {}
|
||||||
|
|
||||||
string-width@4.2.3:
|
string-width@4.2.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
emoji-regex: 8.0.0
|
emoji-regex: 8.0.0
|
||||||
@@ -4019,10 +4220,14 @@ snapshots:
|
|||||||
tinyglobby: 0.2.15
|
tinyglobby: 0.2.15
|
||||||
ts-interface-checker: 0.1.13
|
ts-interface-checker: 0.1.13
|
||||||
|
|
||||||
|
suffix-thumb@5.0.2: {}
|
||||||
|
|
||||||
supports-color@7.2.0:
|
supports-color@7.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
has-flag: 4.0.0
|
has-flag: 4.0.0
|
||||||
|
|
||||||
|
sylvester@0.0.21: {}
|
||||||
|
|
||||||
tar-fs@2.1.4:
|
tar-fs@2.1.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
chownr: 1.1.4
|
chownr: 1.1.4
|
||||||
@@ -4065,6 +4270,10 @@ snapshots:
|
|||||||
|
|
||||||
tr46@0.0.3: {}
|
tr46@0.0.3: {}
|
||||||
|
|
||||||
|
tr46@5.1.1:
|
||||||
|
dependencies:
|
||||||
|
punycode: 2.3.1
|
||||||
|
|
||||||
tree-kill@1.2.2: {}
|
tree-kill@1.2.2: {}
|
||||||
|
|
||||||
ts-interface-checker@0.1.13: {}
|
ts-interface-checker@0.1.13: {}
|
||||||
@@ -4107,6 +4316,8 @@ snapshots:
|
|||||||
|
|
||||||
ufo@1.6.3: {}
|
ufo@1.6.3: {}
|
||||||
|
|
||||||
|
underscore@1.13.8: {}
|
||||||
|
|
||||||
undici-types@5.26.5: {}
|
undici-types@5.26.5: {}
|
||||||
|
|
||||||
undici-types@6.21.0: {}
|
undici-types@6.21.0: {}
|
||||||
@@ -4119,6 +4330,8 @@ snapshots:
|
|||||||
|
|
||||||
uuid@10.0.0: {}
|
uuid@10.0.0: {}
|
||||||
|
|
||||||
|
uuid@13.0.0: {}
|
||||||
|
|
||||||
uuid@8.3.2: {}
|
uuid@8.3.2: {}
|
||||||
|
|
||||||
uuid@9.0.1: {}
|
uuid@9.0.1: {}
|
||||||
@@ -4169,8 +4382,15 @@ snapshots:
|
|||||||
|
|
||||||
webidl-conversions@3.0.1: {}
|
webidl-conversions@3.0.1: {}
|
||||||
|
|
||||||
|
webidl-conversions@7.0.0: {}
|
||||||
|
|
||||||
whatwg-fetch@3.6.20: {}
|
whatwg-fetch@3.6.20: {}
|
||||||
|
|
||||||
|
whatwg-url@14.2.0:
|
||||||
|
dependencies:
|
||||||
|
tr46: 5.1.1
|
||||||
|
webidl-conversions: 7.0.0
|
||||||
|
|
||||||
whatwg-url@5.0.0:
|
whatwg-url@5.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
tr46: 0.0.3
|
tr46: 0.0.3
|
||||||
@@ -4185,6 +4405,8 @@ snapshots:
|
|||||||
siginfo: 2.0.0
|
siginfo: 2.0.0
|
||||||
stackback: 0.0.2
|
stackback: 0.0.2
|
||||||
|
|
||||||
|
wordnet-db@3.1.14: {}
|
||||||
|
|
||||||
wrap-ansi@7.0.0:
|
wrap-ansi@7.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
ansi-styles: 4.3.0
|
ansi-styles: 4.3.0
|
||||||
@@ -4207,8 +4429,6 @@ snapshots:
|
|||||||
|
|
||||||
xtend@4.0.2: {}
|
xtend@4.0.2: {}
|
||||||
|
|
||||||
yallist@4.0.0: {}
|
|
||||||
|
|
||||||
zod-to-json-schema@3.25.1(zod@3.25.76):
|
zod-to-json-schema@3.25.1(zod@3.25.76):
|
||||||
dependencies:
|
dependencies:
|
||||||
zod: 3.25.76
|
zod: 3.25.76
|
||||||
|
|||||||
+61
-55
@@ -111,21 +111,19 @@ class PlatformProvider implements Mem0Provider {
|
|||||||
options: AddOptions,
|
options: AddOptions,
|
||||||
): Promise<AddResult> {
|
): Promise<AddResult> {
|
||||||
await this.ensureClient();
|
await this.ensureClient();
|
||||||
const opts: Record<string, unknown> = { user_id: options.user_id };
|
// v3.0.0: SDK uses camelCase (userId, runId, etc.) - it converts to snake_case internally
|
||||||
if (options.run_id) opts.run_id = options.run_id;
|
const opts: Record<string, unknown> = { userId: options.user_id };
|
||||||
|
if (options.run_id) opts.runId = options.run_id;
|
||||||
if (options.custom_instructions)
|
if (options.custom_instructions)
|
||||||
opts.custom_instructions = options.custom_instructions;
|
opts.customInstructions = options.custom_instructions;
|
||||||
if (options.custom_categories)
|
if (options.custom_categories)
|
||||||
opts.custom_categories = options.custom_categories;
|
opts.customCategories = options.custom_categories;
|
||||||
if (options.output_format) opts.output_format = options.output_format;
|
|
||||||
if (options.source) opts.source = options.source;
|
if (options.source) opts.source = options.source;
|
||||||
// Agentic harness: direct storage bypass
|
// Agentic harness: direct storage bypass
|
||||||
if (options.infer !== undefined) opts.infer = options.infer;
|
if (options.infer !== undefined) opts.infer = options.infer;
|
||||||
if (options.deduced_memories)
|
if (options.deduced_memories)
|
||||||
opts.deduced_memories = options.deduced_memories;
|
opts.deducedMemories = options.deduced_memories;
|
||||||
if (options.metadata) opts.metadata = options.metadata;
|
if (options.metadata) opts.metadata = options.metadata;
|
||||||
if (options.expiration_date) opts.expiration_date = options.expiration_date;
|
|
||||||
if (options.immutable) opts.immutable = options.immutable;
|
|
||||||
|
|
||||||
const result = await this.client.add(messages, opts);
|
const result = await this.client.add(messages, opts);
|
||||||
return normalizeAddResult(result);
|
return normalizeAddResult(result);
|
||||||
@@ -133,19 +131,15 @@ class PlatformProvider implements Mem0Provider {
|
|||||||
|
|
||||||
async search(query: string, options: SearchOptions): Promise<MemoryItem[]> {
|
async search(query: string, options: SearchOptions): Promise<MemoryItem[]> {
|
||||||
await this.ensureClient();
|
await this.ensureClient();
|
||||||
const opts: Record<string, unknown> = {
|
// v3.0.0: SDK uses camelCase options, userId must be in filters
|
||||||
api_version: "v2",
|
const opts: Record<string, unknown> = {};
|
||||||
user_id: options.user_id,
|
if (options.top_k != null) opts.topK = options.top_k;
|
||||||
};
|
|
||||||
if (options.run_id) opts.run_id = options.run_id;
|
|
||||||
if (options.top_k != null) opts.top_k = options.top_k;
|
|
||||||
if (options.threshold != null) opts.threshold = options.threshold;
|
if (options.threshold != null) opts.threshold = options.threshold;
|
||||||
if (options.keyword_search != null)
|
|
||||||
opts.keyword_search = options.keyword_search;
|
|
||||||
if (options.reranking != null) opts.rerank = options.reranking;
|
|
||||||
if (options.filter_memories != null)
|
|
||||||
opts.filter_memories = options.filter_memories;
|
|
||||||
if (options.categories != null) opts.categories = options.categories;
|
if (options.categories != null) opts.categories = options.categories;
|
||||||
|
|
||||||
|
// Build filters with user_id/run_id inside (v3.0.0 requirement)
|
||||||
|
// Filters use snake_case as they're passed directly to the API
|
||||||
|
// Note: source is NOT a valid filter field - only used when adding
|
||||||
const baseFilters: Record<string, unknown> = { user_id: options.user_id };
|
const baseFilters: Record<string, unknown> = { user_id: options.user_id };
|
||||||
if (options.run_id) baseFilters.run_id = options.run_id;
|
if (options.run_id) baseFilters.run_id = options.run_id;
|
||||||
|
|
||||||
@@ -167,16 +161,14 @@ class PlatformProvider implements Mem0Provider {
|
|||||||
|
|
||||||
async getAll(options: ListOptions): Promise<MemoryItem[]> {
|
async getAll(options: ListOptions): Promise<MemoryItem[]> {
|
||||||
await this.ensureClient();
|
await this.ensureClient();
|
||||||
const opts: Record<string, unknown> = {
|
// v3.0.0: SDK uses camelCase options, userId must be in filters
|
||||||
api_version: "v2",
|
// Filters use snake_case as they're passed directly to the API
|
||||||
user_id: options.user_id,
|
// Note: source is NOT a valid filter field - only used when adding
|
||||||
filters: { user_id: options.user_id },
|
const filters: Record<string, unknown> = { user_id: options.user_id };
|
||||||
};
|
if (options.run_id) filters.run_id = options.run_id;
|
||||||
if (options.run_id) {
|
|
||||||
opts.run_id = options.run_id;
|
const opts: Record<string, unknown> = { filters };
|
||||||
(opts.filters as Record<string, unknown>).run_id = options.run_id;
|
if (options.page_size != null) opts.pageSize = options.page_size;
|
||||||
}
|
|
||||||
if (options.page_size != null) opts.page_size = options.page_size;
|
|
||||||
|
|
||||||
const results = await this.client.getAll(opts);
|
const results = await this.client.getAll(opts);
|
||||||
if (Array.isArray(results)) return results.map(normalizeMemoryItem);
|
if (Array.isArray(results)) return results.map(normalizeMemoryItem);
|
||||||
@@ -198,7 +190,8 @@ class PlatformProvider implements Mem0Provider {
|
|||||||
|
|
||||||
async deleteAll(userId: string): Promise<void> {
|
async deleteAll(userId: string): Promise<void> {
|
||||||
await this.ensureClient();
|
await this.ensureClient();
|
||||||
await this.client.deleteAll({ user_id: userId });
|
// v3.0.0: SDK uses camelCase
|
||||||
|
await this.client.deleteAll({ userId });
|
||||||
}
|
}
|
||||||
|
|
||||||
async history(memoryId: string): Promise<
|
async history(memoryId: string): Promise<
|
||||||
@@ -226,7 +219,7 @@ class OSSProvider implements Mem0Provider {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly ossConfig?: Mem0Config["oss"],
|
private readonly ossConfig?: Mem0Config["oss"],
|
||||||
private readonly customPrompt?: string,
|
private readonly customInstructions?: string,
|
||||||
private readonly resolvePath?: (p: string) => string,
|
private readonly resolvePath?: (p: string) => string,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -241,7 +234,8 @@ class OSSProvider implements Mem0Provider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _buildConfig(disableHistory = false): Record<string, unknown> {
|
private _buildConfig(disableHistory = false): Record<string, unknown> {
|
||||||
const config: Record<string, unknown> = { version: "v1.1" };
|
// v3.0.0: removed version field
|
||||||
|
const config: Record<string, unknown> = {};
|
||||||
|
|
||||||
const defaultEmbedder = {
|
const defaultEmbedder = {
|
||||||
provider: "openai",
|
provider: "openai",
|
||||||
@@ -299,7 +293,8 @@ class OSSProvider implements Mem0Provider {
|
|||||||
config.disableHistory = true;
|
config.disableHistory = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.customPrompt) config.customPrompt = this.customPrompt;
|
// v3.0.0: customPrompt renamed to customInstructions
|
||||||
|
if (this.customInstructions) config.customInstructions = this.customInstructions;
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,7 +342,8 @@ class OSSProvider implements Mem0Provider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await mem.getAll({ userId: "__mem0_warmup__" });
|
// v3.0.0: entity IDs must be in filters, not top-level
|
||||||
|
await mem.getAll({ filters: { user_id: "__mem0_warmup__" } });
|
||||||
|
|
||||||
this.memory = mem;
|
this.memory = mem;
|
||||||
}
|
}
|
||||||
@@ -364,9 +360,7 @@ class OSSProvider implements Mem0Provider {
|
|||||||
// Agentic harness: direct storage bypass
|
// Agentic harness: direct storage bypass
|
||||||
if (options.infer !== undefined) addOpts.infer = options.infer;
|
if (options.infer !== undefined) addOpts.infer = options.infer;
|
||||||
if (options.metadata) addOpts.metadata = options.metadata;
|
if (options.metadata) addOpts.metadata = options.metadata;
|
||||||
if (options.expiration_date)
|
// v3.0.0: removed expiration_date, immutable
|
||||||
addOpts.expirationDate = options.expiration_date;
|
|
||||||
if (options.immutable) addOpts.immutable = options.immutable;
|
|
||||||
|
|
||||||
// OSS SDK doesn't support deduced_memories — when infer=false, it stores
|
// OSS SDK doesn't support deduced_memories — when infer=false, it stores
|
||||||
// raw message content directly. Rewrite messages to contain the facts so
|
// raw message content directly. Rewrite messages to contain the facts so
|
||||||
@@ -385,17 +379,24 @@ class OSSProvider implements Mem0Provider {
|
|||||||
|
|
||||||
async search(query: string, options: SearchOptions): Promise<MemoryItem[]> {
|
async search(query: string, options: SearchOptions): Promise<MemoryItem[]> {
|
||||||
await this.ensureMemory();
|
await this.ensureMemory();
|
||||||
// OSS SDK uses camelCase: userId/runId, not user_id/run_id
|
// v3.0.0: entity IDs must be in filters, not top-level; limit renamed to topK
|
||||||
const opts: Record<string, unknown> = { userId: options.user_id };
|
const opts: Record<string, unknown> = {};
|
||||||
if (options.run_id) opts.runId = options.run_id;
|
if (options.top_k != null) opts.topK = options.top_k;
|
||||||
if (options.limit != null) opts.limit = options.limit;
|
|
||||||
else if (options.top_k != null) opts.limit = options.top_k;
|
|
||||||
if (options.keyword_search != null)
|
|
||||||
opts.keyword_search = options.keyword_search;
|
|
||||||
if (options.reranking != null) opts.reranking = options.reranking;
|
|
||||||
if (options.source) opts.source = options.source;
|
|
||||||
if (options.threshold != null) opts.threshold = options.threshold;
|
if (options.threshold != null) opts.threshold = options.threshold;
|
||||||
|
|
||||||
|
// Build filters with user_id/run_id inside (v3.0.0 requirement)
|
||||||
|
// Filters use snake_case as they're passed directly to the vector store
|
||||||
|
// Note: source is NOT a valid filter field - only used when adding
|
||||||
|
const baseFilters: Record<string, unknown> = { user_id: options.user_id };
|
||||||
|
if (options.run_id) baseFilters.run_id = options.run_id;
|
||||||
|
|
||||||
|
// Merge with any additional user-provided filters
|
||||||
|
if (options.filters) {
|
||||||
|
opts.filters = { AND: [baseFilters, options.filters] };
|
||||||
|
} else {
|
||||||
|
opts.filters = baseFilters;
|
||||||
|
}
|
||||||
|
|
||||||
const results = await this.memory.search(query, opts);
|
const results = await this.memory.search(query, opts);
|
||||||
const normalized = normalizeSearchResults(results);
|
const normalized = normalizeSearchResults(results);
|
||||||
|
|
||||||
@@ -417,10 +418,16 @@ class OSSProvider implements Mem0Provider {
|
|||||||
|
|
||||||
async getAll(options: ListOptions): Promise<MemoryItem[]> {
|
async getAll(options: ListOptions): Promise<MemoryItem[]> {
|
||||||
await this.ensureMemory();
|
await this.ensureMemory();
|
||||||
// OSS SDK uses camelCase: userId/runId, not user_id/run_id
|
// v3.0.0: entity IDs must be in filters, not top-level
|
||||||
const getAllOpts: Record<string, unknown> = { userId: options.user_id };
|
// Filters use snake_case as they're passed directly to the vector store
|
||||||
if (options.run_id) getAllOpts.runId = options.run_id;
|
// Note: source is NOT a valid filter field - only used when adding
|
||||||
if (options.source) getAllOpts.source = options.source;
|
const filters: Record<string, unknown> = { user_id: options.user_id };
|
||||||
|
if (options.run_id) filters.run_id = options.run_id;
|
||||||
|
|
||||||
|
// OSS SDK uses topK for limiting results (not pageSize like Platform)
|
||||||
|
const getAllOpts: Record<string, unknown> = { filters };
|
||||||
|
if (options.page_size != null) getAllOpts.topK = options.page_size;
|
||||||
|
|
||||||
const results = await this.memory.getAll(getAllOpts);
|
const results = await this.memory.getAll(getAllOpts);
|
||||||
if (Array.isArray(results)) return results.map(normalizeMemoryItem);
|
if (Array.isArray(results)) return results.map(normalizeMemoryItem);
|
||||||
if (results?.results && Array.isArray(results.results))
|
if (results?.results && Array.isArray(results.results))
|
||||||
@@ -476,7 +483,8 @@ export function createProvider(
|
|||||||
api: OpenClawPluginApi,
|
api: OpenClawPluginApi,
|
||||||
): Mem0Provider {
|
): Mem0Provider {
|
||||||
if (cfg.mode === "open-source") {
|
if (cfg.mode === "open-source") {
|
||||||
return new OSSProvider(cfg.oss, cfg.customPrompt, (p) =>
|
// v3.0.0: use customInstructions (was customPrompt)
|
||||||
|
return new OSSProvider(cfg.oss, cfg.customInstructions, (p) =>
|
||||||
api.resolvePath(p),
|
api.resolvePath(p),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -502,6 +510,7 @@ export function providerToBackend(
|
|||||||
return {
|
return {
|
||||||
async add(content, messages, opts = {}) {
|
async add(content, messages, opts = {}) {
|
||||||
const msgs = messages ?? (content ? [{ role: "user", content }] : []);
|
const msgs = messages ?? (content ? [{ role: "user", content }] : []);
|
||||||
|
// v3.0.0: removed immutable, expiration_date
|
||||||
const result = await provider.add(
|
const result = await provider.add(
|
||||||
msgs as Array<{ role: string; content: string }>,
|
msgs as Array<{ role: string; content: string }>,
|
||||||
{
|
{
|
||||||
@@ -509,21 +518,18 @@ export function providerToBackend(
|
|||||||
source: "OPENCLAW",
|
source: "OPENCLAW",
|
||||||
...(opts.runId && { run_id: opts.runId }),
|
...(opts.runId && { run_id: opts.runId }),
|
||||||
...(opts.metadata && { metadata: opts.metadata }),
|
...(opts.metadata && { metadata: opts.metadata }),
|
||||||
...(opts.immutable && { immutable: true }),
|
|
||||||
...(opts.infer === false && { infer: false }),
|
...(opts.infer === false && { infer: false }),
|
||||||
...(opts.expires && { expiration_date: opts.expires }),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return result as unknown as Record<string, unknown>;
|
return result as unknown as Record<string, unknown>;
|
||||||
},
|
},
|
||||||
|
|
||||||
async search(query, opts = {}) {
|
async search(query, opts = {}) {
|
||||||
|
// v3.0.0: removed keyword_search, reranking
|
||||||
const results = await provider.search(query, {
|
const results = await provider.search(query, {
|
||||||
user_id: opts.userId ?? userId,
|
user_id: opts.userId ?? userId,
|
||||||
top_k: opts.topK,
|
top_k: opts.topK,
|
||||||
threshold: opts.threshold,
|
threshold: opts.threshold,
|
||||||
keyword_search: opts.keyword,
|
|
||||||
reranking: opts.rerank,
|
|
||||||
filters: opts.filters,
|
filters: opts.filters,
|
||||||
source: "OPENCLAW",
|
source: "OPENCLAW",
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
/**
|
||||||
|
* Public Artifacts Provider for OpenClaw memory-wiki bridge mode.
|
||||||
|
*
|
||||||
|
* Exposes Mem0 memories and dream state as artifacts that can be
|
||||||
|
* consumed by other plugins (e.g., memory-wiki in bridge mode).
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { Mem0Provider, MemoryItem, Mem0Config } from "./types.ts";
|
||||||
|
import type { MemoryArtifact } from "openclaw/plugin-sdk";
|
||||||
|
import { getDreamState } from "./dream-gate.ts";
|
||||||
|
|
||||||
|
export interface PublicArtifactsContext {
|
||||||
|
provider: Mem0Provider;
|
||||||
|
cfg: Mem0Config;
|
||||||
|
stateDir?: string;
|
||||||
|
effectiveUserId: (sessionKey?: string) => string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a publicArtifacts provider that exposes Mem0 data to other plugins.
|
||||||
|
*/
|
||||||
|
export function createPublicArtifactsProvider(ctx: PublicArtifactsContext) {
|
||||||
|
return {
|
||||||
|
async listArtifacts(options?: {
|
||||||
|
userId?: string;
|
||||||
|
types?: string[];
|
||||||
|
limit?: number;
|
||||||
|
}): Promise<MemoryArtifact[]> {
|
||||||
|
const artifacts: MemoryArtifact[] = [];
|
||||||
|
const userId = options?.userId ?? ctx.effectiveUserId();
|
||||||
|
const types = options?.types ?? ["memory", "dream", "entity"];
|
||||||
|
const limit = options?.limit ?? 100;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Memory artifacts
|
||||||
|
if (types.includes("memory")) {
|
||||||
|
const memories = await ctx.provider.getAll({
|
||||||
|
user_id: userId,
|
||||||
|
page_size: limit,
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const mem of memories) {
|
||||||
|
artifacts.push(memoryToArtifact(mem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dream state artifact (if dream enabled and stateDir available)
|
||||||
|
if (types.includes("dream") && ctx.stateDir && ctx.cfg.skills?.dream?.enabled) {
|
||||||
|
const dreamArtifact = getDreamArtifact(ctx.stateDir, userId);
|
||||||
|
if (dreamArtifact) {
|
||||||
|
artifacts.push(dreamArtifact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entity artifacts (grouped memories by category)
|
||||||
|
if (types.includes("entity")) {
|
||||||
|
const entityArtifacts = extractEntityArtifacts(artifacts.filter(a => a.type === "memory"));
|
||||||
|
artifacts.push(...entityArtifacts);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(
|
||||||
|
"[mem0] publicArtifacts.listArtifacts failed:",
|
||||||
|
err instanceof Error ? err.message : err,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return artifacts.slice(0, limit);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a MemoryItem to a MemoryArtifact.
|
||||||
|
*/
|
||||||
|
function memoryToArtifact(mem: MemoryItem): MemoryArtifact {
|
||||||
|
return {
|
||||||
|
id: `mem0:memory:${mem.id}`,
|
||||||
|
type: "memory",
|
||||||
|
title: mem.memory.slice(0, 80) + (mem.memory.length > 80 ? "..." : ""),
|
||||||
|
content: mem.memory,
|
||||||
|
metadata: {
|
||||||
|
score: mem.score,
|
||||||
|
categories: mem.categories,
|
||||||
|
user_id: mem.user_id,
|
||||||
|
...mem.metadata,
|
||||||
|
},
|
||||||
|
createdAt: mem.created_at,
|
||||||
|
updatedAt: mem.updated_at,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get dream consolidation state as an artifact.
|
||||||
|
*/
|
||||||
|
function getDreamArtifact(stateDir: string, userId: string): MemoryArtifact | null {
|
||||||
|
try {
|
||||||
|
const state = getDreamState(stateDir);
|
||||||
|
if (state.lastConsolidatedAt === 0) {
|
||||||
|
return null; // No consolidation has occurred yet
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastDate = new Date(state.lastConsolidatedAt).toISOString();
|
||||||
|
return {
|
||||||
|
id: `mem0:dream:${userId}:state`,
|
||||||
|
type: "dream",
|
||||||
|
title: `Dream State (last: ${lastDate.split("T")[0]})`,
|
||||||
|
content: [
|
||||||
|
`Last consolidation: ${lastDate}`,
|
||||||
|
`Sessions since: ${state.sessionsSince}`,
|
||||||
|
`Last session: ${state.lastSessionId ?? "none"}`,
|
||||||
|
].join("\n"),
|
||||||
|
metadata: {
|
||||||
|
lastConsolidatedAt: state.lastConsolidatedAt,
|
||||||
|
sessionsSince: state.sessionsSince,
|
||||||
|
lastSessionId: state.lastSessionId,
|
||||||
|
user_id: userId,
|
||||||
|
},
|
||||||
|
updatedAt: lastDate,
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract entity artifacts from memories (grouped by category).
|
||||||
|
*/
|
||||||
|
function extractEntityArtifacts(memoryArtifacts: MemoryArtifact[]): MemoryArtifact[] {
|
||||||
|
const byCategory = new Map<string, MemoryArtifact[]>();
|
||||||
|
|
||||||
|
for (const artifact of memoryArtifacts) {
|
||||||
|
const categories = (artifact.metadata?.categories as string[]) ?? ["uncategorized"];
|
||||||
|
for (const cat of categories) {
|
||||||
|
const existing = byCategory.get(cat) ?? [];
|
||||||
|
existing.push(artifact);
|
||||||
|
byCategory.set(cat, existing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const entities: MemoryArtifact[] = [];
|
||||||
|
for (const [category, mems] of byCategory) {
|
||||||
|
if (mems.length >= 2) {
|
||||||
|
entities.push({
|
||||||
|
id: `mem0:entity:${category}`,
|
||||||
|
type: "entity",
|
||||||
|
title: `${category.charAt(0).toUpperCase() + category.slice(1)} (${mems.length} memories)`,
|
||||||
|
content: mems.map(m => `- ${m.content}`).join("\n"),
|
||||||
|
metadata: {
|
||||||
|
category,
|
||||||
|
memoryCount: mems.length,
|
||||||
|
memoryIds: mems.map(m => m.id),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entities;
|
||||||
|
}
|
||||||
+2
-7
@@ -2,7 +2,7 @@
|
|||||||
* Token-budgeted, category-ranked recall engine.
|
* Token-budgeted, category-ranked recall engine.
|
||||||
*
|
*
|
||||||
* Replaces naive "dump all search results" with:
|
* Replaces naive "dump all search results" with:
|
||||||
* 1. Search with rerank + keyword_search
|
* 1. Search memories with threshold filtering
|
||||||
* 2. Rank by category priority (identity first)
|
* 2. Rank by category priority (identity first)
|
||||||
* 3. Token-budget the results
|
* 3. Token-budget the results
|
||||||
* 4. Format by category with importance scores
|
* 4. Format by category with importance scores
|
||||||
@@ -253,18 +253,13 @@ export async function recall(
|
|||||||
const categoryOrder = recallConfig.categoryOrder ?? DEFAULT_CATEGORY_ORDER;
|
const categoryOrder = recallConfig.categoryOrder ?? DEFAULT_CATEGORY_ORDER;
|
||||||
const identityAlwaysInclude = recallConfig.identityAlwaysInclude !== false;
|
const identityAlwaysInclude = recallConfig.identityAlwaysInclude !== false;
|
||||||
|
|
||||||
// Build search options with enhanced features
|
// Build search options (v3.0.0: keyword_search, reranking, filter_memories removed)
|
||||||
const searchOpts: SearchOptions = {
|
const searchOpts: SearchOptions = {
|
||||||
user_id: userId,
|
user_id: userId,
|
||||||
top_k: maxMemories * 2, // Over-fetch for ranking
|
top_k: maxMemories * 2, // Over-fetch for ranking
|
||||||
threshold,
|
threshold,
|
||||||
keyword_search: recallConfig.keywordSearch !== false, // Default on
|
|
||||||
reranking: recallConfig.rerank !== false, // Default on
|
|
||||||
source: "OPENCLAW",
|
source: "OPENCLAW",
|
||||||
};
|
};
|
||||||
if (recallConfig.filterMemories) {
|
|
||||||
searchOpts.filter_memories = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sanitize query: strip OpenClaw metadata prefix before searching
|
// Sanitize query: strip OpenClaw metadata prefix before searching
|
||||||
const cleanQuery = sanitizeQuery(query);
|
const cleanQuery = sanitizeQuery(query);
|
||||||
|
|||||||
@@ -654,9 +654,9 @@ describe("OSSProvider — history error handling", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// 9. OSSProvider: customPrompt passthrough
|
// 9. OSSProvider: customInstructions passthrough (v3.0.0: renamed from customPrompt)
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
describe("OSSProvider — customPrompt passthrough", () => {
|
describe("OSSProvider — customInstructions passthrough", () => {
|
||||||
let capturedConfig: Record<string, unknown> | undefined;
|
let capturedConfig: Record<string, unknown> | undefined;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -682,12 +682,13 @@ describe("OSSProvider — customPrompt passthrough", () => {
|
|||||||
vi.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("passes customPrompt to Memory config when provided", async () => {
|
// v3.0.0: customPrompt renamed to customInstructions
|
||||||
|
it("passes customInstructions to Memory config when provided", async () => {
|
||||||
const { createProvider } = await import("./index.ts");
|
const { createProvider } = await import("./index.ts");
|
||||||
const cfg = mem0ConfigSchema.parse({
|
const cfg = mem0ConfigSchema.parse({
|
||||||
mode: "open-source",
|
mode: "open-source",
|
||||||
oss: { disableHistory: true },
|
oss: { disableHistory: true },
|
||||||
customPrompt: "Extract only user preferences.",
|
customInstructions: "Extract only user preferences.",
|
||||||
});
|
});
|
||||||
const api = { resolvePath: (p: string) => p } as any;
|
const api = { resolvePath: (p: string) => p } as any;
|
||||||
const provider = createProvider(cfg, api);
|
const provider = createProvider(cfg, api);
|
||||||
@@ -695,6 +696,6 @@ describe("OSSProvider — customPrompt passthrough", () => {
|
|||||||
await provider.search("test", { user_id: "u1" });
|
await provider.search("test", { user_id: "u1" });
|
||||||
|
|
||||||
expect(capturedConfig).toBeDefined();
|
expect(capturedConfig).toBeDefined();
|
||||||
expect(capturedConfig!.customPrompt).toBe("Extract only user preferences.");
|
expect(capturedConfig!.customInstructions).toBe("Extract only user preferences.");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { createHash, randomUUID } from "node:crypto";
|
import { createHash, randomUUID } from "node:crypto";
|
||||||
import { readPluginAuth, writePluginAuth, getBaseUrl } from "./cli/config-file.ts";
|
import { readPluginAuth, writePluginAuth, getBaseUrl, clearAnonymousTelemetryId } from "./cli/config-file.ts";
|
||||||
|
|
||||||
export const PLUGIN_VERSION = "1.0.6";
|
export const PLUGIN_VERSION = "1.0.7";
|
||||||
|
|
||||||
const POSTHOG_API_KEY = "phc_hgJkUVJFYtmaJqrvf6CYN67TIQ8yhXAkWzUn9AMU4yX";
|
const POSTHOG_API_KEY = "phc_hgJkUVJFYtmaJqrvf6CYN67TIQ8yhXAkWzUn9AMU4yX";
|
||||||
const POSTHOG_HOST = "https://us.i.posthog.com/i/v0/e/";
|
const POSTHOG_HOST = "https://us.i.posthog.com/i/v0/e/";
|
||||||
@@ -84,8 +84,9 @@ function maybeBuildIdentifyEvent(
|
|||||||
$lib: "posthog-node",
|
$lib: "posthog-node",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
// Clear the anonymous ID from config after aliasing (don't write empty string)
|
||||||
try {
|
try {
|
||||||
writePluginAuth({ anonymousTelemetryId: "" });
|
clearAnonymousTelemetryId();
|
||||||
} catch {
|
} catch {
|
||||||
/* ignore — alias may double-fire next session, harmless */
|
/* ignore — alias may double-fire next session, harmless */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,9 +113,15 @@ describe("readPluginAuth", () => {
|
|||||||
expect(auth.userId).toBe("user-snake");
|
expect(auth.userId).toBe("user-snake");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns empty object when JSON is invalid", () => {
|
it("throws error when JSON is invalid (prevents config destruction)", () => {
|
||||||
mockExists.mockReturnValue(true);
|
mockExists.mockReturnValue(true);
|
||||||
mockReadText.mockReturnValue("not valid json {{{");
|
mockReadText.mockReturnValue("not valid json {{{");
|
||||||
|
expect(() => readPluginAuth()).toThrow(/Failed to parse[\s\S]*Fix the JSON syntax error/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns empty object when config file is empty", () => {
|
||||||
|
mockExists.mockReturnValue(true);
|
||||||
|
mockReadText.mockReturnValue(" ");
|
||||||
expect(readPluginAuth()).toEqual({});
|
expect(readPluginAuth()).toEqual({});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -74,9 +74,10 @@ describe("mem0ConfigSchema.parse() — defaults", () => {
|
|||||||
expect(cfg.customCategories).toBe(DEFAULT_CUSTOM_CATEGORIES);
|
expect(cfg.customCategories).toBe(DEFAULT_CUSTOM_CATEGORIES);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("customPrompt defaults to DEFAULT_CUSTOM_INSTRUCTIONS", () => {
|
// v3.0.0: customPrompt removed, use customInstructions instead
|
||||||
const cfg = mem0ConfigSchema.parse({ apiKey: "test-key" });
|
it("customPrompt input falls back to customInstructions", () => {
|
||||||
expect(cfg.customPrompt).toBe(DEFAULT_CUSTOM_INSTRUCTIONS);
|
const cfg = mem0ConfigSchema.parse({ apiKey: "test-key", customPrompt: "My prompt" });
|
||||||
|
expect(cfg.customInstructions).toBe("My prompt");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("oss defaults to undefined", () => {
|
it("oss defaults to undefined", () => {
|
||||||
@@ -296,13 +297,14 @@ describe("mem0ConfigSchema.parse() — explicit overrides", () => {
|
|||||||
expect(cfg.customInstructions).toBe(custom);
|
expect(cfg.customInstructions).toBe(custom);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("custom customPrompt overrides defaults", () => {
|
// v3.0.0: customPrompt renamed to customInstructions (backwards compat: customPrompt maps to customInstructions)
|
||||||
|
it("customPrompt input maps to customInstructions output", () => {
|
||||||
const custom = "My custom prompt";
|
const custom = "My custom prompt";
|
||||||
const cfg = mem0ConfigSchema.parse({
|
const cfg = mem0ConfigSchema.parse({
|
||||||
apiKey: "k",
|
apiKey: "k",
|
||||||
customPrompt: custom,
|
customPrompt: custom,
|
||||||
});
|
});
|
||||||
expect(cfg.customPrompt).toBe(custom);
|
expect(cfg.customInstructions).toBe(custom);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("custom customCategories override defaults", () => {
|
it("custom customCategories override defaults", () => {
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
import { describe, it, expect } from "vitest";
|
||||||
|
import {
|
||||||
|
isNoiseMessage,
|
||||||
|
isGenericAssistantMessage,
|
||||||
|
isSessionSpecificContent,
|
||||||
|
stripNoiseFromContent,
|
||||||
|
filterMessagesForExtraction,
|
||||||
|
} from "../filtering.ts";
|
||||||
|
|
||||||
|
describe("isNoiseMessage", () => {
|
||||||
|
it("returns true for heartbeat messages", () => {
|
||||||
|
expect(isNoiseMessage("HEARTBEAT_OK")).toBe(true);
|
||||||
|
expect(isNoiseMessage("NO_REPLY")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns true for single-word acknowledgments", () => {
|
||||||
|
expect(isNoiseMessage("ok")).toBe(true);
|
||||||
|
expect(isNoiseMessage("done")).toBe(true);
|
||||||
|
expect(isNoiseMessage("thanks")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns false for substantive content", () => {
|
||||||
|
expect(isNoiseMessage("My name is John and I live in Tokyo")).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("isGenericAssistantMessage", () => {
|
||||||
|
it("returns true for generic acknowledgments", () => {
|
||||||
|
expect(isGenericAssistantMessage("I see you've shared this. How can I help?")).toBe(true);
|
||||||
|
expect(isGenericAssistantMessage("Got it! How can I assist you?")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns false for substantive responses", () => {
|
||||||
|
expect(isGenericAssistantMessage("Based on the code, the bug is in line 42 where the null check is missing.")).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("isSessionSpecificContent", () => {
|
||||||
|
it("returns true for tool availability discussions", () => {
|
||||||
|
expect(isSessionSpecificContent(
|
||||||
|
"I do not currently see Mem0 write/update/delete tools exposed in this session."
|
||||||
|
)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns true for plugin capability statements", () => {
|
||||||
|
expect(isSessionSpecificContent(
|
||||||
|
"As of 2026-04-18, the openclaw-mem0 plugin does not expose a memory wiki capability."
|
||||||
|
)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns true for session-specific tool lists", () => {
|
||||||
|
expect(isSessionSpecificContent(
|
||||||
|
"The tools I have access to in this session are memory_search and memory_get."
|
||||||
|
)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns false for user preferences", () => {
|
||||||
|
expect(isSessionSpecificContent(
|
||||||
|
"My name is Kartik and I like to watch Pokemon."
|
||||||
|
)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns false for technical facts that span sessions", () => {
|
||||||
|
expect(isSessionSpecificContent(
|
||||||
|
"The project uses TypeScript 5.0 and Node.js 20."
|
||||||
|
)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("filterMessagesForExtraction", () => {
|
||||||
|
it("filters out session-specific tool discussions", () => {
|
||||||
|
const messages = [
|
||||||
|
{ role: "user", content: "What tools do you have access to?" },
|
||||||
|
{ role: "assistant", content: "I have memory_search and memory_get tools. The other tools are not exposed in this session." },
|
||||||
|
{ role: "user", content: "My name is Kartik" },
|
||||||
|
{ role: "assistant", content: "Got it, I'll remember that!" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const filtered = filterMessagesForExtraction(messages);
|
||||||
|
|
||||||
|
// Should keep the name statement, filter the tool discussion
|
||||||
|
expect(filtered.some(m => m.content.includes("Kartik"))).toBe(true);
|
||||||
|
expect(filtered.some(m => m.content.includes("not exposed in this session"))).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps valuable user facts", () => {
|
||||||
|
const messages = [
|
||||||
|
{ role: "user", content: "I prefer dark mode and use VS Code for development." },
|
||||||
|
{ role: "assistant", content: "Noted! Dark mode in VS Code is great for reducing eye strain." },
|
||||||
|
];
|
||||||
|
|
||||||
|
const filtered = filterMessagesForExtraction(messages);
|
||||||
|
expect(filtered.length).toBe(2);
|
||||||
|
expect(filtered[0].content).toContain("dark mode");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -42,6 +42,7 @@ beforeEach(() => {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
describe("providerToBackend — search", () => {
|
describe("providerToBackend — search", () => {
|
||||||
|
// v3.0.0: keyword_search, reranking removed from SDK
|
||||||
it("delegates to provider.search with correct options", async () => {
|
it("delegates to provider.search with correct options", async () => {
|
||||||
const provider = createMockProvider();
|
const provider = createMockProvider();
|
||||||
const backend = providerToBackend(provider as any, DEFAULT_USER);
|
const backend = providerToBackend(provider as any, DEFAULT_USER);
|
||||||
@@ -49,8 +50,6 @@ describe("providerToBackend — search", () => {
|
|||||||
const results = await backend.search("hello world", {
|
const results = await backend.search("hello world", {
|
||||||
topK: 10,
|
topK: 10,
|
||||||
threshold: 0.5,
|
threshold: 0.5,
|
||||||
keyword: true,
|
|
||||||
rerank: true,
|
|
||||||
filters: { category: "preference" },
|
filters: { category: "preference" },
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -58,8 +57,6 @@ describe("providerToBackend — search", () => {
|
|||||||
user_id: DEFAULT_USER,
|
user_id: DEFAULT_USER,
|
||||||
top_k: 10,
|
top_k: 10,
|
||||||
threshold: 0.5,
|
threshold: 0.5,
|
||||||
keyword_search: true,
|
|
||||||
reranking: true,
|
|
||||||
filters: { category: "preference" },
|
filters: { category: "preference" },
|
||||||
source: "OPENCLAW",
|
source: "OPENCLAW",
|
||||||
});
|
});
|
||||||
@@ -73,12 +70,11 @@ describe("providerToBackend — search", () => {
|
|||||||
|
|
||||||
await backend.search("query");
|
await backend.search("query");
|
||||||
|
|
||||||
|
// v3.0.0: keyword_search, reranking removed
|
||||||
expect(provider.search).toHaveBeenCalledWith("query", {
|
expect(provider.search).toHaveBeenCalledWith("query", {
|
||||||
user_id: DEFAULT_USER,
|
user_id: DEFAULT_USER,
|
||||||
top_k: undefined,
|
top_k: undefined,
|
||||||
threshold: undefined,
|
threshold: undefined,
|
||||||
keyword_search: undefined,
|
|
||||||
reranking: undefined,
|
|
||||||
filters: undefined,
|
filters: undefined,
|
||||||
source: "OPENCLAW",
|
source: "OPENCLAW",
|
||||||
});
|
});
|
||||||
@@ -119,6 +115,7 @@ describe("providerToBackend — add", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// v3.0.0: immutable, expiration_date removed from SDK
|
||||||
it("forwards optional add options", async () => {
|
it("forwards optional add options", async () => {
|
||||||
const provider = createMockProvider();
|
const provider = createMockProvider();
|
||||||
const backend = providerToBackend(provider as any, DEFAULT_USER);
|
const backend = providerToBackend(provider as any, DEFAULT_USER);
|
||||||
@@ -126,9 +123,7 @@ describe("providerToBackend — add", () => {
|
|||||||
await backend.add("fact", undefined, {
|
await backend.add("fact", undefined, {
|
||||||
runId: "run-1",
|
runId: "run-1",
|
||||||
metadata: { source: "test" },
|
metadata: { source: "test" },
|
||||||
immutable: true,
|
|
||||||
infer: false,
|
infer: false,
|
||||||
expires: "2027-01-01",
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(provider.add).toHaveBeenCalledWith(
|
expect(provider.add).toHaveBeenCalledWith(
|
||||||
@@ -137,9 +132,7 @@ describe("providerToBackend — add", () => {
|
|||||||
user_id: DEFAULT_USER,
|
user_id: DEFAULT_USER,
|
||||||
run_id: "run-1",
|
run_id: "run-1",
|
||||||
metadata: { source: "test" },
|
metadata: { source: "test" },
|
||||||
immutable: true,
|
|
||||||
infer: false,
|
infer: false,
|
||||||
expiration_date: "2027-01-01",
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ describe("telemetry", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("exports PLUGIN_VERSION", () => {
|
it("exports PLUGIN_VERSION", () => {
|
||||||
expect(PLUGIN_VERSION).toBe("1.0.6");
|
expect(PLUGIN_VERSION).toBe("1.0.7");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("captureEvent does not throw", () => {
|
it("captureEvent does not throw", () => {
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ function createMockToolDeps(overrides = {}): ToolDeps {
|
|||||||
searchThreshold: 0.5,
|
searchThreshold: 0.5,
|
||||||
customInstructions: "test",
|
customInstructions: "test",
|
||||||
customCategories: {},
|
customCategories: {},
|
||||||
customPrompt: "test",
|
|
||||||
} as any,
|
} as any,
|
||||||
provider: {
|
provider: {
|
||||||
search: vi
|
search: vi
|
||||||
@@ -108,13 +107,14 @@ describe("registerAllTools", () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("registers tools without a second argument (required, not optional)", () => {
|
it("registers tools with optional: false metadata", () => {
|
||||||
const ctx = createMockToolDeps();
|
const ctx = createMockToolDeps();
|
||||||
registerAllTools(ctx);
|
registerAllTools(ctx);
|
||||||
|
|
||||||
const calls = (ctx.api.registerTool as ReturnType<typeof vi.fn>).mock.calls;
|
const calls = (ctx.api.registerTool as ReturnType<typeof vi.fn>).mock.calls;
|
||||||
for (const call of calls) {
|
for (const call of calls) {
|
||||||
expect(call).toHaveLength(1);
|
expect(call).toHaveLength(2);
|
||||||
|
expect(call[1]).toEqual({ optional: false });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,13 +28,14 @@ export interface ToolDeps {
|
|||||||
|
|
||||||
export function registerAllTools(deps: ToolDeps): void {
|
export function registerAllTools(deps: ToolDeps): void {
|
||||||
const { api } = deps;
|
const { api } = deps;
|
||||||
|
const nonOptional = { optional: false };
|
||||||
|
|
||||||
api.registerTool(createMemorySearchTool(deps));
|
api.registerTool(createMemorySearchTool(deps), nonOptional);
|
||||||
api.registerTool(createMemoryAddTool(deps));
|
api.registerTool(createMemoryAddTool(deps), nonOptional);
|
||||||
api.registerTool(createMemoryGetTool(deps));
|
api.registerTool(createMemoryGetTool(deps), nonOptional);
|
||||||
api.registerTool(createMemoryListTool(deps));
|
api.registerTool(createMemoryListTool(deps), nonOptional);
|
||||||
api.registerTool(createMemoryUpdateTool(deps));
|
api.registerTool(createMemoryUpdateTool(deps), nonOptional);
|
||||||
api.registerTool(createMemoryDeleteTool(deps));
|
api.registerTool(createMemoryDeleteTool(deps), nonOptional);
|
||||||
api.registerTool(createMemoryEventListTool(deps));
|
api.registerTool(createMemoryEventListTool(deps), nonOptional);
|
||||||
api.registerTool(createMemoryEventStatusTool(deps));
|
api.registerTool(createMemoryEventStatusTool(deps), nonOptional);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { Type } from "@sinclair/typebox";
|
import { Type } from "@sinclair/typebox";
|
||||||
import type { AddOptions } from "../types.ts";
|
import type { AddOptions } from "../types.ts";
|
||||||
import { isSubagentSession } from "../isolation.ts";
|
import { isSubagentSession } from "../isolation.ts";
|
||||||
import { resolveCategories, ttlToExpirationDate } from "../skill-loader.ts";
|
import { isNoiseMessage, stripNoiseFromContent } from "../filtering.ts";
|
||||||
|
// v3.0.0: resolveCategories/ttlToExpirationDate removed - expiration_date/immutable no longer supported
|
||||||
import type { ToolDeps } from "./index.ts";
|
import type { ToolDeps } from "./index.ts";
|
||||||
|
|
||||||
export function createMemoryAddTool(deps: ToolDeps) {
|
export function createMemoryAddTool(deps: ToolDeps) {
|
||||||
const { api, cfg, provider, resolveUserId, getCurrentSessionId, buildAddOptions, buildSearchOptions, skillsActive } = deps;
|
const { api, provider, resolveUserId, getCurrentSessionId, buildAddOptions, buildSearchOptions, skillsActive } = deps;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: "memory_add",
|
name: "memory_add",
|
||||||
@@ -28,11 +29,20 @@ export function createMemoryAddTool(deps: ToolDeps) {
|
|||||||
userId?: string; agentId?: string; metadata?: Record<string, unknown>; longTerm?: boolean;
|
userId?: string; agentId?: string; metadata?: Record<string, unknown>; longTerm?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const allFacts: string[] = p.facts?.length ? p.facts : (p.text ? [p.text] : []);
|
const rawFacts: string[] = p.facts?.length ? p.facts : (p.text ? [p.text] : []);
|
||||||
if (allFacts.length === 0) {
|
if (rawFacts.length === 0) {
|
||||||
return { content: [{ type: "text", text: "No facts provided. Pass 'text' or 'facts' array." }], details: { error: "missing_facts" } };
|
return { content: [{ type: "text", text: "No facts provided. Pass 'text' or 'facts' array." }], details: { error: "missing_facts" } };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter out noise and clean the facts before storing
|
||||||
|
const allFacts = rawFacts
|
||||||
|
.map((f) => stripNoiseFromContent(f))
|
||||||
|
.filter((f) => f.length > 0 && !isNoiseMessage(f));
|
||||||
|
|
||||||
|
if (allFacts.length === 0) {
|
||||||
|
return { content: [{ type: "text", text: "All provided facts were filtered as noise. Nothing stored." }], details: { error: "all_noise" } };
|
||||||
|
}
|
||||||
|
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
try {
|
try {
|
||||||
const currentSessionId = getCurrentSessionId();
|
const currentSessionId = getCurrentSessionId();
|
||||||
@@ -53,21 +63,12 @@ export function createMemoryAddTool(deps: ToolDeps) {
|
|||||||
...(category && { category }),
|
...(category && { category }),
|
||||||
...(importance !== undefined && { importance }),
|
...(importance !== undefined && { importance }),
|
||||||
};
|
};
|
||||||
const categories = resolveCategories(cfg.skills);
|
|
||||||
const catConfig = category ? categories[category] : undefined;
|
|
||||||
const expirationDate = catConfig ? ttlToExpirationDate(catConfig.ttl) : undefined;
|
|
||||||
const isImmutable = catConfig?.immutable ?? false;
|
|
||||||
|
|
||||||
const addOpts: AddOptions = {
|
const addOpts: AddOptions = {
|
||||||
user_id: uid, source: "OPENCLAW", infer: false,
|
user_id: uid, source: "OPENCLAW", infer: false,
|
||||||
deduced_memories: allFacts, metadata: parsedMetadata ?? {},
|
deduced_memories: allFacts, metadata: parsedMetadata ?? {},
|
||||||
...(expirationDate && { expiration_date: expirationDate }),
|
|
||||||
...(isImmutable && { immutable: true }),
|
|
||||||
};
|
};
|
||||||
if (runId) addOpts.run_id = runId;
|
if (runId) addOpts.run_id = runId;
|
||||||
if (cfg.mode === "platform") {
|
|
||||||
addOpts.output_format = "v1.1";
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await provider.add([{ role: "user", content: allFacts.join("\n") }], addOpts);
|
const result = await provider.add([{ role: "user", content: allFacts.join("\n") }], addOpts);
|
||||||
const count = result.results?.length ?? 0;
|
const count = result.results?.length ?? 0;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export function createMemorySearchTool(deps: ToolDeps) {
|
|||||||
agentId: Type.Optional(Type.String({ description: "Agent ID to search a specific agent's memories" })),
|
agentId: Type.Optional(Type.String({ description: "Agent ID to search a specific agent's memories" })),
|
||||||
scope: Type.Optional(
|
scope: Type.Optional(
|
||||||
Type.Union([Type.Literal("session"), Type.Literal("long-term"), Type.Literal("all")], {
|
Type.Union([Type.Literal("session"), Type.Literal("long-term"), Type.Literal("all")], {
|
||||||
description: 'Scope: "long-term" (default), "session", or "all"',
|
description: 'Scope: "all" (default), "session", or "long-term"',
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
categories: Type.Optional(Type.Array(Type.String(), { description: "Filter by category" })),
|
categories: Type.Optional(Type.Array(Type.String(), { description: "Filter by category" })),
|
||||||
@@ -25,7 +25,7 @@ export function createMemorySearchTool(deps: ToolDeps) {
|
|||||||
|
|
||||||
async execute(_toolCallId: string, params: Record<string, unknown>) {
|
async execute(_toolCallId: string, params: Record<string, unknown>) {
|
||||||
const {
|
const {
|
||||||
query, limit, userId, agentId, scope = "long-term",
|
query, limit, userId, agentId, scope = "all",
|
||||||
categories: filterCategories, filters: agentFilters,
|
categories: filterCategories, filters: agentFilters,
|
||||||
} = params as {
|
} = params as {
|
||||||
query: string; limit?: number; userId?: string; agentId?: string;
|
query: string; limit?: number; userId?: string; agentId?: string;
|
||||||
|
|||||||
+2
-10
@@ -12,8 +12,7 @@ export type Mem0Config = {
|
|||||||
baseUrl?: string;
|
baseUrl?: string;
|
||||||
customInstructions: string;
|
customInstructions: string;
|
||||||
customCategories: Record<string, string>;
|
customCategories: Record<string, string>;
|
||||||
// OSS-specific
|
// OSS-specific (customPrompt renamed to customInstructions in v3.0.0)
|
||||||
customPrompt?: string;
|
|
||||||
oss?: {
|
oss?: {
|
||||||
embedder?: { provider: string; config: Record<string, unknown> };
|
embedder?: { provider: string; config: Record<string, unknown> };
|
||||||
vectorStore?: { provider: string; config: Record<string, unknown> };
|
vectorStore?: { provider: string; config: Record<string, unknown> };
|
||||||
@@ -37,15 +36,12 @@ export interface AddOptions {
|
|||||||
user_id: string;
|
user_id: string;
|
||||||
run_id?: string;
|
run_id?: string;
|
||||||
custom_instructions?: string;
|
custom_instructions?: string;
|
||||||
custom_categories?: Array<Record<string, string>>;
|
custom_categories?: Record<string, string>;
|
||||||
output_format?: string;
|
|
||||||
source?: string;
|
source?: string;
|
||||||
// Agentic harness additions
|
// Agentic harness additions
|
||||||
infer?: boolean;
|
infer?: boolean;
|
||||||
deduced_memories?: string[];
|
deduced_memories?: string[];
|
||||||
metadata?: Record<string, unknown>;
|
metadata?: Record<string, unknown>;
|
||||||
expiration_date?: string;
|
|
||||||
immutable?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SearchOptions {
|
export interface SearchOptions {
|
||||||
@@ -53,10 +49,6 @@ export interface SearchOptions {
|
|||||||
run_id?: string;
|
run_id?: string;
|
||||||
top_k?: number;
|
top_k?: number;
|
||||||
threshold?: number;
|
threshold?: number;
|
||||||
limit?: number;
|
|
||||||
keyword_search?: boolean;
|
|
||||||
reranking?: boolean;
|
|
||||||
filter_memories?: boolean;
|
|
||||||
categories?: string[];
|
categories?: string[];
|
||||||
filters?: Record<string, unknown>;
|
filters?: Record<string, unknown>;
|
||||||
source?: string;
|
source?: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user