diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e8e521f63f..4abe1a295a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Gateway/chat history: merge Claude CLI transcript imports for Anthropic-routed sessions that still have a Claude CLI binding, so local chat history does not hide CLI JSONL turns. Fixes #75850. Thanks @alfredjbclaw. - Cron: make scheduler reload schedule comparison tolerate malformed persisted jobs, so one bad cron entry no longer aborts the whole tick. Fixes #75886. Thanks @samfox-ai. - Doctor/channels: warn after migrations when default Telegram or Discord accounts have no configured token and their env fallback (`TELEGRAM_BOT_TOKEN` or `DISCORD_BOT_TOKEN`) is unavailable, with secret-safe migration docs for checking state-dir `.env`. Fixes #74298. Thanks @lolaopenclaw. - Control UI/chat: keep live replies visible when a raw session alias such as `main` sends the chat turn but Gateway emits events under the canonical session key for the same run. Fixes #73716. Thanks @teebes. diff --git a/src/gateway/cli-session-history.test.ts b/src/gateway/cli-session-history.test.ts index 9530e06bd15..d6e88cbb44c 100644 --- a/src/gateway/cli-session-history.test.ts +++ b/src/gateway/cli-session-history.test.ts @@ -256,6 +256,73 @@ describe("cli session history", () => { }); }); + it("augments anthropic-routed chat history when a Claude CLI binding has local messages", async () => { + await withClaudeProjectsDir(async ({ homeDir, sessionId }) => { + const messages = augmentChatHistoryWithCliSessionImports({ + entry: { + sessionId: "openclaw-session", + updatedAt: Date.now(), + cliSessionBindings: { + "claude-cli": { + sessionId, + }, + }, + }, + provider: "anthropic", + localMessages: [ + { + role: "assistant", + content: "local assistant turn", + timestamp: Date.parse("2026-03-26T16:29:57.000Z"), + }, + ], + homeDir, + }); + + expect(messages).toHaveLength(4); + expect(messages).toContainEqual( + expect.objectContaining({ + role: "assistant", + content: "local assistant turn", + }), + ); + expect(messages).toContainEqual( + expect.objectContaining({ + role: "user", + __openclaw: expect.objectContaining({ cliSessionId: sessionId }), + }), + ); + }); + }); + + it("does not import stale Claude CLI history for unrelated providers with local messages", async () => { + await withClaudeProjectsDir(async ({ homeDir, sessionId }) => { + const localMessages = [ + { + role: "assistant", + content: "local OpenAI turn", + timestamp: Date.parse("2026-03-26T16:29:57.000Z"), + }, + ]; + const messages = augmentChatHistoryWithCliSessionImports({ + entry: { + sessionId: "openclaw-session", + updatedAt: Date.now(), + cliSessionBindings: { + "claude-cli": { + sessionId, + }, + }, + }, + provider: "openai", + localMessages, + homeDir, + }); + + expect(messages).toBe(localMessages); + }); + }); + it("falls back to legacy cliSessionIds when bindings are absent", async () => { await withClaudeProjectsDir(async ({ homeDir, sessionId }) => { const messages = augmentChatHistoryWithCliSessionImports({ diff --git a/src/gateway/cli-session-history.ts b/src/gateway/cli-session-history.ts index 74835cf73c1..cec3cb64fa1 100644 --- a/src/gateway/cli-session-history.ts +++ b/src/gateway/cli-session-history.ts @@ -10,6 +10,8 @@ import { } from "./cli-session-history.claude.js"; import { mergeImportedChatHistoryMessages } from "./cli-session-history.merge.js"; +const ANTHROPIC_PROVIDER = "anthropic"; + export { mergeImportedChatHistoryMessages, readClaudeCliFallbackSeed, @@ -34,6 +36,7 @@ export function augmentChatHistoryWithCliSessionImports(params: { if ( normalizedProvider && normalizedProvider !== CLAUDE_CLI_PROVIDER && + normalizedProvider !== ANTHROPIC_PROVIDER && params.localMessages.length > 0 ) { return params.localMessages;