feat(cli): remove mem0 version subcommand from md files and fix help --json in the Python CLI (#6773)
This commit is contained in:
+1
-2
@@ -60,9 +60,8 @@ mem0 delete <memory-id>
|
|||||||
| `mem0 entity` | List or delete entities (users, agents, apps, runs) |
|
| `mem0 entity` | List or delete entities (users, agents, apps, runs) |
|
||||||
| `mem0 event` | Inspect background processing events (bulk deletes, large add jobs) |
|
| `mem0 event` | Inspect background processing events (bulk deletes, large add jobs) |
|
||||||
| `mem0 status` | Verify API connection and display current project |
|
| `mem0 status` | Verify API connection and display current project |
|
||||||
| `mem0 version` | Print the CLI version |
|
|
||||||
|
|
||||||
Run `mem0 <command> --help` for detailed usage on any command.
|
Run `mem0 <command> --help` for detailed usage on any command, or `mem0 --version` to print the CLI version.
|
||||||
|
|
||||||
## Agent mode
|
## Agent mode
|
||||||
|
|
||||||
|
|||||||
+2
-8
@@ -232,14 +232,6 @@ Verify your API connection and display the current project.
|
|||||||
mem0 status
|
mem0 status
|
||||||
```
|
```
|
||||||
|
|
||||||
### `mem0 version`
|
|
||||||
|
|
||||||
Print the CLI version.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mem0 version
|
|
||||||
```
|
|
||||||
|
|
||||||
## Agent mode
|
## Agent mode
|
||||||
|
|
||||||
Pass `--agent` (or its alias `--json`) as a **global flag** on any command to get output designed for AI agent tool loops:
|
Pass `--agent` (or its alias `--json`) as a **global flag** on any command to get output designed for AI agent tool loops:
|
||||||
@@ -298,6 +290,8 @@ These flags are available on all commands:
|
|||||||
| `--base-url` | Override the configured API base URL for this request |
|
| `--base-url` | Override the configured API base URL for this request |
|
||||||
| `-o, --output` | Set the output format |
|
| `-o, --output` | Set the output format |
|
||||||
|
|
||||||
|
`mem0 --version` prints the CLI version. It is only valid before a subcommand, not after one.
|
||||||
|
|
||||||
## Environment variables
|
## Environment variables
|
||||||
|
|
||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ pnpm link --global
|
|||||||
|
|
||||||
# Now use it like a normal CLI
|
# Now use it like a normal CLI
|
||||||
mem0 --help
|
mem0 --help
|
||||||
mem0 version
|
mem0 --version
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Warning:** If you also have the Python CLI installed, both register the `mem0` command. The last one linked/installed wins. Unlink with `pnpm unlink --global`.
|
> **Warning:** If you also have the Python CLI installed, both register the `mem0` command. The last one linked/installed wins. Unlink with `pnpm unlink --global`.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Utility commands: status, version, import.
|
* Utility commands: status, import.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
@@ -8,7 +8,6 @@ import type { Backend } from "../backend/base.js";
|
|||||||
import { colors, printError, printSuccess, timedStatus } from "../branding.js";
|
import { colors, printError, printSuccess, timedStatus } from "../branding.js";
|
||||||
import { formatAgentEnvelope, formatJsonEnvelope } from "../output.js";
|
import { formatAgentEnvelope, formatJsonEnvelope } from "../output.js";
|
||||||
import { setCurrentCommand } from "../state.js";
|
import { setCurrentCommand } from "../state.js";
|
||||||
import { CLI_VERSION } from "../version.js";
|
|
||||||
|
|
||||||
const { brand, dim, success, error: errorColor } = colors;
|
const { brand, dim, success, error: errorColor } = colors;
|
||||||
|
|
||||||
@@ -82,10 +81,6 @@ export async function cmdStatus(
|
|||||||
console.log();
|
console.log();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function cmdVersion(): void {
|
|
||||||
console.log(` ${brand("◆ Mem0")} CLI v${CLI_VERSION}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function cmdImport(
|
export async function cmdImport(
|
||||||
backend: Backend,
|
backend: Backend,
|
||||||
filePath: string,
|
filePath: string,
|
||||||
|
|||||||
@@ -858,8 +858,8 @@ program
|
|||||||
.addHelpText("after", "\nExamples:\n $ mem0 help\n $ mem0 help --json")
|
.addHelpText("after", "\nExamples:\n $ mem0 help\n $ mem0 help --json")
|
||||||
.action((opts) => {
|
.action((opts) => {
|
||||||
// opts.json is set when `mem0 help --json` is used (subcommand flag).
|
// opts.json is set when `mem0 help --json` is used (subcommand flag).
|
||||||
// program.opts().json is set when the root --json global flag was used first.
|
// program.opts().json/.agent is set when a root global flag was used first.
|
||||||
if (opts.json || program.opts().json) {
|
if (opts.json || program.opts().json || program.opts().agent) {
|
||||||
// Load spec from parent directory
|
// Load spec from parent directory
|
||||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
const specPath = path.join(__dirname, "..", "..", "cli-spec.json");
|
const specPath = path.join(__dirname, "..", "..", "cli-spec.json");
|
||||||
|
|||||||
@@ -44,15 +44,25 @@ describe("CLI Integration — help and version", () => {
|
|||||||
expect(result.stdout).toContain("search");
|
expect(result.stdout).toContain("search");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("help --json produces valid JSON", () => {
|
it("prints the version with --version, and has no version subcommand", () => {
|
||||||
const result = run(["help", "--json"]);
|
const flag = run(["--version"]);
|
||||||
expect(result.exitCode).toBe(0);
|
expect(flag.exitCode).toBe(0);
|
||||||
const parsed = JSON.parse(result.stdout);
|
expect(flag.stdout).toContain("Mem0");
|
||||||
// spec may have cli.name or top-level name
|
expect(run(["version"]).exitCode).not.toBe(0);
|
||||||
const name = parsed.name ?? parsed.cli?.name;
|
|
||||||
expect(name).toBe("mem0");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it.each([["help", "--json"], ["--json", "help"], ["--agent", "help"]])(
|
||||||
|
"%s %s produces valid JSON",
|
||||||
|
(...args) => {
|
||||||
|
const result = run(args);
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
const parsed = JSON.parse(result.stdout);
|
||||||
|
// spec may have cli.name or top-level name
|
||||||
|
const name = parsed.name ?? parsed.cli?.name;
|
||||||
|
expect(name).toBe("mem0");
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
it("shows add help", () => {
|
it("shows add help", () => {
|
||||||
const result = run(["add", "--help"]);
|
const result = run(["add", "--help"]);
|
||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
|
|||||||
@@ -16,18 +16,45 @@ const OPENAPI_PATH = path.join(
|
|||||||
"openapi.json",
|
"openapi.json",
|
||||||
);
|
);
|
||||||
|
|
||||||
const KNOWN_UNSURFACED: Record<string, Record<string, string>> = {};
|
const KNOWN_UNSURFACED: Record<string, Record<string, string>> = {
|
||||||
|
"/v3/memories/add/": {
|
||||||
|
includes: "extraction hint, no CLI flag yet",
|
||||||
|
excludes: "extraction hint, no CLI flag yet",
|
||||||
|
enable_graph: "graph memory toggle, no CLI flag yet",
|
||||||
|
output_format: "response envelope is pinned by the CLI",
|
||||||
|
prompt_profile_id: "no CLI flag yet",
|
||||||
|
temporal_reasoning: "no CLI flag yet",
|
||||||
|
timezone: "no CLI flag yet",
|
||||||
|
observation_datetime: "no CLI flag yet, --timestamp backdates instead",
|
||||||
|
observation_date: "no CLI flag yet, --timestamp backdates instead",
|
||||||
|
},
|
||||||
|
"/v3/memories/search/": {
|
||||||
|
categories: "expressible through --filter",
|
||||||
|
metadata: "expressible through --filter",
|
||||||
|
},
|
||||||
|
"/v3/memories/": {
|
||||||
|
start_date: "covered by --after via filters.created_at.gte",
|
||||||
|
end_date: "covered by --before via filters.created_at.lte",
|
||||||
|
categories: "covered by --category via filters.categories",
|
||||||
|
fields: "no CLI flag yet",
|
||||||
|
keywords: "no CLI flag yet",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const ADD_MAPPING: Record<string, string[]> = {
|
const ADD_MAPPING: Record<string, string[]> = {
|
||||||
messages: ["--messages", "--file", "text"],
|
messages: ["--messages", "--file", "text"],
|
||||||
user_id: ["--user-id"],
|
user_id: ["--user-id"],
|
||||||
agent_id: ["--agent-id"],
|
agent_id: ["--agent-id"],
|
||||||
|
app_id: ["--app-id"],
|
||||||
run_id: ["--run-id"],
|
run_id: ["--run-id"],
|
||||||
metadata: ["--metadata"],
|
metadata: ["--metadata"],
|
||||||
expiration_date: ["--expires"],
|
expiration_date: ["--expires"],
|
||||||
custom_instructions: ["--custom-instructions"],
|
custom_instructions: ["--custom-instructions"],
|
||||||
custom_categories: ["--custom-categories"],
|
custom_categories: ["--custom-categories"],
|
||||||
infer: ["--no-infer"],
|
infer: ["--no-infer"],
|
||||||
|
immutable: ["--immutable"],
|
||||||
|
structured_data_schema: ["--structured-data-schema"],
|
||||||
|
timestamp: ["--timestamp"],
|
||||||
};
|
};
|
||||||
|
|
||||||
const SEARCH_MAPPING: Record<string, string[]> = {
|
const SEARCH_MAPPING: Record<string, string[]> = {
|
||||||
@@ -38,6 +65,7 @@ const SEARCH_MAPPING: Record<string, string[]> = {
|
|||||||
threshold: ["--threshold"],
|
threshold: ["--threshold"],
|
||||||
rerank: ["--rerank"],
|
rerank: ["--rerank"],
|
||||||
reference_date: ["--reference-date"],
|
reference_date: ["--reference-date"],
|
||||||
|
fields: ["--fields"],
|
||||||
};
|
};
|
||||||
|
|
||||||
const LIST_MAPPING: Record<string, string[]> = {
|
const LIST_MAPPING: Record<string, string[]> = {
|
||||||
@@ -50,6 +78,8 @@ const LIST_MAPPING: Record<string, string[]> = {
|
|||||||
"--before",
|
"--before",
|
||||||
],
|
],
|
||||||
show_expired: ["--show-expired"],
|
show_expired: ["--show-expired"],
|
||||||
|
page: ["--page"],
|
||||||
|
page_size: ["--page-size"],
|
||||||
};
|
};
|
||||||
|
|
||||||
function documentedFields(endpoint: string): string[] {
|
function documentedFields(endpoint: string): string[] {
|
||||||
|
|||||||
@@ -241,14 +241,6 @@ Verify your API connection and display the current project.
|
|||||||
mem0 status
|
mem0 status
|
||||||
```
|
```
|
||||||
|
|
||||||
### `mem0 version`
|
|
||||||
|
|
||||||
Print the CLI version.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mem0 version
|
|
||||||
```
|
|
||||||
|
|
||||||
## Agent mode
|
## Agent mode
|
||||||
|
|
||||||
Pass `--agent` (or its alias `--json`) as a **global flag** on any command to get output designed for AI agent tool loops:
|
Pass `--agent` (or its alias `--json`) as a **global flag** on any command to get output designed for AI agent tool loops:
|
||||||
@@ -307,6 +299,8 @@ These flags are available on all commands:
|
|||||||
| `--base-url` | Override the configured API base URL for this request |
|
| `--base-url` | Override the configured API base URL for this request |
|
||||||
| `-o, --output` | Set the output format |
|
| `-o, --output` | Set the output format |
|
||||||
|
|
||||||
|
`mem0 --version` prints the CLI version. It is only valid before a subcommand, not after one.
|
||||||
|
|
||||||
## Environment variables
|
## Environment variables
|
||||||
|
|
||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ mem0 --help
|
|||||||
# Using Python directly (with venv activated)
|
# Using Python directly (with venv activated)
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
mem0 --help
|
mem0 --help
|
||||||
mem0 version
|
mem0 --version
|
||||||
|
|
||||||
# Or run without activating
|
# Or run without activating
|
||||||
.venv/bin/mem0 --help
|
.venv/bin/mem0 --help
|
||||||
|
|||||||
@@ -1350,8 +1350,10 @@ def help(
|
|||||||
mem0 help
|
mem0 help
|
||||||
mem0 help --json
|
mem0 help --json
|
||||||
"""
|
"""
|
||||||
if json:
|
from mem0_cli.state import is_agent_mode
|
||||||
console.print(_json.dumps(_build_help_json(), indent=2))
|
|
||||||
|
if json or is_agent_mode():
|
||||||
|
console.print_json(_json.dumps(_build_help_json()))
|
||||||
else:
|
else:
|
||||||
console.print(
|
console.print(
|
||||||
f"[{BRAND_COLOR}]◆ mem0 CLI[/] v{__version__} — The Memory Layer for AI Agents\n"
|
f"[{BRAND_COLOR}]◆ mem0 CLI[/] v{__version__} — The Memory Layer for AI Agents\n"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ boundaries).
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
@@ -84,6 +85,31 @@ class TestCLIIntegration:
|
|||||||
assert "add" in result.stdout
|
assert "add" in result.stdout
|
||||||
assert "search" in result.stdout
|
assert "search" in result.stdout
|
||||||
|
|
||||||
|
def test_version_flag_only(self):
|
||||||
|
from mem0_cli import __version__
|
||||||
|
|
||||||
|
flag = _run(["--version"])
|
||||||
|
assert flag.returncode == 0
|
||||||
|
assert __version__ in flag.stdout
|
||||||
|
assert _run(["version"]).returncode != 0
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"args",
|
||||||
|
[["help", "--json"], ["--json", "help"], ["help", "--agent"], ["--agent", "help"]],
|
||||||
|
)
|
||||||
|
def test_help_json_produces_valid_json(self, args):
|
||||||
|
result = _run(args)
|
||||||
|
assert result.returncode == 0
|
||||||
|
spec = json.loads(result.stdout)
|
||||||
|
assert spec["name"] == "mem0"
|
||||||
|
assert "add" in spec["commands"]
|
||||||
|
|
||||||
|
def test_help_without_json_is_text(self):
|
||||||
|
result = _run(["help"])
|
||||||
|
assert result.returncode == 0
|
||||||
|
with pytest.raises(json.JSONDecodeError):
|
||||||
|
json.loads(result.stdout)
|
||||||
|
|
||||||
def test_add_help(self):
|
def test_add_help(self):
|
||||||
result = _run(["add", "--help"])
|
result = _run(["add", "--help"])
|
||||||
assert result.returncode == 0
|
assert result.returncode == 0
|
||||||
|
|||||||
@@ -10,18 +10,39 @@ from mem0_cli.app import app
|
|||||||
REPO_ROOT = Path(__file__).resolve().parents[3]
|
REPO_ROOT = Path(__file__).resolve().parents[3]
|
||||||
OPENAPI_PATH = REPO_ROOT / "docs" / "openapi.json"
|
OPENAPI_PATH = REPO_ROOT / "docs" / "openapi.json"
|
||||||
|
|
||||||
KNOWN_UNSURFACED: dict[tuple[str, str], str] = {}
|
KNOWN_UNSURFACED: dict[tuple[str, str], str] = {
|
||||||
|
("/v3/memories/add/", "includes"): "extraction hint, no CLI flag yet",
|
||||||
|
("/v3/memories/add/", "excludes"): "extraction hint, no CLI flag yet",
|
||||||
|
("/v3/memories/add/", "enable_graph"): "graph memory toggle, no CLI flag yet",
|
||||||
|
("/v3/memories/add/", "output_format"): "response envelope is pinned by the CLI",
|
||||||
|
("/v3/memories/add/", "prompt_profile_id"): "no CLI flag yet",
|
||||||
|
("/v3/memories/add/", "temporal_reasoning"): "no CLI flag yet",
|
||||||
|
("/v3/memories/add/", "timezone"): "no CLI flag yet",
|
||||||
|
("/v3/memories/add/", "observation_datetime"): "no CLI flag yet, --timestamp backdates instead",
|
||||||
|
("/v3/memories/add/", "observation_date"): "no CLI flag yet, --timestamp backdates instead",
|
||||||
|
("/v3/memories/search/", "categories"): "expressible through --filter",
|
||||||
|
("/v3/memories/search/", "metadata"): "expressible through --filter",
|
||||||
|
("/v3/memories/", "start_date"): "covered by --after via filters.created_at.gte",
|
||||||
|
("/v3/memories/", "end_date"): "covered by --before via filters.created_at.lte",
|
||||||
|
("/v3/memories/", "categories"): "covered by --category via filters.categories",
|
||||||
|
("/v3/memories/", "fields"): "no CLI flag yet",
|
||||||
|
("/v3/memories/", "keywords"): "no CLI flag yet",
|
||||||
|
}
|
||||||
|
|
||||||
ADD_MAPPING: dict[str, list[str]] = {
|
ADD_MAPPING: dict[str, list[str]] = {
|
||||||
"messages": ["messages", "file", "text"],
|
"messages": ["messages", "file", "text"],
|
||||||
"user_id": ["user_id"],
|
"user_id": ["user_id"],
|
||||||
"agent_id": ["agent_id"],
|
"agent_id": ["agent_id"],
|
||||||
|
"app_id": ["app_id"],
|
||||||
"run_id": ["run_id"],
|
"run_id": ["run_id"],
|
||||||
"metadata": ["metadata"],
|
"metadata": ["metadata"],
|
||||||
"expiration_date": ["expires"],
|
"expiration_date": ["expires"],
|
||||||
"custom_instructions": ["custom_instructions"],
|
"custom_instructions": ["custom_instructions"],
|
||||||
"custom_categories": ["custom_categories"],
|
"custom_categories": ["custom_categories"],
|
||||||
"infer": ["no_infer"],
|
"infer": ["no_infer"],
|
||||||
|
"immutable": ["immutable"],
|
||||||
|
"structured_data_schema": ["structured_data_schema"],
|
||||||
|
"timestamp": ["timestamp"],
|
||||||
}
|
}
|
||||||
|
|
||||||
SEARCH_MAPPING: dict[str, list[str]] = {
|
SEARCH_MAPPING: dict[str, list[str]] = {
|
||||||
@@ -32,11 +53,14 @@ SEARCH_MAPPING: dict[str, list[str]] = {
|
|||||||
"threshold": ["threshold"],
|
"threshold": ["threshold"],
|
||||||
"rerank": ["rerank"],
|
"rerank": ["rerank"],
|
||||||
"reference_date": ["reference_date"],
|
"reference_date": ["reference_date"],
|
||||||
|
"fields": ["fields"],
|
||||||
}
|
}
|
||||||
|
|
||||||
LIST_MAPPING: dict[str, list[str]] = {
|
LIST_MAPPING: dict[str, list[str]] = {
|
||||||
"filters": ["user_id", "agent_id", "run_id", "category", "after", "before"],
|
"filters": ["user_id", "agent_id", "run_id", "category", "after", "before"],
|
||||||
"show_expired": ["show_expired"],
|
"show_expired": ["show_expired"],
|
||||||
|
"page": ["page"],
|
||||||
|
"page_size": ["page_size"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user