diff --git a/docs/gateway/cli-backends.md b/docs/gateway/cli-backends.md index fa1672082ae..d2cc0bc66e8 100644 --- a/docs/gateway/cli-backends.md +++ b/docs/gateway/cli-backends.md @@ -181,10 +181,10 @@ child process environment for the run. - `always`: always send a session id (new UUID if none stored). - `existing`: only send a session id if one was stored before. - `none`: never send a session id. -- The bundled `claude-cli` backend uses `liveSession: "claude-stdio"` so - follow-up turns reuse the live Claude process while it is active. If the - Gateway restarts or the idle process exits, OpenClaw resumes from the stored - Claude session id. +- `claude-cli` defaults to `liveSession: "claude-stdio"`, `output: "jsonl"`, + and `input: "stdin"` so follow-up turns reuse the live Claude process while + it is active. If the Gateway restarts or the idle process exits, OpenClaw + resumes from the stored Claude session id. - Stored CLI sessions are provider-owned continuity. The implicit daily session reset does not cut them; `/reset` and explicit `session.reset` policies still do. diff --git a/extensions/anthropic/cli-shared.test.ts b/extensions/anthropic/cli-shared.test.ts index 0542a810077..306315e53bb 100644 --- a/extensions/anthropic/cli-shared.test.ts +++ b/extensions/anthropic/cli-shared.test.ts @@ -107,6 +107,21 @@ describe("normalizeClaudeBackendConfig", () => { "--permission-mode", "bypassPermissions", ]); + expect(normalized.output).toBe("jsonl"); + expect(normalized.liveSession).toBe("claude-stdio"); + expect(normalized.input).toBe("stdin"); + }); + + it("does not infer live stdio when explicit transport overrides are incompatible", () => { + const normalized = normalizeClaudeBackendConfig({ + command: "claude", + output: "json", + input: "arg", + }); + + expect(normalized.output).toBe("json"); + expect(normalized.liveSession).toBeUndefined(); + expect(normalized.input).toBe("arg"); }); it("is wired through the anthropic cli backend normalize hook", () => { @@ -129,12 +144,16 @@ describe("normalizeClaudeBackendConfig", () => { expect(normalized?.resumeArgs).toContain("bypassPermissions"); expect(normalized?.resumeArgs).toContain("--setting-sources"); expect(normalized?.resumeArgs).toContain("user"); + expect(normalized?.liveSession).toBe("claude-stdio"); }); it("leaves claude cli subscription-managed, restricts setting sources, and clears inherited env overrides", () => { const backend = buildAnthropicCliBackend(); expect(backend.config.env).toBeUndefined(); + expect(backend.config.liveSession).toBe("claude-stdio"); + expect(backend.config.output).toBe("jsonl"); + expect(backend.config.input).toBe("stdin"); expect(backend.config.args).toContain("--setting-sources"); expect(backend.config.args).toContain("user"); expect(backend.config.resumeArgs).toContain("--setting-sources"); diff --git a/extensions/anthropic/cli-shared.ts b/extensions/anthropic/cli-shared.ts index 737baae346d..44cab5c54f1 100644 --- a/extensions/anthropic/cli-shared.ts +++ b/extensions/anthropic/cli-shared.ts @@ -135,9 +135,15 @@ export function normalizeClaudeSettingSourcesArgs(args?: string[]): string[] | u } export function normalizeClaudeBackendConfig(config: CliBackendConfig): CliBackendConfig { + const output = config.output ?? "jsonl"; + const input = config.input ?? "stdin"; return { ...config, args: normalizeClaudePermissionArgs(normalizeClaudeSettingSourcesArgs(config.args)), resumeArgs: normalizeClaudePermissionArgs(normalizeClaudeSettingSourcesArgs(config.resumeArgs)), + output, + liveSession: + config.liveSession ?? (output === "jsonl" && input === "stdin" ? "claude-stdio" : undefined), + input, }; }