refactor(cli): self-declared agent_caller via --agent-caller flag
Switch agent identity from env-var sniffing to explicit self-declaration
(Proof Editor-style). The agent now passes its own name when running
mem0 init --agent --agent-caller <name>.
Why: env-var detection was speculative for everything but Claude Code —
CLAUDECODE=1 is documented and verified, but CURSOR_AGENT, CODEX_CLI,
CLINE_AGENT etc. were plausible-sounding picks without upstream
confirmation. Self-declaration is honest, future-proof (no whitelist
treadmill as new agents emerge), and matches how Proof handles agent
join: explicit identity from the agent itself.
CLI changes:
- New --agent-caller <name> option on `mem0 init` (Python + Node)
- Removed detect_agent_caller() as the source for agent_caller field;
still used as a context trigger ("does this look like an agent?")
for Rule 3 auto-bootstrap and for telemetry-only event property —
identity goes to NULL unless --agent-caller is passed
- runInit / run_init accept agent_caller kwarg, forward to backend
- PostHog cli.init event uses the self-declared value (not env-sniffed)
Companion backend change (mem0ai/platform#2784) drops the whitelist
normalizer for an open sanitize so any sensible name is accepted.
This commit is contained in:
@@ -270,6 +270,7 @@ export async function runInit(
|
|||||||
force?: boolean;
|
force?: boolean;
|
||||||
agent?: boolean;
|
agent?: boolean;
|
||||||
source?: string;
|
source?: string;
|
||||||
|
agentCaller?: string;
|
||||||
} = {},
|
} = {},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { detectAgentCaller } = await import("../agent-detect.js");
|
const { detectAgentCaller } = await import("../agent-detect.js");
|
||||||
@@ -282,8 +283,8 @@ export async function runInit(
|
|||||||
claimed = false,
|
claimed = false,
|
||||||
) => {
|
) => {
|
||||||
const props: Record<string, unknown> = { command: "init", mode };
|
const props: Record<string, unknown> = { command: "init", mode };
|
||||||
const caller = detectAgentCaller();
|
// Self-declared via --agent-caller; not sniffed from env vars.
|
||||||
if (caller) props.agent_caller = caller;
|
if (opts.agentCaller) props.agent_caller = opts.agentCaller;
|
||||||
if (opts.source) props.signup_source = opts.source;
|
if (opts.source) props.signup_source = opts.source;
|
||||||
if (claimed) props.claimed_agent_mode = true;
|
if (claimed) props.claimed_agent_mode = true;
|
||||||
captureEvent("cli.init", props);
|
captureEvent("cli.init", props);
|
||||||
@@ -367,9 +368,13 @@ export async function runInit(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Rule 3: mint a fresh shadow (no valid key to reuse).
|
// Rule 3: mint a fresh shadow (no valid key to reuse).
|
||||||
|
// agent_caller is self-declared via --agent-caller (Proof Editor-style),
|
||||||
|
// not derived from env-var sniffing. detectAgentCaller() above is still
|
||||||
|
// used as a context trigger (does this look like an agent?) but never
|
||||||
|
// to fill identity.
|
||||||
await bootstrapViaBackend(config, {
|
await bootstrapViaBackend(config, {
|
||||||
source: opts.source ?? null,
|
source: opts.source ?? null,
|
||||||
agentCaller: detectAgentCaller(),
|
agentCaller: opts.agentCaller ?? null,
|
||||||
});
|
});
|
||||||
fireInit("agent");
|
fireInit("agent");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -220,6 +220,10 @@ program
|
|||||||
"--source <channel>",
|
"--source <channel>",
|
||||||
"Channel attribution for signup (e.g. github, hn, ph).",
|
"Channel attribution for signup (e.g. github, hn, ph).",
|
||||||
)
|
)
|
||||||
|
.option(
|
||||||
|
"--agent-caller <name>",
|
||||||
|
"Self-declared agent identity (e.g. claude-code, cursor). Used with --agent to attribute Agent Mode signups.",
|
||||||
|
)
|
||||||
// Accept `--json` at the init level too so the PRD-documented form
|
// Accept `--json` at the init level too so the PRD-documented form
|
||||||
// `mem0 init --agent --json` works without requiring users to move it
|
// `mem0 init --agent --json` works without requiring users to move it
|
||||||
// before the subcommand. Effect is identical to the global `--json`:
|
// before the subcommand. Effect is identical to the global `--json`:
|
||||||
@@ -242,6 +246,7 @@ program
|
|||||||
force: opts.force,
|
force: opts.force,
|
||||||
agent: opts.agent,
|
agent: opts.agent,
|
||||||
source: opts.source,
|
source: opts.source,
|
||||||
|
agentCaller: opts.agentCaller,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -867,6 +867,11 @@ def init(
|
|||||||
"--source",
|
"--source",
|
||||||
help="Channel attribution for signup (e.g. github, hn, ph).",
|
help="Channel attribution for signup (e.g. github, hn, ph).",
|
||||||
),
|
),
|
||||||
|
agent_caller: str | None = typer.Option(
|
||||||
|
None,
|
||||||
|
"--agent-caller",
|
||||||
|
help="Self-declared agent identity (e.g. claude-code, cursor). Used with --agent to attribute Agent Mode signups.",
|
||||||
|
),
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Interactive setup wizard for mem0 CLI.
|
"""Interactive setup wizard for mem0 CLI.
|
||||||
|
|
||||||
@@ -875,7 +880,7 @@ def init(
|
|||||||
mem0 init --api-key m0-xxx --user-id alice
|
mem0 init --api-key m0-xxx --user-id alice
|
||||||
mem0 init --email alice@company.com
|
mem0 init --email alice@company.com
|
||||||
mem0 init --email alice@company.com --code 482901
|
mem0 init --email alice@company.com --code 482901
|
||||||
mem0 init --agent # Bootstrap an Agent Mode account (unattended)
|
mem0 init --agent --agent-caller claude-code # AI agent self-identifies on Agent Mode bootstrap
|
||||||
mem0 init --email alice@company.com # Claims an existing Agent Mode key when one is present
|
mem0 init --email alice@company.com # Claims an existing Agent Mode key when one is present
|
||||||
"""
|
"""
|
||||||
from mem0_cli.commands.init_cmd import run_init
|
from mem0_cli.commands.init_cmd import run_init
|
||||||
@@ -888,6 +893,7 @@ def init(
|
|||||||
force=force,
|
force=force,
|
||||||
source=source,
|
source=source,
|
||||||
agent=agent_signal,
|
agent=agent_signal,
|
||||||
|
agent_caller=agent_caller,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -197,6 +197,7 @@ def run_init(
|
|||||||
force: bool = False,
|
force: bool = False,
|
||||||
source: str | None = None,
|
source: str | None = None,
|
||||||
agent: bool = False,
|
agent: bool = False,
|
||||||
|
agent_caller: str | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Interactive setup wizard for mem0 CLI.
|
"""Interactive setup wizard for mem0 CLI.
|
||||||
|
|
||||||
@@ -223,8 +224,8 @@ def run_init(
|
|||||||
def _fire_init(mode: str, *, claimed: bool = False) -> None:
|
def _fire_init(mode: str, *, claimed: bool = False) -> None:
|
||||||
"""Fire cli.init telemetry with M1-M6 properties."""
|
"""Fire cli.init telemetry with M1-M6 properties."""
|
||||||
props: dict = {"command": "init", "mode": mode}
|
props: dict = {"command": "init", "mode": mode}
|
||||||
agent_caller = detect_agent_caller()
|
|
||||||
if agent_caller:
|
if agent_caller:
|
||||||
|
# Self-declared via --agent-caller; not sniffed from env vars.
|
||||||
props["agent_caller"] = agent_caller
|
props["agent_caller"] = agent_caller
|
||||||
if source:
|
if source:
|
||||||
props["signup_source"] = source
|
props["signup_source"] = source
|
||||||
@@ -295,7 +296,10 @@ def run_init(
|
|||||||
_fire_init("existing_key")
|
_fire_init("existing_key")
|
||||||
return
|
return
|
||||||
# Rule 3: mint a fresh shadow (no valid key to reuse).
|
# Rule 3: mint a fresh shadow (no valid key to reuse).
|
||||||
bootstrap_via_backend(config, source=source, agent_caller=detect_agent_caller())
|
# agent_caller is the agent's self-declared identity from --agent-caller
|
||||||
|
# (Proof Editor-style). Env-var auto-detect is still used above to
|
||||||
|
# decide we're in an agent context, but never to fill identity.
|
||||||
|
bootstrap_via_backend(config, source=source, agent_caller=agent_caller)
|
||||||
_fire_init("agent")
|
_fire_init("agent")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user