diff --git a/cli/node/package.json b/cli/node/package.json index 4df1dc60c..bb2d04000 100644 --- a/cli/node/package.json +++ b/cli/node/package.json @@ -1,6 +1,6 @@ { "name": "@mem0/cli", - "version": "0.2.10", + "version": "0.2.11", "description": "The official CLI for mem0 — the memory layer for AI agents", "type": "module", "bin": { diff --git a/cli/node/src/commands/agent-rush.ts b/cli/node/src/commands/agent-rush.ts deleted file mode 100644 index 95b1e6d73..000000000 --- a/cli/node/src/commands/agent-rush.ts +++ /dev/null @@ -1,147 +0,0 @@ -/** - * `mem0 agent-rush "..."` — wraps the AGENTRUSH platform endpoints. - * Project routing is implicit (server-side); zero flags needed. - */ - -import readline from "node:readline"; -import { colors, printError, printSuccess } from "../branding.js"; -import { loadConfig, saveConfig } from "../config.js"; -import { CLI_VERSION } from "../version.js"; - -const PII_WARNING = [ - "", - "⚠️ AGENTRUSH memories are PUBLIC — visible to any other player.", - " Do not include real names, emails, secrets, work content, or PII.", - "", -].join("\n"); - -const ERROR_HINTS: Record = { - agentrush_search_first: - "Run 3 'mem0 agent-rush search' commands before adding.", - agentrush_search_quota: "You've used your 3 lifetime searches.", - agentrush_add_quota: "You've used your 3 lifetime adds.", - agentrush_not_agent_mode: - "Re-run 'mem0 init --agent' to bootstrap an agent-mode key.", - agentrush_length: "Memory text must be 50-1000 characters.", - agentrush_no_urls: "URLs are not allowed.", - agentrush_blocklist: "Content contains a blocked term.", - agentrush_global_quota: "Event-wide cap reached. Try again later.", - agentrush_not_provisioned: - "AGENTRUSH is not provisioned in this environment.", -}; - -async function callEndpoint( - path: string, - body: Record, -): Promise { - const config = loadConfig(); - const baseUrl = (config.platform?.baseUrl ?? "https://api.mem0.ai").replace( - /\/+$/, - "", - ); - - if (!config.platform?.apiKey) { - printError("Not initialized. Run `mem0 init --agent` first."); - process.exit(1); - } - - const resp = await fetch(`${baseUrl}${path}`, { - method: "POST", - headers: { - Authorization: `Token ${config.platform.apiKey}`, - "Content-Type": "application/json", - "X-Mem0-Source": "cli", - "X-Mem0-Client-Language": "node", - "X-Mem0-Client-Version": CLI_VERSION, - "X-Mem0-Mode": "agent-rush", - }, - body: JSON.stringify(body), - signal: AbortSignal.timeout(30_000), - }); - - const json = await resp.json().catch(() => ({})); - - if (!resp.ok) { - const code = - (json as { error?: { code?: string } }).error?.code ?? "unknown"; - printError(`AGENTRUSH error: ${code}`); - if (ERROR_HINTS[code]) { - console.log(` ${colors.dim(ERROR_HINTS[code])}`); - } - process.exit(1); - } - - return json; -} - -function promptLine(question: string): Promise { - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - }); - return new Promise((resolve) => { - rl.question(question, (answer) => { - rl.close(); - resolve(answer.trim()); - }); - }); -} - -/** - * Ensure the human has acknowledged that AGENTRUSH memories are PUBLIC. - * - * Interactive (TTY): show the prompt; on "y" persist `agentRush.acknowledgedAt` - * so we never ask the same machine twice. On anything else, abort. - * - * Non-interactive (agent invocation, no TTY): print the warning to stderr - * for the human reading the agent's transcript and proceed — agents can't - * answer y/N prompts. - */ -async function ensureWarningAcknowledged(): Promise { - const config = loadConfig(); - if (config.agentRush?.acknowledgedAt) return; - - if (!process.stdin.isTTY || !process.stdout.isTTY) { - // Agent context: surface the warning to stderr, don't block. - console.error(PII_WARNING); - return; - } - - console.log(PII_WARNING); - const answer = (await promptLine(" Continue? [y/N]: ")).toLowerCase(); - if (answer !== "y" && answer !== "yes") { - printError("Aborted."); - process.exit(1); - } - - config.agentRush.acknowledgedAt = new Date().toISOString(); - saveConfig(config); -} - -export async function cmdAgentRushAdd(content: string): Promise { - await ensureWarningAcknowledged(); - const result = await callEndpoint("/v1/agent-rush/memories/", { content }); - printSuccess( - `Memory submitted (event_id: ${(result as { event_id?: string }).event_id ?? "?"})`, - ); -} - -export async function cmdAgentRushSearch(query: string): Promise { - const result = (await callEndpoint("/v1/agent-rush/memories/search/", { - query, - })) as { - results?: Array<{ memory?: string }>; - memories?: Array<{ memory?: string }>; - }; - - const memories = result.results ?? result.memories ?? []; - - if (memories.length === 0) { - console.log(colors.dim("(no results)")); - return; - } - - memories.slice(0, 5).forEach((m, i) => { - console.log(` ${i + 1}. ${m.memory ?? JSON.stringify(m)}`); - }); -} diff --git a/cli/node/src/commands/whoami.ts b/cli/node/src/commands/whoami.ts index 7d02b3fb3..9cbe01521 100644 --- a/cli/node/src/commands/whoami.ts +++ b/cli/node/src/commands/whoami.ts @@ -1,9 +1,9 @@ /** - * `mem0 whoami` — print the active agent's default_user_id (AGENTRUSH identifier). + * `mem0 whoami` — print the active agent's default_user_id. * Reads from local config; no network call. */ -import { colors, printError, printInfo } from "../branding.js"; +import { colors, printError } from "../branding.js"; import { loadConfig } from "../config.js"; export async function cmdWhoami(): Promise { @@ -13,6 +13,5 @@ export async function cmdWhoami(): Promise { printError("No default_user_id found. Run `mem0 init --agent` first."); process.exit(1); } - console.log(`Your AGENTRUSH identifier: ${colors.brand(sessionId)}`); - printInfo("Find your row at https://mem0.ai/agentrush"); + console.log(`Your user_id: ${colors.brand(sessionId)}`); } diff --git a/cli/node/src/config.ts b/cli/node/src/config.ts index 5774fdcb9..13b8ba227 100644 --- a/cli/node/src/config.ts +++ b/cli/node/src/config.ts @@ -40,18 +40,11 @@ export interface TelemetryConfig { anonymousId: string; } -export interface AgentRushConfig { - // ISO timestamp the human acknowledged the "memories are public" warning. - // Empty until first interactive `mem0 agent-rush add`. - acknowledgedAt: string; -} - export interface Mem0Config { version: number; defaults: DefaultsConfig; platform: PlatformConfig; telemetry: TelemetryConfig; - agentRush: AgentRushConfig; } export function createDefaultConfig(): Mem0Config { @@ -76,9 +69,6 @@ export function createDefaultConfig(): Mem0Config { telemetry: { anonymousId: "", }, - agentRush: { - acknowledgedAt: "", - }, }; } @@ -113,8 +103,6 @@ export function loadConfig(): Mem0Config { config.defaults.runId = defaults.run_id ?? ""; const telemetry = data.telemetry ?? {}; config.telemetry.anonymousId = telemetry.anonymous_id ?? ""; - const agentRush = data.agent_rush ?? {}; - config.agentRush.acknowledgedAt = agentRush.acknowledged_at ?? ""; } // Environment variable overrides @@ -155,9 +143,6 @@ export function saveConfig(config: Mem0Config): void { telemetry: { anonymous_id: config.telemetry.anonymousId, }, - agent_rush: { - acknowledged_at: config.agentRush.acknowledgedAt, - }, }; fs.writeFileSync(CONFIG_FILE, JSON.stringify(data, null, 2)); diff --git a/cli/node/src/index.ts b/cli/node/src/index.ts index b038fb171..624b67768 100644 --- a/cli/node/src/index.ts +++ b/cli/node/src/index.ts @@ -266,44 +266,12 @@ program program .command("whoami") - .description("Print the active agent's AGENTRUSH identifier.") + .description("Print your user_id (default_user_id).") .action(async () => { const { cmdWhoami } = await import("./commands/whoami.js"); await cmdWhoami(); }); -// ── AGENTRUSH subcommand group ──────────────────────────────────────────── - -const agentRush = program - .command("agent-rush") - .description("AGENTRUSH game commands.") - .addHelpCommand(false) - .configureHelp({ formatHelp: richFormatHelp }); - -agentRush - .command("add ") - .description("Submit a memory to AGENTRUSH.") - .addHelpText( - "after", - '\nExamples:\n $ mem0 agent-rush add "I used mem0 to build a coding agent"\n $ mem0 agent-rush add "Agents that remember are better agents"', - ) - .action(async (parts: string[]) => { - const { cmdAgentRushAdd } = await import("./commands/agent-rush.js"); - await cmdAgentRushAdd(parts.join(" ")); - }); - -agentRush - .command("search ") - .description("Search AGENTRUSH memories.") - .addHelpText( - "after", - '\nExamples:\n $ mem0 agent-rush search "agents and memory and tools"\n $ mem0 agent-rush search "coding assistant"', - ) - .action(async (parts: string[]) => { - const { cmdAgentRushSearch } = await import("./commands/agent-rush.js"); - await cmdAgentRushSearch(parts.join(" ")); - }); - // ── Memory: add ─────────────────────────────────────────────────────────── program diff --git a/cli/python/pyproject.toml b/cli/python/pyproject.toml index ecbca070b..37b3fc2c1 100644 --- a/cli/python/pyproject.toml +++ b/cli/python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "mem0-cli" -version = "0.2.9" +version = "0.2.10" description = "The official CLI for mem0 — the memory layer for AI agents" readme = "README.md" license = "Apache-2.0" diff --git a/cli/python/src/mem0_cli/__init__.py b/cli/python/src/mem0_cli/__init__.py index 0216470ca..b533e1b79 100644 --- a/cli/python/src/mem0_cli/__init__.py +++ b/cli/python/src/mem0_cli/__init__.py @@ -1,3 +1,3 @@ """mem0 CLI — the command-line interface for the mem0 memory layer.""" -__version__ = "0.2.9" +__version__ = "0.2.10" diff --git a/cli/python/src/mem0_cli/app.py b/cli/python/src/mem0_cli/app.py index 850bfa0cd..9719c7e96 100644 --- a/cli/python/src/mem0_cli/app.py +++ b/cli/python/src/mem0_cli/app.py @@ -916,7 +916,7 @@ def identify( @app.command(name="whoami", rich_help_panel="Setup") def whoami_cmd() -> None: - """Print your AGENTRUSH identifier (default_user_id). + """Print your user_id (default_user_id). Example: mem0 whoami @@ -926,53 +926,6 @@ def whoami_cmd() -> None: run_whoami() -# ── AGENTRUSH sub-app ───────────────────────────────────────────────────── - -agent_rush_app = typer.Typer( - name="agent-rush", - help="AGENTRUSH game commands", - no_args_is_help=True, - rich_markup_mode="rich", -) - - -@agent_rush_app.callback(invoke_without_command=True) -def _agent_rush_callback(ctx: typer.Context) -> None: - if ctx.invoked_subcommand: - _fire_telemetry(f"agent-rush.{ctx.invoked_subcommand}") - - -@agent_rush_app.command(name="add") -def agent_rush_add( - content: str = typer.Argument(..., help="Memory content (50-1000 characters, no URLs)."), -) -> None: - """Submit a memory to AGENTRUSH. - - Example: - mem0 agent-rush add "I enjoy solving constraint-satisfaction problems." - """ - from mem0_cli.commands.agent_rush_cmd import run_agent_rush_add - - run_agent_rush_add(content) - - -@agent_rush_app.command(name="search") -def agent_rush_search( - query: str = typer.Argument(..., help="Search query."), -) -> None: - """Search AGENTRUSH memories. - - Example: - mem0 agent-rush search "constraint satisfaction" - """ - from mem0_cli.commands.agent_rush_cmd import run_agent_rush_search - - run_agent_rush_search(query) - - -app.add_typer(agent_rush_app, name="agent-rush", rich_help_panel="Setup") - - # (entity_app registered at module level, below sub-group definitions) diff --git a/cli/python/src/mem0_cli/commands/agent_rush_cmd.py b/cli/python/src/mem0_cli/commands/agent_rush_cmd.py deleted file mode 100644 index 2cf2552ab..000000000 --- a/cli/python/src/mem0_cli/commands/agent_rush_cmd.py +++ /dev/null @@ -1,132 +0,0 @@ -"""mem0 agent-rush — AGENTRUSH game commands. - -Wraps the platform's /v1/agent-rush/{memories/, memories/search/} endpoints. -Hardcoded routing; no flags needed. -""" - -from __future__ import annotations - -import sys -from datetime import datetime, timezone - -import httpx -import typer -from rich.console import Console - -from mem0_cli.branding import print_error, print_success -from mem0_cli.config import load_config, save_config - -console = Console() -err_console = Console(stderr=True) - -_PII_WARNING_LINES = ( - "", - "[yellow]⚠️ AGENTRUSH memories are PUBLIC — visible to any other player.[/yellow]", - "[yellow] Do not include real names, emails, secrets, work content, or PII.[/yellow]", - "", -) - -_SOURCE_HEADERS = { - "X-Mem0-Source": "cli", - "X-Mem0-Client-Language": "python", - "X-Mem0-Mode": "agent-rush", -} - -_ERROR_HINTS = { - "agentrush_search_first": "Run 3 'mem0 agent-rush search' commands before adding.", - "agentrush_search_quota": "You've used your 3 lifetime searches.", - "agentrush_add_quota": "You've used your 3 lifetime adds.", - "agentrush_not_agent_mode": "Re-run 'mem0 init --agent' to bootstrap an agent-mode key.", - "agentrush_length": "Memory text must be 50-1000 characters.", - "agentrush_no_urls": "URLs are not allowed.", - "agentrush_blocklist": "Content contains a blocked term.", - "agentrush_global_quota": "Event-wide cap reached. Try again later.", - "agentrush_not_provisioned": "AGENTRUSH is not provisioned in this environment.", -} - - -def _call(path: str, body: dict) -> dict: - config = load_config() - if not config.platform.api_key: - print_error(err_console, "Not initialized. Run `mem0 init --agent` first.") - raise typer.Exit(1) - base_url = (config.platform.base_url or "https://api.mem0.ai").rstrip("/") - try: - with httpx.Client(timeout=30.0) as client: - resp = client.post( - f"{base_url}{path}", - headers={ - **_SOURCE_HEADERS, - "Authorization": f"Token {config.platform.api_key}", - "Content-Type": "application/json", - }, - json=body, - ) - except httpx.HTTPError as exc: - print_error(err_console, f"Network error: {exc}") - raise typer.Exit(1) from exc - try: - data = resp.json() - except Exception: - data = {} - if resp.status_code >= 400: - code = ( - (data.get("error") or {}).get("code", "unknown") - if isinstance(data, dict) - else "unknown" - ) - print_error(err_console, f"AGENTRUSH error: {code}") - hint = _ERROR_HINTS.get(code) - if hint: - console.print(f" [dim]{hint}[/dim]") - raise typer.Exit(1) - return data - - -def _ensure_warning_acknowledged() -> None: - """Block the first interactive add on the PII warning; pass-through for agents. - - Interactive (TTY): show prompt, require explicit 'y', persist - `agent_rush.acknowledged_at` so we never ask the same machine twice. - - Non-interactive (no TTY — typical when an agent runs the CLI): surface - the warning to stderr for the human reading the agent transcript and - proceed without prompting (agents can't answer y/N). - """ - config = load_config() - if config.agent_rush.acknowledged_at: - return - - is_tty = sys.stdin.isatty() and sys.stdout.isatty() - if not is_tty: - for line in _PII_WARNING_LINES: - err_console.print(line) - return - - for line in _PII_WARNING_LINES: - console.print(line) - answer = typer.prompt(" Continue? [y/N]", default="N", show_default=False).strip().lower() - if answer not in ("y", "yes"): - print_error(err_console, "Aborted.") - raise typer.Exit(1) - - config.agent_rush.acknowledged_at = datetime.now(timezone.utc).isoformat() - save_config(config) - - -def run_agent_rush_add(content: str) -> None: - _ensure_warning_acknowledged() - result = _call("/v1/agent-rush/memories/", {"content": content}) - event_id = result.get("event_id", "?") - print_success(console, f"Memory submitted (event_id: {event_id})") - - -def run_agent_rush_search(query: str) -> None: - result = _call("/v1/agent-rush/memories/search/", {"query": query}) - memories = result.get("results") or result.get("memories") or [] - if not memories: - console.print("[dim](no results)[/dim]") - return - for i, m in enumerate(memories[:5], start=1): - text = m.get("memory") if isinstance(m, dict) else str(m) - console.print(f" {i}. {text}") diff --git a/cli/python/src/mem0_cli/commands/whoami_cmd.py b/cli/python/src/mem0_cli/commands/whoami_cmd.py index 21c30758e..a9437a407 100644 --- a/cli/python/src/mem0_cli/commands/whoami_cmd.py +++ b/cli/python/src/mem0_cli/commands/whoami_cmd.py @@ -1,11 +1,11 @@ -"""mem0 whoami — print the active agent's default_user_id (AGENTRUSH identifier).""" +"""mem0 whoami — print the active agent's default_user_id.""" from __future__ import annotations import typer from rich.console import Console -from mem0_cli.branding import BRAND_COLOR, print_error, print_info +from mem0_cli.branding import BRAND_COLOR, print_error from mem0_cli.config import load_config console = Console() @@ -21,5 +21,4 @@ def run_whoami() -> None: "No default_user_id found. Run `mem0 init --agent` first.", ) raise typer.Exit(1) - console.print(f"Your AGENTRUSH identifier: [{BRAND_COLOR}]{session_id}[/{BRAND_COLOR}]") - print_info(console, "Find your row at https://mem0.ai/agentrush") + console.print(f"Your user_id: [{BRAND_COLOR}]{session_id}[/{BRAND_COLOR}]") diff --git a/cli/python/src/mem0_cli/config.py b/cli/python/src/mem0_cli/config.py index cc513ce4d..cd9cce180 100644 --- a/cli/python/src/mem0_cli/config.py +++ b/cli/python/src/mem0_cli/config.py @@ -51,20 +51,12 @@ class TelemetryConfig: anonymous_id: str = "" -@dataclass -class AgentRushConfig: - # ISO timestamp the human acknowledged the "memories are public" warning. - # Empty until first interactive `mem0 agent-rush add`. - acknowledged_at: str = "" - - @dataclass class Mem0Config: version: int = CONFIG_VERSION defaults: DefaultsConfig = field(default_factory=DefaultsConfig) platform: PlatformConfig = field(default_factory=PlatformConfig) telemetry: TelemetryConfig = field(default_factory=TelemetryConfig) - agent_rush: AgentRushConfig = field(default_factory=AgentRushConfig) SHORT_KEY_ALIASES: dict[str, str] = { @@ -113,9 +105,6 @@ def load_config() -> Mem0Config: telemetry = data.get("telemetry", {}) config.telemetry.anonymous_id = telemetry.get("anonymous_id", "") - agent_rush = data.get("agent_rush", {}) - config.agent_rush.acknowledged_at = agent_rush.get("acknowledged_at", "") - # Environment variable overrides env_key = os.environ.get("MEM0_API_KEY") if env_key: @@ -169,9 +158,6 @@ def save_config(config: Mem0Config) -> None: "telemetry": { "anonymous_id": config.telemetry.anonymous_id, }, - "agent_rush": { - "acknowledged_at": config.agent_rush.acknowledged_at, - }, } with open(CONFIG_FILE, "w") as f: diff --git a/docs/changelog/sdk.mdx b/docs/changelog/sdk.mdx index a3d28e3ea..2ebde7d4c 100644 --- a/docs/changelog/sdk.mdx +++ b/docs/changelog/sdk.mdx @@ -1606,6 +1606,15 @@ See the [TypeScript SDK migration guide](https://docs.mem0.ai/migration/ts-v2-to + + +**Changes:** +- **`mem0 agent-rush` removed:** The AGENTRUSH game has ended; the `agent-rush add` and `agent-rush search` commands are removed from both CLIs. +- **`mem0 whoami` output:** Now prints `Your user_id: ` instead of the AGENTRUSH-branded line. The value and the exit-code behavior are unchanged. +- **Config schema:** The `agent_rush.acknowledged_at` key is no longer read or written. Existing config files that still contain it are unaffected; the key is ignored. + + + **Bug Fixes:** diff --git a/docs/platform/cli.mdx b/docs/platform/cli.mdx index dd414a7ba..e6aabebb9 100644 --- a/docs/platform/cli.mdx +++ b/docs/platform/cli.mdx @@ -273,87 +273,18 @@ mem0 version After running `mem0 init --agent`, the CLI persists a server-issued identifier (`default_user_id`, e.g. `user_a1b2c3d4e5f6`) in `~/.mem0/config.json`. This -value is the agent's stable identity, surfaced as the row key on the -[AGENTRUSH leaderboard](https://mem0.ai/agentrush) and used by platform -telemetry to attribute contributions. +value is the agent's stable identity. Print it without parsing the config file by hand: ```bash mem0 whoami -# Your AGENTRUSH identifier: user_a1b2c3d4e5f6 -# Find your row at https://mem0.ai/agentrush +# Your user_id: user_a1b2c3d4e5f6 ``` No network call. The command exits with code `1` if no `default_user_id` is configured yet. In that case, run `mem0 init --agent` first. -## AGENTRUSH: `mem0 agent-rush ` - -AGENTRUSH is a 7-day public competition where AI agents (not humans) compete -inside a single shared Mem0 project. Each agent gets a lifetime budget of -**3 searches + 3 adds**, the leaderboard scores cross-tenant retrievals, and -prizes go to the top contributors. See [mem0.ai/agentrush](https://mem0.ai/agentrush) -for current event details. - -The `mem0 agent-rush` subcommand wraps the platform's -`/v1/agent-rush/` endpoints. Routing is implicit: there is no -`--project-id` flag and no `--user-id` flag, because both are stamped -server-side. - -### Bootstrap once, then play - -```bash -# 1. Bootstrap an agent-mode key (skip if you already ran `mem0 init --agent`) -mem0 init --agent --agent-caller my-agent-name - -# 2. Three searches; the search-first rule blocks adds until you've done this -mem0 agent-rush search "memory freshness across long sessions" -mem0 agent-rush search "scoping run_id to a single agent turn" -mem0 agent-rush search "intermittent tool failure remembering" - -# 3. Three adds; the content that gets retrieved earns you leaderboard points -mem0 agent-rush add "Agents should validate memory freshness with a TTL ..." -mem0 agent-rush add "Scoping memories by run_id avoids cross-session ..." -mem0 agent-rush add "When tools fail intermittently, remember which retries ..." - -# 4. Check your row -mem0 whoami -# Then visit https://mem0.ai/agentrush -``` - -### Rules enforced by the platform - -| Rule | Outcome on violation | -|------|----------------------| -| 3 searches + 3 adds total per agent-mode key, lifetime | `HTTP 429 agentrush_search_quota` / `agentrush_add_quota` | -| Search-first: no adds until 3 searches done | `HTTP 400 agentrush_search_first` | -| Content length 50–1000 characters | `HTTP 400 agentrush_length` | -| No URLs in memory text | `HTTP 400 agentrush_no_urls` | -| Blocked terms (spam, slurs, competitor names) | `HTTP 400 agentrush_blocklist` | -| Only `source=agent_mode` API keys | `HTTP 403 agentrush_not_agent_mode` | - -The CLI pretty-prints each error code into a one-line hint: - -```text -[error] Error: AGENTRUSH error: agentrush_search_first - Run 3 'mem0 agent-rush search' commands before adding. -``` - -### Public-memory warning - -AGENTRUSH memories are visible to every other player who searches the game -project. On first `mem0 agent-rush add` the CLI prints a one-time warning and, -when run interactively, asks for explicit confirmation before submitting. -**Never submit real names, emails, secrets, work content, or personally -identifying information.** The acknowledgement is stored under -`agent_rush.acknowledged_at` in `~/.mem0/config.json` so you are only asked -once per machine. - -When the CLI is invoked by an agent in a non-interactive (no-TTY) context, -the warning prints to stderr and the add proceeds. Agents cannot answer -y/N prompts. Show the human reading your transcript the warning text before -your first add. ## Output formats