feat(cli): migrate Python and Node CLIs to v3 API routes (#4916)
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@mem0/cli",
|
"name": "@mem0/cli",
|
||||||
"version": "0.2.3",
|
"version": "0.2.4",
|
||||||
"description": "The official CLI for mem0 — the memory layer for AI agents",
|
"description": "The official CLI for mem0 — the memory layer for AI agents",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ export interface AddOptions {
|
|||||||
infer?: boolean;
|
infer?: boolean;
|
||||||
expires?: string;
|
expires?: string;
|
||||||
categories?: string[];
|
categories?: string[];
|
||||||
enableGraph?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SearchOptions {
|
export interface SearchOptions {
|
||||||
@@ -29,7 +28,6 @@ export interface SearchOptions {
|
|||||||
keyword?: boolean;
|
keyword?: boolean;
|
||||||
filters?: Record<string, unknown>;
|
filters?: Record<string, unknown>;
|
||||||
fields?: string[];
|
fields?: string[];
|
||||||
enableGraph?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ListOptions {
|
export interface ListOptions {
|
||||||
@@ -42,7 +40,6 @@ export interface ListOptions {
|
|||||||
category?: string;
|
category?: string;
|
||||||
after?: string;
|
after?: string;
|
||||||
before?: string;
|
before?: string;
|
||||||
enableGraph?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DeleteOptions {
|
export interface DeleteOptions {
|
||||||
|
|||||||
@@ -115,10 +115,9 @@ export class PlatformBackend implements Backend {
|
|||||||
if (opts.infer === false) payload.infer = false;
|
if (opts.infer === false) payload.infer = false;
|
||||||
if (opts.expires) payload.expiration_date = opts.expires;
|
if (opts.expires) payload.expiration_date = opts.expires;
|
||||||
if (opts.categories) payload.categories = opts.categories;
|
if (opts.categories) payload.categories = opts.categories;
|
||||||
if (opts.enableGraph) payload.enable_graph = true;
|
|
||||||
payload.source = "CLI";
|
payload.source = "CLI";
|
||||||
|
|
||||||
return (await this._request("POST", "/v1/memories/", {
|
return (await this._request("POST", "/v3/memories/add/", {
|
||||||
json: payload,
|
json: payload,
|
||||||
})) as Record<string, unknown>;
|
})) as Record<string, unknown>;
|
||||||
}
|
}
|
||||||
@@ -176,10 +175,9 @@ export class PlatformBackend implements Backend {
|
|||||||
if (opts.rerank) payload.rerank = true;
|
if (opts.rerank) payload.rerank = true;
|
||||||
if (opts.keyword) payload.keyword_search = true;
|
if (opts.keyword) payload.keyword_search = true;
|
||||||
if (opts.fields) payload.fields = opts.fields;
|
if (opts.fields) payload.fields = opts.fields;
|
||||||
if (opts.enableGraph) payload.enable_graph = true;
|
|
||||||
payload.source = "CLI";
|
payload.source = "CLI";
|
||||||
|
|
||||||
const result = (await this._request("POST", "/v2/memories/search/", {
|
const result = (await this._request("POST", "/v3/memories/search/", {
|
||||||
json: payload,
|
json: payload,
|
||||||
})) as unknown;
|
})) as unknown;
|
||||||
if (Array.isArray(result)) return result;
|
if (Array.isArray(result)) return result;
|
||||||
@@ -227,10 +225,9 @@ export class PlatformBackend implements Backend {
|
|||||||
extraFilters: Object.keys(extra).length > 0 ? extra : undefined,
|
extraFilters: Object.keys(extra).length > 0 ? extra : undefined,
|
||||||
});
|
});
|
||||||
if (apiFilters) payload.filters = apiFilters;
|
if (apiFilters) payload.filters = apiFilters;
|
||||||
if (opts.enableGraph) payload.enable_graph = true;
|
|
||||||
payload.source = "CLI";
|
payload.source = "CLI";
|
||||||
|
|
||||||
const result = (await this._request("POST", "/v2/memories/", {
|
const result = (await this._request("POST", "/v3/memories/", {
|
||||||
json: payload,
|
json: payload,
|
||||||
params,
|
params,
|
||||||
})) as unknown;
|
})) as unknown;
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ export function cmdConfigShow(opts: { output?: string } = {}): void {
|
|||||||
agent_id: config.defaults.agentId || null,
|
agent_id: config.defaults.agentId || null,
|
||||||
app_id: config.defaults.appId || null,
|
app_id: config.defaults.appId || null,
|
||||||
run_id: config.defaults.runId || null,
|
run_id: config.defaults.runId || null,
|
||||||
enable_graph: config.defaults.enableGraph,
|
|
||||||
},
|
},
|
||||||
platform: {
|
platform: {
|
||||||
api_key: redactKey(config.platform.apiKey),
|
api_key: redactKey(config.platform.apiKey),
|
||||||
@@ -56,7 +55,6 @@ export function cmdConfigShow(opts: { output?: string } = {}): void {
|
|||||||
]);
|
]);
|
||||||
table.push(["defaults.app_id", config.defaults.appId || dim("(not set)")]);
|
table.push(["defaults.app_id", config.defaults.appId || dim("(not set)")]);
|
||||||
table.push(["defaults.run_id", config.defaults.runId || dim("(not set)")]);
|
table.push(["defaults.run_id", config.defaults.runId || dim("(not set)")]);
|
||||||
table.push(["defaults.enable_graph", String(config.defaults.enableGraph)]);
|
|
||||||
table.push(["", ""]);
|
table.push(["", ""]);
|
||||||
|
|
||||||
// Platform
|
// Platform
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ export async function cmdAdd(
|
|||||||
noInfer: boolean;
|
noInfer: boolean;
|
||||||
expires?: string;
|
expires?: string;
|
||||||
categories?: string;
|
categories?: string;
|
||||||
enableGraph: boolean;
|
|
||||||
output: string;
|
output: string;
|
||||||
},
|
},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
@@ -140,7 +139,6 @@ export async function cmdAdd(
|
|||||||
infer: !opts.noInfer,
|
infer: !opts.noInfer,
|
||||||
expires: opts.expires,
|
expires: opts.expires,
|
||||||
categories: cats,
|
categories: cats,
|
||||||
enableGraph: opts.enableGraph,
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -225,7 +223,6 @@ export async function cmdSearch(
|
|||||||
keyword: boolean;
|
keyword: boolean;
|
||||||
filterJson?: string;
|
filterJson?: string;
|
||||||
fields?: string;
|
fields?: string;
|
||||||
enableGraph: boolean;
|
|
||||||
output: string;
|
output: string;
|
||||||
},
|
},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
@@ -274,7 +271,6 @@ export async function cmdSearch(
|
|||||||
keyword: opts.keyword,
|
keyword: opts.keyword,
|
||||||
filters,
|
filters,
|
||||||
fields: fieldList,
|
fields: fieldList,
|
||||||
enableGraph: opts.enableGraph,
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -368,7 +364,6 @@ export async function cmdList(
|
|||||||
category?: string;
|
category?: string;
|
||||||
after?: string;
|
after?: string;
|
||||||
before?: string;
|
before?: string;
|
||||||
enableGraph: boolean;
|
|
||||||
output: string;
|
output: string;
|
||||||
},
|
},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
@@ -396,7 +391,6 @@ export async function cmdList(
|
|||||||
category: opts.category,
|
category: opts.category,
|
||||||
after: opts.after,
|
after: opts.after,
|
||||||
before: opts.before,
|
before: opts.before,
|
||||||
enableGraph: opts.enableGraph,
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ export interface DefaultsConfig {
|
|||||||
agentId: string;
|
agentId: string;
|
||||||
appId: string;
|
appId: string;
|
||||||
runId: string;
|
runId: string;
|
||||||
enableGraph: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TelemetryConfig {
|
export interface TelemetryConfig {
|
||||||
@@ -50,7 +49,6 @@ export function createDefaultConfig(): Mem0Config {
|
|||||||
agentId: "",
|
agentId: "",
|
||||||
appId: "",
|
appId: "",
|
||||||
runId: "",
|
runId: "",
|
||||||
enableGraph: false,
|
|
||||||
},
|
},
|
||||||
platform: {
|
platform: {
|
||||||
apiKey: "",
|
apiKey: "",
|
||||||
@@ -87,8 +85,6 @@ export function loadConfig(): Mem0Config {
|
|||||||
config.defaults.agentId = defaults.agent_id ?? "";
|
config.defaults.agentId = defaults.agent_id ?? "";
|
||||||
config.defaults.appId = defaults.app_id ?? "";
|
config.defaults.appId = defaults.app_id ?? "";
|
||||||
config.defaults.runId = defaults.run_id ?? "";
|
config.defaults.runId = defaults.run_id ?? "";
|
||||||
config.defaults.enableGraph = defaults.enable_graph ?? false;
|
|
||||||
|
|
||||||
const telemetry = data.telemetry ?? {};
|
const telemetry = data.telemetry ?? {};
|
||||||
config.telemetry.anonymousId = telemetry.anonymous_id ?? "";
|
config.telemetry.anonymousId = telemetry.anonymous_id ?? "";
|
||||||
}
|
}
|
||||||
@@ -104,12 +100,6 @@ export function loadConfig(): Mem0Config {
|
|||||||
config.defaults.agentId = process.env.MEM0_AGENT_ID;
|
config.defaults.agentId = process.env.MEM0_AGENT_ID;
|
||||||
if (process.env.MEM0_APP_ID) config.defaults.appId = process.env.MEM0_APP_ID;
|
if (process.env.MEM0_APP_ID) config.defaults.appId = process.env.MEM0_APP_ID;
|
||||||
if (process.env.MEM0_RUN_ID) config.defaults.runId = process.env.MEM0_RUN_ID;
|
if (process.env.MEM0_RUN_ID) config.defaults.runId = process.env.MEM0_RUN_ID;
|
||||||
if (process.env.MEM0_ENABLE_GRAPH) {
|
|
||||||
config.defaults.enableGraph = ["true", "1", "yes"].includes(
|
|
||||||
process.env.MEM0_ENABLE_GRAPH.toLowerCase(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +113,6 @@ export function saveConfig(config: Mem0Config): void {
|
|||||||
agent_id: config.defaults.agentId,
|
agent_id: config.defaults.agentId,
|
||||||
app_id: config.defaults.appId,
|
app_id: config.defaults.appId,
|
||||||
run_id: config.defaults.runId,
|
run_id: config.defaults.runId,
|
||||||
enable_graph: config.defaults.enableGraph,
|
|
||||||
},
|
},
|
||||||
platform: {
|
platform: {
|
||||||
api_key: config.platform.apiKey,
|
api_key: config.platform.apiKey,
|
||||||
@@ -154,7 +143,6 @@ const KEY_MAP: Record<string, [keyof Mem0Config, string]> = {
|
|||||||
"defaults.agent_id": ["defaults", "agentId"],
|
"defaults.agent_id": ["defaults", "agentId"],
|
||||||
"defaults.app_id": ["defaults", "appId"],
|
"defaults.app_id": ["defaults", "appId"],
|
||||||
"defaults.run_id": ["defaults", "runId"],
|
"defaults.run_id": ["defaults", "runId"],
|
||||||
"defaults.enable_graph": ["defaults", "enableGraph"],
|
|
||||||
// Short-form aliases
|
// Short-form aliases
|
||||||
api_key: ["platform", "apiKey"],
|
api_key: ["platform", "apiKey"],
|
||||||
base_url: ["platform", "baseUrl"],
|
base_url: ["platform", "baseUrl"],
|
||||||
@@ -163,7 +151,6 @@ const KEY_MAP: Record<string, [keyof Mem0Config, string]> = {
|
|||||||
agent_id: ["defaults", "agentId"],
|
agent_id: ["defaults", "agentId"],
|
||||||
app_id: ["defaults", "appId"],
|
app_id: ["defaults", "appId"],
|
||||||
run_id: ["defaults", "runId"],
|
run_id: ["defaults", "runId"],
|
||||||
enable_graph: ["defaults", "enableGraph"],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getNestedValue(config: Mem0Config, dottedKey: string): unknown {
|
export function getNestedValue(config: Mem0Config, dottedKey: string): unknown {
|
||||||
|
|||||||
+1
-24
@@ -134,18 +134,6 @@ function resolveIds(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve graph tri-state: --no-graph > --graph > config default.
|
|
||||||
*/
|
|
||||||
function resolveGraph(
|
|
||||||
config: Mem0Config,
|
|
||||||
opts: { graph?: boolean; noGraph?: boolean },
|
|
||||||
): boolean {
|
|
||||||
if (opts.noGraph) return false;
|
|
||||||
if (opts.graph) return true;
|
|
||||||
return config.defaults.enableGraph;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Main program ──────────────────────────────────────────────────────────
|
// ── Main program ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
program
|
program
|
||||||
@@ -236,8 +224,6 @@ program
|
|||||||
.option("--no-infer", "Skip inference, store raw.")
|
.option("--no-infer", "Skip inference, store raw.")
|
||||||
.option("--expires <date>", "Expiration date (YYYY-MM-DD).")
|
.option("--expires <date>", "Expiration date (YYYY-MM-DD).")
|
||||||
.option("--categories <value>", "Categories (JSON array or comma-separated).")
|
.option("--categories <value>", "Categories (JSON array or comma-separated).")
|
||||||
.option("--graph", "Enable graph memory extraction.", false)
|
|
||||||
.option("--no-graph", "Disable graph memory extraction.")
|
|
||||||
.option("-o, --output <format>", "Output format: text, json, quiet.", "text")
|
.option("-o, --output <format>", "Output format: text, json, quiet.", "text")
|
||||||
.option("--api-key <key>", "Override API key.")
|
.option("--api-key <key>", "Override API key.")
|
||||||
.option("--base-url <url>", "Override API base URL.")
|
.option("--base-url <url>", "Override API base URL.")
|
||||||
@@ -253,9 +239,8 @@ program
|
|||||||
opts.baseUrl,
|
opts.baseUrl,
|
||||||
);
|
);
|
||||||
const ids = resolveIds(config, opts);
|
const ids = resolveIds(config, opts);
|
||||||
const enableGraph = resolveGraph(config, opts);
|
|
||||||
const output = isAgent ? "agent" : opts.output;
|
const output = isAgent ? "agent" : opts.output;
|
||||||
await cmdAdd(backend, text, { ...ids, ...opts, enableGraph, output });
|
await cmdAdd(backend, text, { ...ids, ...opts, output });
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── Memory: search ────────────────────────────────────────────────────────
|
// ── Memory: search ────────────────────────────────────────────────────────
|
||||||
@@ -285,8 +270,6 @@ program
|
|||||||
.option("--keyword", "Use keyword search.", false)
|
.option("--keyword", "Use keyword search.", false)
|
||||||
.option("--filter <json>", "Advanced filter expression (JSON).")
|
.option("--filter <json>", "Advanced filter expression (JSON).")
|
||||||
.option("--fields <list>", "Specific fields to return (comma-separated).")
|
.option("--fields <list>", "Specific fields to return (comma-separated).")
|
||||||
.option("--graph", "Enable graph in search.", false)
|
|
||||||
.option("--no-graph", "Disable graph in search.")
|
|
||||||
.option("-o, --output <format>", "Output: text, json, table.", "text")
|
.option("-o, --output <format>", "Output: text, json, table.", "text")
|
||||||
.option("--api-key <key>", "Override API key.")
|
.option("--api-key <key>", "Override API key.")
|
||||||
.option("--base-url <url>", "Override API base URL.")
|
.option("--base-url <url>", "Override API base URL.")
|
||||||
@@ -310,7 +293,6 @@ program
|
|||||||
opts.baseUrl,
|
opts.baseUrl,
|
||||||
);
|
);
|
||||||
const ids = resolveIds(config, opts);
|
const ids = resolveIds(config, opts);
|
||||||
const enableGraph = resolveGraph(config, opts);
|
|
||||||
const output = isAgent ? "agent" : opts.output;
|
const output = isAgent ? "agent" : opts.output;
|
||||||
await cmdSearch(backend, resolvedQuery, {
|
await cmdSearch(backend, resolvedQuery, {
|
||||||
...ids,
|
...ids,
|
||||||
@@ -320,7 +302,6 @@ program
|
|||||||
keyword: opts.keyword,
|
keyword: opts.keyword,
|
||||||
filterJson: opts.filter,
|
filterJson: opts.filter,
|
||||||
fields: opts.fields,
|
fields: opts.fields,
|
||||||
enableGraph,
|
|
||||||
output,
|
output,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -364,8 +345,6 @@ program
|
|||||||
.option("--category <name>", "Filter by category.")
|
.option("--category <name>", "Filter by category.")
|
||||||
.option("--after <date>", "Created after (YYYY-MM-DD).")
|
.option("--after <date>", "Created after (YYYY-MM-DD).")
|
||||||
.option("--before <date>", "Created before (YYYY-MM-DD).")
|
.option("--before <date>", "Created before (YYYY-MM-DD).")
|
||||||
.option("--graph", "Enable graph in listing.", false)
|
|
||||||
.option("--no-graph", "Disable graph in listing.")
|
|
||||||
.option("-o, --output <format>", "Output: text, json, table.", "table")
|
.option("-o, --output <format>", "Output: text, json, table.", "table")
|
||||||
.option("--api-key <key>", "Override API key.")
|
.option("--api-key <key>", "Override API key.")
|
||||||
.option("--base-url <url>", "Override API base URL.")
|
.option("--base-url <url>", "Override API base URL.")
|
||||||
@@ -381,7 +360,6 @@ program
|
|||||||
opts.baseUrl,
|
opts.baseUrl,
|
||||||
);
|
);
|
||||||
const ids = resolveIds(config, opts);
|
const ids = resolveIds(config, opts);
|
||||||
const enableGraph = resolveGraph(config, opts);
|
|
||||||
const output = isAgent ? "agent" : opts.output;
|
const output = isAgent ? "agent" : opts.output;
|
||||||
await cmdList(backend, {
|
await cmdList(backend, {
|
||||||
...ids,
|
...ids,
|
||||||
@@ -390,7 +368,6 @@ program
|
|||||||
category: opts.category,
|
category: opts.category,
|
||||||
after: opts.after,
|
after: opts.after,
|
||||||
before: opts.before,
|
before: opts.before,
|
||||||
enableGraph,
|
|
||||||
output,
|
output,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -107,22 +107,22 @@ describe("CLI Integration — help and version", () => {
|
|||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("add help has --graph flag", () => {
|
it("add help has --output flag", () => {
|
||||||
const result = run(["add", "--help"]);
|
const result = run(["add", "--help"]);
|
||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
expect(result.stdout).toContain("--graph");
|
expect(result.stdout).toContain("--output");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("search help has --graph flag", () => {
|
it("search help has --rerank flag", () => {
|
||||||
const result = run(["search", "--help"]);
|
const result = run(["search", "--help"]);
|
||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
expect(result.stdout).toContain("--graph");
|
expect(result.stdout).toContain("--rerank");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("list help has --graph flag", () => {
|
it("list help has --category flag", () => {
|
||||||
const result = run(["list", "--help"]);
|
const result = run(["list", "--help"]);
|
||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
expect(result.stdout).toContain("--graph");
|
expect(result.stdout).toContain("--category");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ describe("cmdAdd", () => {
|
|||||||
userId: "alice",
|
userId: "alice",
|
||||||
immutable: false,
|
immutable: false,
|
||||||
noInfer: false,
|
noInfer: false,
|
||||||
enableGraph: false,
|
|
||||||
output: "text",
|
output: "text",
|
||||||
});
|
});
|
||||||
expect(mockBackend.add).toHaveBeenCalledOnce();
|
expect(mockBackend.add).toHaveBeenCalledOnce();
|
||||||
@@ -55,7 +55,7 @@ describe("cmdAdd", () => {
|
|||||||
messages: JSON.stringify([{ role: "user", content: "I love Python" }]),
|
messages: JSON.stringify([{ role: "user", content: "I love Python" }]),
|
||||||
immutable: false,
|
immutable: false,
|
||||||
noInfer: false,
|
noInfer: false,
|
||||||
enableGraph: false,
|
|
||||||
output: "text",
|
output: "text",
|
||||||
});
|
});
|
||||||
expect(mockBackend.add).toHaveBeenCalledOnce();
|
expect(mockBackend.add).toHaveBeenCalledOnce();
|
||||||
@@ -67,7 +67,7 @@ describe("cmdAdd", () => {
|
|||||||
userId: "alice",
|
userId: "alice",
|
||||||
immutable: false,
|
immutable: false,
|
||||||
noInfer: false,
|
noInfer: false,
|
||||||
enableGraph: false,
|
|
||||||
output: "json",
|
output: "json",
|
||||||
});
|
});
|
||||||
expect(output).toContain("results");
|
expect(output).toContain("results");
|
||||||
@@ -79,7 +79,7 @@ describe("cmdAdd", () => {
|
|||||||
userId: "alice",
|
userId: "alice",
|
||||||
immutable: false,
|
immutable: false,
|
||||||
noInfer: false,
|
noInfer: false,
|
||||||
enableGraph: false,
|
|
||||||
output: "quiet",
|
output: "quiet",
|
||||||
});
|
});
|
||||||
expect(output).not.toContain("dark mode");
|
expect(output).not.toContain("dark mode");
|
||||||
@@ -101,7 +101,7 @@ describe("cmdAdd deduplicates PENDING", () => {
|
|||||||
userId: "alice",
|
userId: "alice",
|
||||||
immutable: false,
|
immutable: false,
|
||||||
noInfer: false,
|
noInfer: false,
|
||||||
enableGraph: false,
|
|
||||||
output: "text",
|
output: "text",
|
||||||
});
|
});
|
||||||
expect(output.match(/Queued/g)?.length).toBe(1);
|
expect(output.match(/Queued/g)?.length).toBe(1);
|
||||||
@@ -114,7 +114,7 @@ describe("cmdAdd deduplicates PENDING", () => {
|
|||||||
userId: "alice",
|
userId: "alice",
|
||||||
immutable: false,
|
immutable: false,
|
||||||
noInfer: false,
|
noInfer: false,
|
||||||
enableGraph: false,
|
|
||||||
output: "json",
|
output: "json",
|
||||||
});
|
});
|
||||||
const data = JSON.parse(output);
|
const data = JSON.parse(output);
|
||||||
@@ -130,7 +130,7 @@ describe("cmdAdd deduplicates PENDING", () => {
|
|||||||
userId: "alice",
|
userId: "alice",
|
||||||
immutable: false,
|
immutable: false,
|
||||||
noInfer: false,
|
noInfer: false,
|
||||||
enableGraph: false,
|
|
||||||
output: "agent",
|
output: "agent",
|
||||||
});
|
});
|
||||||
const data = JSON.parse(output);
|
const data = JSON.parse(output);
|
||||||
@@ -148,7 +148,7 @@ describe("cmdSearch", () => {
|
|||||||
threshold: 0.3,
|
threshold: 0.3,
|
||||||
rerank: false,
|
rerank: false,
|
||||||
keyword: false,
|
keyword: false,
|
||||||
enableGraph: false,
|
|
||||||
output: "text",
|
output: "text",
|
||||||
});
|
});
|
||||||
expect(output).toContain("Found 2");
|
expect(output).toContain("Found 2");
|
||||||
@@ -162,7 +162,7 @@ describe("cmdSearch", () => {
|
|||||||
threshold: 0.3,
|
threshold: 0.3,
|
||||||
rerank: false,
|
rerank: false,
|
||||||
keyword: false,
|
keyword: false,
|
||||||
enableGraph: false,
|
|
||||||
output: "json",
|
output: "json",
|
||||||
});
|
});
|
||||||
expect(output).toContain("memory");
|
expect(output).toContain("memory");
|
||||||
@@ -177,7 +177,7 @@ describe("cmdSearch", () => {
|
|||||||
threshold: 0.3,
|
threshold: 0.3,
|
||||||
rerank: false,
|
rerank: false,
|
||||||
keyword: false,
|
keyword: false,
|
||||||
enableGraph: false,
|
|
||||||
output: "text",
|
output: "text",
|
||||||
});
|
});
|
||||||
expect(errOutput).toContain("No memories found");
|
expect(errOutput).toContain("No memories found");
|
||||||
@@ -205,7 +205,7 @@ describe("cmdList", () => {
|
|||||||
userId: "alice",
|
userId: "alice",
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 100,
|
pageSize: 100,
|
||||||
enableGraph: false,
|
|
||||||
output: "table",
|
output: "table",
|
||||||
});
|
});
|
||||||
expect(output).toContain("dark mode");
|
expect(output).toContain("dark mode");
|
||||||
@@ -218,7 +218,7 @@ describe("cmdList", () => {
|
|||||||
userId: "alice",
|
userId: "alice",
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 100,
|
pageSize: 100,
|
||||||
enableGraph: false,
|
|
||||||
output: "text",
|
output: "text",
|
||||||
});
|
});
|
||||||
expect(errOutput).toContain("No memories found");
|
expect(errOutput).toContain("No memories found");
|
||||||
@@ -316,7 +316,7 @@ describe("agent mode", () => {
|
|||||||
userId: "alice",
|
userId: "alice",
|
||||||
immutable: false,
|
immutable: false,
|
||||||
noInfer: false,
|
noInfer: false,
|
||||||
enableGraph: false,
|
|
||||||
output: "agent",
|
output: "agent",
|
||||||
});
|
});
|
||||||
const parsed = JSON.parse(output.trim());
|
const parsed = JSON.parse(output.trim());
|
||||||
@@ -336,7 +336,7 @@ describe("agent mode", () => {
|
|||||||
threshold: 0.3,
|
threshold: 0.3,
|
||||||
rerank: false,
|
rerank: false,
|
||||||
keyword: false,
|
keyword: false,
|
||||||
enableGraph: false,
|
|
||||||
output: "agent",
|
output: "agent",
|
||||||
});
|
});
|
||||||
const parsed = JSON.parse(output.trim());
|
const parsed = JSON.parse(output.trim());
|
||||||
@@ -361,7 +361,7 @@ describe("agent mode", () => {
|
|||||||
userId: "alice",
|
userId: "alice",
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 100,
|
pageSize: 100,
|
||||||
enableGraph: false,
|
|
||||||
output: "agent",
|
output: "agent",
|
||||||
});
|
});
|
||||||
const parsed = JSON.parse(output.trim());
|
const parsed = JSON.parse(output.trim());
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ describe("createDefaultConfig", () => {
|
|||||||
expect(config.platform.baseUrl).toBe("https://api.mem0.ai");
|
expect(config.platform.baseUrl).toBe("https://api.mem0.ai");
|
||||||
expect(config.platform.apiKey).toBe("");
|
expect(config.platform.apiKey).toBe("");
|
||||||
expect(config.defaults.userId).toBe("");
|
expect(config.defaults.userId).toBe("");
|
||||||
expect(config.defaults.enableGraph).toBe(false);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -105,9 +104,4 @@ describe("setNestedValue", () => {
|
|||||||
expect(config.defaults.userId).toBe("bob");
|
expect(config.defaults.userId).toBe("bob");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("coerces boolean for enable_graph", () => {
|
|
||||||
const config = createDefaultConfig();
|
|
||||||
expect(setNestedValue(config, "defaults.enable_graph", "true")).toBe(true);
|
|
||||||
expect(config.defaults.enableGraph).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "mem0-cli"
|
name = "mem0-cli"
|
||||||
version = "0.2.3"
|
version = "0.2.4"
|
||||||
description = "The official CLI for mem0 — the memory layer for AI agents"
|
description = "The official CLI for mem0 — the memory layer for AI agents"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
"""mem0 CLI — the command-line interface for the mem0 memory layer."""
|
"""mem0 CLI — the command-line interface for the mem0 memory layer."""
|
||||||
|
|
||||||
__version__ = "0.2.3"
|
__version__ = "0.2.4"
|
||||||
|
|||||||
@@ -267,8 +267,6 @@ def add(
|
|||||||
categories: str | None = typer.Option(
|
categories: str | None = typer.Option(
|
||||||
None, "--categories", help="Categories (JSON array or comma-separated)."
|
None, "--categories", help="Categories (JSON array or comma-separated)."
|
||||||
),
|
),
|
||||||
graph: bool = typer.Option(False, "--graph", help="Enable graph memory extraction."),
|
|
||||||
no_graph: bool = typer.Option(False, "--no-graph", help="Disable graph memory extraction."),
|
|
||||||
output: str = typer.Option(
|
output: str = typer.Option(
|
||||||
"text", "--output", "-o", help="Output format: text, json, quiet.", rich_help_panel="Output"
|
"text", "--output", "-o", help="Output format: text, json, quiet.", rich_help_panel="Output"
|
||||||
),
|
),
|
||||||
@@ -295,13 +293,6 @@ def add(
|
|||||||
backend, config = _get_backend_and_config(api_key, base_url)
|
backend, config = _get_backend_and_config(api_key, base_url)
|
||||||
ids = _resolve_ids(config, user_id=user_id, agent_id=agent_id, app_id=app_id, run_id=run_id)
|
ids = _resolve_ids(config, user_id=user_id, agent_id=agent_id, app_id=app_id, run_id=run_id)
|
||||||
|
|
||||||
if no_graph:
|
|
||||||
graph_enabled = False
|
|
||||||
elif graph:
|
|
||||||
graph_enabled = True
|
|
||||||
else:
|
|
||||||
graph_enabled = config.defaults.enable_graph
|
|
||||||
|
|
||||||
cmd_add(
|
cmd_add(
|
||||||
backend,
|
backend,
|
||||||
text,
|
text,
|
||||||
@@ -313,7 +304,6 @@ def add(
|
|||||||
no_infer=no_infer,
|
no_infer=no_infer,
|
||||||
expires=expires,
|
expires=expires,
|
||||||
categories=categories,
|
categories=categories,
|
||||||
enable_graph=graph_enabled,
|
|
||||||
output=output,
|
output=output,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -357,12 +347,6 @@ def search(
|
|||||||
help="Specific fields to return (comma-separated).",
|
help="Specific fields to return (comma-separated).",
|
||||||
rich_help_panel="Search",
|
rich_help_panel="Search",
|
||||||
),
|
),
|
||||||
graph: bool = typer.Option(
|
|
||||||
False, "--graph", help="Enable graph in search.", rich_help_panel="Search"
|
|
||||||
),
|
|
||||||
no_graph: bool = typer.Option(
|
|
||||||
False, "--no-graph", help="Disable graph in search.", rich_help_panel="Search"
|
|
||||||
),
|
|
||||||
output: str = typer.Option(
|
output: str = typer.Option(
|
||||||
"text", "--output", "-o", help="Output: text, json, table.", rich_help_panel="Output"
|
"text", "--output", "-o", help="Output: text, json, table.", rich_help_panel="Output"
|
||||||
),
|
),
|
||||||
@@ -396,13 +380,6 @@ def search(
|
|||||||
backend, config = _get_backend_and_config(api_key, base_url)
|
backend, config = _get_backend_and_config(api_key, base_url)
|
||||||
ids = _resolve_ids(config, user_id=user_id, agent_id=agent_id, app_id=app_id, run_id=run_id)
|
ids = _resolve_ids(config, user_id=user_id, agent_id=agent_id, app_id=app_id, run_id=run_id)
|
||||||
|
|
||||||
if no_graph:
|
|
||||||
graph_enabled = False
|
|
||||||
elif graph:
|
|
||||||
graph_enabled = True
|
|
||||||
else:
|
|
||||||
graph_enabled = config.defaults.enable_graph
|
|
||||||
|
|
||||||
cmd_search(
|
cmd_search(
|
||||||
backend,
|
backend,
|
||||||
query,
|
query,
|
||||||
@@ -413,7 +390,6 @@ def search(
|
|||||||
keyword=keyword,
|
keyword=keyword,
|
||||||
filter_json=filter_json,
|
filter_json=filter_json,
|
||||||
fields=fields,
|
fields=fields,
|
||||||
enable_graph=graph_enabled,
|
|
||||||
output=output,
|
output=output,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -480,12 +456,6 @@ def list_cmd(
|
|||||||
before: str | None = typer.Option(
|
before: str | None = typer.Option(
|
||||||
None, "--before", help="Created before (YYYY-MM-DD).", rich_help_panel="Filters"
|
None, "--before", help="Created before (YYYY-MM-DD).", rich_help_panel="Filters"
|
||||||
),
|
),
|
||||||
graph: bool = typer.Option(
|
|
||||||
False, "--graph", help="Enable graph in listing.", rich_help_panel="Filters"
|
|
||||||
),
|
|
||||||
no_graph: bool = typer.Option(
|
|
||||||
False, "--no-graph", help="Disable graph in listing.", rich_help_panel="Filters"
|
|
||||||
),
|
|
||||||
output: str = typer.Option(
|
output: str = typer.Option(
|
||||||
"table", "--output", "-o", help="Output: text, json, table.", rich_help_panel="Output"
|
"table", "--output", "-o", help="Output: text, json, table.", rich_help_panel="Output"
|
||||||
),
|
),
|
||||||
@@ -511,13 +481,6 @@ def list_cmd(
|
|||||||
backend, config = _get_backend_and_config(api_key, base_url)
|
backend, config = _get_backend_and_config(api_key, base_url)
|
||||||
ids = _resolve_ids(config, user_id=user_id, agent_id=agent_id, app_id=app_id, run_id=run_id)
|
ids = _resolve_ids(config, user_id=user_id, agent_id=agent_id, app_id=app_id, run_id=run_id)
|
||||||
|
|
||||||
if no_graph:
|
|
||||||
graph_enabled = False
|
|
||||||
elif graph:
|
|
||||||
graph_enabled = True
|
|
||||||
else:
|
|
||||||
graph_enabled = config.defaults.enable_graph
|
|
||||||
|
|
||||||
cmd_list(
|
cmd_list(
|
||||||
backend,
|
backend,
|
||||||
**ids,
|
**ids,
|
||||||
@@ -526,7 +489,6 @@ def list_cmd(
|
|||||||
category=category,
|
category=category,
|
||||||
after=after,
|
after=after,
|
||||||
before=before,
|
before=before,
|
||||||
enable_graph=graph_enabled,
|
|
||||||
output=output,
|
output=output,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ class Backend(ABC):
|
|||||||
infer: bool = True,
|
infer: bool = True,
|
||||||
expires: str | None = None,
|
expires: str | None = None,
|
||||||
categories: list[str] | None = None,
|
categories: list[str] | None = None,
|
||||||
enable_graph: bool = False,
|
|
||||||
) -> dict: ...
|
) -> dict: ...
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@@ -44,7 +43,6 @@ class Backend(ABC):
|
|||||||
keyword: bool = False,
|
keyword: bool = False,
|
||||||
filters: dict | None = None,
|
filters: dict | None = None,
|
||||||
fields: list[str] | None = None,
|
fields: list[str] | None = None,
|
||||||
enable_graph: bool = False,
|
|
||||||
) -> list[dict]: ...
|
) -> list[dict]: ...
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@@ -63,7 +61,6 @@ class Backend(ABC):
|
|||||||
category: str | None = None,
|
category: str | None = None,
|
||||||
after: str | None = None,
|
after: str | None = None,
|
||||||
before: str | None = None,
|
before: str | None = None,
|
||||||
enable_graph: bool = False,
|
|
||||||
) -> list[dict]: ...
|
) -> list[dict]: ...
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ class PlatformBackend(Backend):
|
|||||||
infer: bool = True,
|
infer: bool = True,
|
||||||
expires: str | None = None,
|
expires: str | None = None,
|
||||||
categories: list[str] | None = None,
|
categories: list[str] | None = None,
|
||||||
enable_graph: bool = False,
|
|
||||||
) -> dict:
|
) -> dict:
|
||||||
payload: dict[str, Any] = {}
|
payload: dict[str, Any] = {}
|
||||||
|
|
||||||
@@ -91,11 +90,9 @@ class PlatformBackend(Backend):
|
|||||||
payload["expiration_date"] = expires
|
payload["expiration_date"] = expires
|
||||||
if categories:
|
if categories:
|
||||||
payload["categories"] = categories
|
payload["categories"] = categories
|
||||||
if enable_graph:
|
|
||||||
payload["enable_graph"] = True
|
|
||||||
payload["source"] = "CLI"
|
payload["source"] = "CLI"
|
||||||
|
|
||||||
return self._request("POST", "/v1/memories/", json=payload)
|
return self._request("POST", "/v3/memories/add/", json=payload)
|
||||||
|
|
||||||
def _build_filters(
|
def _build_filters(
|
||||||
self,
|
self,
|
||||||
@@ -106,7 +103,7 @@ class PlatformBackend(Backend):
|
|||||||
run_id: str | None = None,
|
run_id: str | None = None,
|
||||||
extra_filters: dict | None = None,
|
extra_filters: dict | None = None,
|
||||||
) -> dict | None:
|
) -> dict | None:
|
||||||
"""Build a filters dict for v2 API endpoints.
|
"""Build a filters dict for v3 API endpoints.
|
||||||
|
|
||||||
Entity IDs are ANDed (all provided IDs must match).
|
Entity IDs are ANDed (all provided IDs must match).
|
||||||
Extra filters (date ranges, categories) are also ANDed.
|
Extra filters (date ranges, categories) are also ANDed.
|
||||||
@@ -152,7 +149,6 @@ class PlatformBackend(Backend):
|
|||||||
keyword: bool = False,
|
keyword: bool = False,
|
||||||
filters: dict | None = None,
|
filters: dict | None = None,
|
||||||
fields: list[str] | None = None,
|
fields: list[str] | None = None,
|
||||||
enable_graph: bool = False,
|
|
||||||
) -> list[dict]:
|
) -> list[dict]:
|
||||||
payload: dict[str, Any] = {"query": query, "top_k": top_k, "threshold": threshold}
|
payload: dict[str, Any] = {"query": query, "top_k": top_k, "threshold": threshold}
|
||||||
|
|
||||||
@@ -171,11 +167,9 @@ class PlatformBackend(Backend):
|
|||||||
payload["keyword_search"] = True
|
payload["keyword_search"] = True
|
||||||
if fields:
|
if fields:
|
||||||
payload["fields"] = fields
|
payload["fields"] = fields
|
||||||
if enable_graph:
|
|
||||||
payload["enable_graph"] = True
|
|
||||||
payload["source"] = "CLI"
|
payload["source"] = "CLI"
|
||||||
|
|
||||||
result = self._request("POST", "/v2/memories/search/", json=payload)
|
result = self._request("POST", "/v3/memories/search/", json=payload)
|
||||||
return (
|
return (
|
||||||
result
|
result
|
||||||
if isinstance(result, list)
|
if isinstance(result, list)
|
||||||
@@ -197,12 +191,11 @@ class PlatformBackend(Backend):
|
|||||||
category: str | None = None,
|
category: str | None = None,
|
||||||
after: str | None = None,
|
after: str | None = None,
|
||||||
before: str | None = None,
|
before: str | None = None,
|
||||||
enable_graph: bool = False,
|
|
||||||
) -> list[dict]:
|
) -> list[dict]:
|
||||||
payload: dict[str, Any] = {}
|
payload: dict[str, Any] = {}
|
||||||
params = {"page": str(page), "page_size": str(page_size)}
|
params = {"page": str(page), "page_size": str(page_size)}
|
||||||
|
|
||||||
# Build filters for v2 API — entity IDs and date filters go inside "filters"
|
# Build filters — entity IDs and date filters go inside "filters"
|
||||||
extra: dict[str, Any] = {}
|
extra: dict[str, Any] = {}
|
||||||
if category:
|
if category:
|
||||||
extra["categories"] = {"contains": category}
|
extra["categories"] = {"contains": category}
|
||||||
@@ -220,11 +213,9 @@ class PlatformBackend(Backend):
|
|||||||
)
|
)
|
||||||
if api_filters:
|
if api_filters:
|
||||||
payload["filters"] = api_filters
|
payload["filters"] = api_filters
|
||||||
if enable_graph:
|
|
||||||
payload["enable_graph"] = True
|
|
||||||
payload["source"] = "CLI"
|
payload["source"] = "CLI"
|
||||||
|
|
||||||
result = self._request("POST", "/v2/memories/", json=payload, params=params)
|
result = self._request("POST", "/v3/memories/", json=payload, params=params)
|
||||||
return (
|
return (
|
||||||
result
|
result
|
||||||
if isinstance(result, list)
|
if isinstance(result, list)
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ def cmd_config_show(*, output: str = "text") -> None:
|
|||||||
"agent_id": config.defaults.agent_id or None,
|
"agent_id": config.defaults.agent_id or None,
|
||||||
"app_id": config.defaults.app_id or None,
|
"app_id": config.defaults.app_id or None,
|
||||||
"run_id": config.defaults.run_id or None,
|
"run_id": config.defaults.run_id or None,
|
||||||
"enable_graph": config.defaults.enable_graph,
|
|
||||||
},
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"api_key": redact_key(config.platform.api_key),
|
"api_key": redact_key(config.platform.api_key),
|
||||||
@@ -73,10 +72,6 @@ def cmd_config_show(*, output: str = "text") -> None:
|
|||||||
"defaults.run_id",
|
"defaults.run_id",
|
||||||
config.defaults.run_id or f"[{DIM_COLOR}](not set)[/]",
|
config.defaults.run_id or f"[{DIM_COLOR}](not set)[/]",
|
||||||
)
|
)
|
||||||
table.add_row(
|
|
||||||
"defaults.enable_graph",
|
|
||||||
str(config.defaults.enable_graph).lower(),
|
|
||||||
)
|
|
||||||
table.add_row("", "")
|
table.add_row("", "")
|
||||||
|
|
||||||
# Platform
|
# Platform
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ def cmd_add(
|
|||||||
no_infer: bool,
|
no_infer: bool,
|
||||||
expires: str | None,
|
expires: str | None,
|
||||||
categories: str | None,
|
categories: str | None,
|
||||||
enable_graph: bool = False,
|
|
||||||
output: str = "text",
|
output: str = "text",
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Add a memory."""
|
"""Add a memory."""
|
||||||
@@ -145,7 +144,6 @@ def cmd_add(
|
|||||||
infer=not no_infer,
|
infer=not no_infer,
|
||||||
expires=expires,
|
expires=expires,
|
||||||
categories=cats,
|
categories=cats,
|
||||||
enable_graph=enable_graph,
|
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ts.error_msg = str(e)
|
ts.error_msg = str(e)
|
||||||
@@ -226,7 +224,6 @@ def cmd_search(
|
|||||||
keyword: bool,
|
keyword: bool,
|
||||||
filter_json: str | None,
|
filter_json: str | None,
|
||||||
fields: str | None,
|
fields: str | None,
|
||||||
enable_graph: bool = False,
|
|
||||||
output: str = "text",
|
output: str = "text",
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Search memories."""
|
"""Search memories."""
|
||||||
@@ -269,7 +266,6 @@ def cmd_search(
|
|||||||
keyword=keyword,
|
keyword=keyword,
|
||||||
filters=filters,
|
filters=filters,
|
||||||
fields=field_list,
|
fields=field_list,
|
||||||
enable_graph=enable_graph,
|
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print_error(err_console, str(e))
|
print_error(err_console, str(e))
|
||||||
@@ -356,7 +352,6 @@ def cmd_list(
|
|||||||
category: str | None,
|
category: str | None,
|
||||||
after: str | None,
|
after: str | None,
|
||||||
before: str | None,
|
before: str | None,
|
||||||
enable_graph: bool = False,
|
|
||||||
output: str = "table",
|
output: str = "table",
|
||||||
) -> None:
|
) -> None:
|
||||||
"""List memories."""
|
"""List memories."""
|
||||||
@@ -385,7 +380,6 @@ def cmd_list(
|
|||||||
category=category,
|
category=category,
|
||||||
after=after,
|
after=after,
|
||||||
before=before,
|
before=before,
|
||||||
enable_graph=enable_graph,
|
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print_error(err_console, str(e))
|
print_error(err_console, str(e))
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ class DefaultsConfig:
|
|||||||
agent_id: str = ""
|
agent_id: str = ""
|
||||||
app_id: str = ""
|
app_id: str = ""
|
||||||
run_id: str = ""
|
run_id: str = ""
|
||||||
enable_graph: bool = False
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -60,7 +59,6 @@ SHORT_KEY_ALIASES: dict[str, str] = {
|
|||||||
"agent_id": "defaults.agent_id",
|
"agent_id": "defaults.agent_id",
|
||||||
"app_id": "defaults.app_id",
|
"app_id": "defaults.app_id",
|
||||||
"run_id": "defaults.run_id",
|
"run_id": "defaults.run_id",
|
||||||
"enable_graph": "defaults.enable_graph",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -91,8 +89,6 @@ def load_config() -> Mem0Config:
|
|||||||
config.defaults.agent_id = defaults.get("agent_id", "")
|
config.defaults.agent_id = defaults.get("agent_id", "")
|
||||||
config.defaults.app_id = defaults.get("app_id", "")
|
config.defaults.app_id = defaults.get("app_id", "")
|
||||||
config.defaults.run_id = defaults.get("run_id", "")
|
config.defaults.run_id = defaults.get("run_id", "")
|
||||||
config.defaults.enable_graph = defaults.get("enable_graph", False)
|
|
||||||
|
|
||||||
telemetry = data.get("telemetry", {})
|
telemetry = data.get("telemetry", {})
|
||||||
config.telemetry.anonymous_id = telemetry.get("anonymous_id", "")
|
config.telemetry.anonymous_id = telemetry.get("anonymous_id", "")
|
||||||
|
|
||||||
@@ -121,10 +117,6 @@ def load_config() -> Mem0Config:
|
|||||||
if env_run_id:
|
if env_run_id:
|
||||||
config.defaults.run_id = env_run_id
|
config.defaults.run_id = env_run_id
|
||||||
|
|
||||||
env_graph = os.environ.get("MEM0_ENABLE_GRAPH")
|
|
||||||
if env_graph:
|
|
||||||
config.defaults.enable_graph = env_graph.lower() in ("true", "1", "yes")
|
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
@@ -139,7 +131,6 @@ def save_config(config: Mem0Config) -> None:
|
|||||||
"agent_id": config.defaults.agent_id,
|
"agent_id": config.defaults.agent_id,
|
||||||
"app_id": config.defaults.app_id,
|
"app_id": config.defaults.app_id,
|
||||||
"run_id": config.defaults.run_id,
|
"run_id": config.defaults.run_id,
|
||||||
"enable_graph": config.defaults.enable_graph,
|
|
||||||
},
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"api_key": config.platform.api_key,
|
"api_key": config.platform.api_key,
|
||||||
|
|||||||
@@ -224,24 +224,13 @@ class TestCLIIsolated:
|
|||||||
|
|
||||||
|
|
||||||
class TestCLINewFeatures:
|
class TestCLINewFeatures:
|
||||||
"""Tests for MCP parity features: --graph, --limit, entities delete."""
|
"""Tests for MCP parity features: --limit, entities delete."""
|
||||||
|
|
||||||
def test_add_help_has_graph(self):
|
def test_search_help_has_limit(self):
|
||||||
result = _run(["add", "--help"])
|
|
||||||
assert result.returncode == 0
|
|
||||||
assert "--graph" in result.stdout
|
|
||||||
|
|
||||||
def test_search_help_has_graph_and_limit(self):
|
|
||||||
result = _run(["search", "--help"])
|
result = _run(["search", "--help"])
|
||||||
assert result.returncode == 0
|
assert result.returncode == 0
|
||||||
assert "--graph" in result.stdout
|
|
||||||
assert "--limit" in result.stdout
|
assert "--limit" in result.stdout
|
||||||
|
|
||||||
def test_list_help_has_graph(self):
|
|
||||||
result = _run(["list", "--help"])
|
|
||||||
assert result.returncode == 0
|
|
||||||
assert "--graph" in result.stdout
|
|
||||||
|
|
||||||
def test_delete_entity_via_delete_flag(self):
|
def test_delete_entity_via_delete_flag(self):
|
||||||
"""delete --entity should appear in help output."""
|
"""delete --entity should appear in help output."""
|
||||||
result = _run(["delete", "--help"])
|
result = _run(["delete", "--help"])
|
||||||
|
|||||||
@@ -997,85 +997,6 @@ class TestEntitiesDeleteCommand:
|
|||||||
mock_backend.delete_entities.assert_not_called()
|
mock_backend.delete_entities.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
class TestEnableGraph:
|
|
||||||
def test_add_with_graph(self, mock_backend):
|
|
||||||
console, _buf = _make_console()
|
|
||||||
err_console, _err_buf = _make_err_console()
|
|
||||||
with (
|
|
||||||
patch("mem0_cli.commands.memory.console", console),
|
|
||||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
|
||||||
):
|
|
||||||
cmd_add(
|
|
||||||
mock_backend,
|
|
||||||
"test",
|
|
||||||
user_id="alice",
|
|
||||||
agent_id=None,
|
|
||||||
app_id=None,
|
|
||||||
run_id=None,
|
|
||||||
messages=None,
|
|
||||||
file=None,
|
|
||||||
metadata=None,
|
|
||||||
immutable=False,
|
|
||||||
no_infer=False,
|
|
||||||
expires=None,
|
|
||||||
categories=None,
|
|
||||||
enable_graph=True,
|
|
||||||
output="text",
|
|
||||||
)
|
|
||||||
call_kwargs = mock_backend.add.call_args
|
|
||||||
assert call_kwargs.kwargs.get("enable_graph") is True
|
|
||||||
|
|
||||||
def test_search_with_graph(self, mock_backend):
|
|
||||||
console, _buf = _make_console()
|
|
||||||
err_console, _err_buf = _make_err_console()
|
|
||||||
with (
|
|
||||||
patch("mem0_cli.commands.memory.console", console),
|
|
||||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
|
||||||
):
|
|
||||||
cmd_search(
|
|
||||||
mock_backend,
|
|
||||||
"test",
|
|
||||||
user_id="alice",
|
|
||||||
agent_id=None,
|
|
||||||
app_id=None,
|
|
||||||
run_id=None,
|
|
||||||
top_k=10,
|
|
||||||
threshold=0.3,
|
|
||||||
rerank=False,
|
|
||||||
keyword=False,
|
|
||||||
filter_json=None,
|
|
||||||
fields=None,
|
|
||||||
enable_graph=True,
|
|
||||||
output="text",
|
|
||||||
)
|
|
||||||
call_kwargs = mock_backend.search.call_args
|
|
||||||
assert call_kwargs.kwargs.get("enable_graph") is True
|
|
||||||
|
|
||||||
def test_list_with_graph(self, mock_backend):
|
|
||||||
console, _buf = _make_console()
|
|
||||||
err_console, _err_buf = _make_err_console()
|
|
||||||
with (
|
|
||||||
patch("mem0_cli.commands.memory.console", console),
|
|
||||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
|
||||||
):
|
|
||||||
cmd_list(
|
|
||||||
mock_backend,
|
|
||||||
user_id="alice",
|
|
||||||
agent_id=None,
|
|
||||||
app_id=None,
|
|
||||||
run_id=None,
|
|
||||||
page=1,
|
|
||||||
page_size=100,
|
|
||||||
category=None,
|
|
||||||
after=None,
|
|
||||||
before=None,
|
|
||||||
enable_graph=True,
|
|
||||||
output="table",
|
|
||||||
)
|
|
||||||
call_kwargs = mock_backend.list_memories.call_args
|
|
||||||
assert call_kwargs.kwargs.get("enable_graph") is True
|
|
||||||
|
|
||||||
|
|
||||||
class TestEventCommands:
|
class TestEventCommands:
|
||||||
def test_event_list_table(self, mock_backend):
|
def test_event_list_table(self, mock_backend):
|
||||||
console, buf = _make_console()
|
console, buf = _make_console()
|
||||||
|
|||||||
@@ -121,46 +121,6 @@ class TestConfig:
|
|||||||
assert config.defaults.agent_id == ""
|
assert config.defaults.agent_id == ""
|
||||||
assert config.defaults.app_id == ""
|
assert config.defaults.app_id == ""
|
||||||
assert config.defaults.run_id == ""
|
assert config.defaults.run_id == ""
|
||||||
assert config.defaults.enable_graph is False
|
|
||||||
|
|
||||||
def test_enable_graph_save_and_load(self, isolate_config):
|
|
||||||
config = Mem0Config()
|
|
||||||
config.defaults.enable_graph = True
|
|
||||||
save_config(config)
|
|
||||||
loaded = load_config()
|
|
||||||
assert loaded.defaults.enable_graph is True
|
|
||||||
|
|
||||||
def test_enable_graph_env_var_true(self, isolate_config, monkeypatch):
|
|
||||||
monkeypatch.setenv("MEM0_ENABLE_GRAPH", "true")
|
|
||||||
loaded = load_config()
|
|
||||||
assert loaded.defaults.enable_graph is True
|
|
||||||
|
|
||||||
def test_enable_graph_env_var_false(self, isolate_config, monkeypatch):
|
|
||||||
config = Mem0Config()
|
|
||||||
config.defaults.enable_graph = True
|
|
||||||
save_config(config)
|
|
||||||
monkeypatch.setenv("MEM0_ENABLE_GRAPH", "false")
|
|
||||||
loaded = load_config()
|
|
||||||
assert loaded.defaults.enable_graph is False
|
|
||||||
|
|
||||||
def test_backward_compat_no_enable_graph_key(self, isolate_config):
|
|
||||||
"""Old config files without 'enable_graph' key should default to False."""
|
|
||||||
import json
|
|
||||||
|
|
||||||
from mem0_cli.config import CONFIG_FILE, ensure_config_dir
|
|
||||||
|
|
||||||
ensure_config_dir()
|
|
||||||
data = {
|
|
||||||
"version": 1,
|
|
||||||
"defaults": {"user_id": "alice"},
|
|
||||||
"platform": {"api_key": "m0-test", "base_url": "https://api.mem0.ai"},
|
|
||||||
}
|
|
||||||
with open(CONFIG_FILE, "w") as f:
|
|
||||||
json.dump(data, f)
|
|
||||||
|
|
||||||
loaded = load_config()
|
|
||||||
assert loaded.defaults.enable_graph is False
|
|
||||||
assert loaded.defaults.user_id == "alice"
|
|
||||||
|
|
||||||
|
|
||||||
class TestNestedAccess:
|
class TestNestedAccess:
|
||||||
@@ -192,11 +152,6 @@ class TestNestedAccess:
|
|||||||
assert set_nested_value(config, "defaults.user_id", "bob")
|
assert set_nested_value(config, "defaults.user_id", "bob")
|
||||||
assert config.defaults.user_id == "bob"
|
assert config.defaults.user_id == "bob"
|
||||||
|
|
||||||
def test_set_defaults_enable_graph(self):
|
|
||||||
config = Mem0Config()
|
|
||||||
assert set_nested_value(config, "defaults.enable_graph", "true")
|
|
||||||
assert config.defaults.enable_graph is True
|
|
||||||
|
|
||||||
|
|
||||||
class TestResolveIds:
|
class TestResolveIds:
|
||||||
def test_cli_flag_overrides_default(self):
|
def test_cli_flag_overrides_default(self):
|
||||||
|
|||||||
@@ -1269,6 +1269,16 @@ See the [TypeScript SDK migration guide](https://docs.mem0.ai/migration/ts-v2-to
|
|||||||
|
|
||||||
<Tab title="CLI">
|
<Tab title="CLI">
|
||||||
|
|
||||||
|
<Update label="2026-04-22" description="Python v0.2.4 / Node v0.2.4">
|
||||||
|
|
||||||
|
**New Features:**
|
||||||
|
- **V3 API Routes:** Migrated `add`, `search`, and `list` commands from v1/v2 to v3 API endpoints — `POST /v3/memories/add/`, `POST /v3/memories/search/`, `POST /v3/memories/`. Aligns both CLIs with the Python and TypeScript SDKs which already use v3 ([#4916](https://github.com/mem0ai/mem0/pull/4916))
|
||||||
|
|
||||||
|
**Breaking Changes:**
|
||||||
|
- **`--graph` / `--no-graph` removed:** The `enable_graph` config option, `--graph` and `--no-graph` CLI flags, and `MEM0_ENABLE_GRAPH` environment variable have been removed from both CLIs. Graph memory is now a project-level setting on the Platform ([#4916](https://github.com/mem0ai/mem0/pull/4916))
|
||||||
|
|
||||||
|
</Update>
|
||||||
|
|
||||||
<Update label="2026-04-11" description="Python v0.2.3 / Node v0.2.3">
|
<Update label="2026-04-11" description="Python v0.2.3 / Node v0.2.3">
|
||||||
|
|
||||||
**Bug Fixes:**
|
**Bug Fixes:**
|
||||||
|
|||||||
Reference in New Issue
Block a user