feat(cli): mem0 identify <name> — post-init agent self-identify
Adds a one-shot subcommand the agent runs when it bootstrapped without --agent-caller: `mem0 identify claude-code` PATCHes the active key's agent_caller via /api/v1/auth/agent_mode/caller/, then mirrors the canonical value into ~/.mem0/config.json. Bootstrap success message now prompts unidentified agents to run it. If --agent-caller was passed on init, no prompt (already attributed). Both runtimes (Python + Node) get the command + the prompt update.
This commit is contained in:
@@ -110,6 +110,12 @@ export async function bootstrapViaBackend(
|
||||
const claimCmd = envelope.claim_command ?? "mem0 init --email <your-email>";
|
||||
console.log(` ${dim(`To claim this account later: ${claimCmd}`)}`);
|
||||
}
|
||||
|
||||
if (!agentCaller) {
|
||||
console.log(
|
||||
` ${dim("If you are an AI agent, identify yourself: `mem0 identify <your-name>` (e.g. claude-code, cursor).")}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* mem0 identify — declare which agent owns the current agent-mode key.
|
||||
*
|
||||
* Used when `mem0 init --agent` ran without --agent-caller, so the backend
|
||||
* saved agent_caller=NULL. The agent re-runs `mem0 identify <name>` to PATCH
|
||||
* its own row with its real identity. Idempotent.
|
||||
*/
|
||||
|
||||
import { printError, printSuccess } from "../branding.js";
|
||||
import { loadConfig, saveConfig } from "../config.js";
|
||||
|
||||
const SOURCE_HEADERS = {
|
||||
"X-Mem0-Source": "cli",
|
||||
"X-Mem0-Client-Language": "node",
|
||||
} as const;
|
||||
|
||||
export async function runIdentify(name: string): Promise<void> {
|
||||
const config = loadConfig();
|
||||
if (!config.platform.apiKey) {
|
||||
printError("No API key configured. Run `mem0 init --agent` first.");
|
||||
process.exit(1);
|
||||
}
|
||||
if (!config.platform.agentMode) {
|
||||
printError("This command only works on unclaimed agent-mode keys.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const clean = (name ?? "").trim();
|
||||
if (!clean) {
|
||||
printError("Agent name is required.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const baseUrl = (config.platform.baseUrl || "https://api.mem0.ai").replace(
|
||||
/\/+$/,
|
||||
"",
|
||||
);
|
||||
|
||||
let resp: Response;
|
||||
try {
|
||||
resp = await fetch(`${baseUrl}/api/v1/auth/agent_mode/caller/`, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
...SOURCE_HEADERS,
|
||||
Authorization: `Token ${config.platform.apiKey}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ agent_caller: clean }),
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
});
|
||||
} catch (err) {
|
||||
printError(
|
||||
`Network error: ${err instanceof Error ? err.message : String(err)}`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!resp.ok) {
|
||||
let detail: string = resp.statusText;
|
||||
try {
|
||||
const body = (await resp.json()) as { error?: string };
|
||||
if (body.error) detail = body.error;
|
||||
} catch {
|
||||
/* leave as statusText */
|
||||
}
|
||||
printError(`Identify failed: ${detail}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const body = (await resp.json()) as { agent_caller?: string };
|
||||
const canonical = body.agent_caller ?? clean;
|
||||
config.platform.agentCaller = canonical;
|
||||
saveConfig(config);
|
||||
printSuccess(`Identified as ${canonical}.`);
|
||||
}
|
||||
@@ -250,6 +250,18 @@ program
|
||||
});
|
||||
});
|
||||
|
||||
// ── Setup: identify (post-bootstrap agent self-tag) ──────────────────────
|
||||
|
||||
program
|
||||
.command("identify <name>")
|
||||
.description(
|
||||
"Tag your active Agent Mode key with the AI agent that's using it (e.g. claude-code, cursor).",
|
||||
)
|
||||
.action(async (name: string) => {
|
||||
const { runIdentify } = await import("./commands/identify.js");
|
||||
await runIdentify(name);
|
||||
});
|
||||
|
||||
// ── Memory: add ───────────────────────────────────────────────────────────
|
||||
|
||||
program
|
||||
|
||||
Reference in New Issue
Block a user