refactor: drop legacy cli session aliases

This commit is contained in:
Peter Steinberger
2026-05-10 03:21:57 +01:00
parent 30e39ac039
commit bceeafe72a
23 changed files with 33 additions and 217 deletions

View File

@@ -218,8 +218,7 @@ type OverrideFieldClearedByDelete =
| "authProfileOverrideCompactionCount"
| "fallbackNoticeSelectedModel"
| "fallbackNoticeActiveModel"
| "fallbackNoticeReason"
| "claudeCliSessionId";
| "fallbackNoticeReason";
const OVERRIDE_FIELDS_CLEARED_BY_DELETE: OverrideFieldClearedByDelete[] = [
"providerOverride",
@@ -230,7 +229,6 @@ const OVERRIDE_FIELDS_CLEARED_BY_DELETE: OverrideFieldClearedByDelete[] = [
"fallbackNoticeSelectedModel",
"fallbackNoticeActiveModel",
"fallbackNoticeReason",
"claudeCliSessionId",
];
const OVERRIDE_VALUE_MAX_LENGTH = 256;

View File

@@ -10,7 +10,7 @@ import {
} from "./cli-session.js";
describe("cli-session helpers", () => {
it("persists binding metadata alongside legacy session ids", () => {
it("persists binding metadata in the canonical CLI session binding", () => {
const entry: SessionEntry = {
sessionId: "openclaw-session",
updatedAt: Date.now(),
@@ -27,8 +27,6 @@ describe("cli-session helpers", () => {
mcpResumeHash: "mcp-resume-hash",
});
expect(entry.cliSessionIds?.["claude-cli"]).toBe("cli-session-1");
expect(entry.claudeCliSessionId).toBe("cli-session-1");
expect(getCliSessionBinding(entry, "claude-cli")).toEqual({
sessionId: "cli-session-1",
forceReuse: true,
@@ -66,12 +64,11 @@ describe("cli-session helpers", () => {
).toEqual({ sessionId: "cli-session-1" });
});
it("keeps legacy bindings reusable until richer metadata is persisted", () => {
it("keeps bindings reusable until richer metadata is persisted", () => {
const entry: SessionEntry = {
sessionId: "openclaw-session",
updatedAt: Date.now(),
cliSessionIds: { "claude-cli": "legacy-session" },
claudeCliSessionId: "legacy-session",
cliSessionBindings: { "claude-cli": { sessionId: "cli-session" } },
};
expect(
@@ -79,15 +76,14 @@ describe("cli-session helpers", () => {
binding: getCliSessionBinding(entry, "claude-cli"),
authEpochVersion: 2,
}),
).toEqual({ sessionId: "legacy-session" });
).toEqual({ sessionId: "cli-session" });
});
it("invalidates legacy bindings when auth, prompt, or MCP state changes", () => {
it("invalidates bindings without matching metadata when auth, prompt, or MCP state changes", () => {
const entry: SessionEntry = {
sessionId: "openclaw-session",
updatedAt: Date.now(),
cliSessionIds: { "claude-cli": "legacy-session" },
claudeCliSessionId: "legacy-session",
cliSessionBindings: { "claude-cli": { sessionId: "cli-session" } },
};
const binding = getCliSessionBinding(entry, "claude-cli");
@@ -363,8 +359,6 @@ describe("cli-session helpers", () => {
clearAllCliSessions(entry);
expect(entry.cliSessionBindings).toBeUndefined();
expect(entry.cliSessionIds).toBeUndefined();
expect(entry.claudeCliSessionId).toBeUndefined();
});
it("hashes trimmed extra system prompts consistently", () => {

View File

@@ -3,8 +3,6 @@ import type { CliSessionBinding, SessionEntry } from "../config/sessions.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { normalizeProviderId } from "./model-selection.js";
const CLAUDE_CLI_BACKEND_ID = "claude-cli";
export function hashCliSessionText(value: string | undefined): string | undefined {
const trimmed = normalizeOptionalString(value);
if (!trimmed) {
@@ -35,17 +33,6 @@ export function getCliSessionBinding(
mcpResumeHash: normalizeOptionalString(fromBindings?.mcpResumeHash),
};
}
const fromMap = entry.cliSessionIds?.[normalized];
const normalizedFromMap = normalizeOptionalString(fromMap);
if (normalizedFromMap) {
return { sessionId: normalizedFromMap };
}
if (normalized === CLAUDE_CLI_BACKEND_ID) {
const legacy = normalizeOptionalString(entry.claudeCliSessionId);
if (legacy) {
return { sessionId: legacy };
}
}
return undefined;
}
@@ -95,10 +82,6 @@ export function setCliSessionBinding(
: {}),
},
};
entry.cliSessionIds = { ...entry.cliSessionIds, [normalized]: trimmed };
if (normalized === CLAUDE_CLI_BACKEND_ID) {
entry.claudeCliSessionId = trimmed;
}
}
export function clearCliSession(entry: SessionEntry, provider: string): void {
@@ -108,20 +91,10 @@ export function clearCliSession(entry: SessionEntry, provider: string): void {
delete next[normalized];
entry.cliSessionBindings = Object.keys(next).length > 0 ? next : undefined;
}
if (entry.cliSessionIds?.[normalized] !== undefined) {
const next = { ...entry.cliSessionIds };
delete next[normalized];
entry.cliSessionIds = Object.keys(next).length > 0 ? next : undefined;
}
if (normalized === CLAUDE_CLI_BACKEND_ID) {
entry.claudeCliSessionId = undefined;
}
}
export function clearAllCliSessions(entry: SessionEntry): void {
entry.cliSessionBindings = undefined;
entry.cliSessionIds = undefined;
entry.claudeCliSessionId = undefined;
}
export function resolveCliSessionReuse(params: {

View File

@@ -206,8 +206,12 @@ describe("CLI attempt execution", () => {
const sessionEntry: SessionEntry = {
sessionId: "session-cli-123",
updatedAt: Date.now(),
cliSessionIds: { "claude-cli": "stale-cli-session" },
claudeCliSessionId: "stale-legacy-session",
cliSessionBindings: {
"claude-cli": {
sessionId: "stale-cli-session",
authProfileId: "anthropic:claude-cli",
},
},
};
const sessionStore: Record<string, SessionEntry> = { [sessionKey]: sessionEntry };
await writeStore(sessionStore);
@@ -254,12 +258,10 @@ describe("CLI attempt execution", () => {
expect(runCliAgentMock).toHaveBeenCalledTimes(2);
expect(runCliAgentMock.mock.calls[0]?.[0]?.cliSessionId).toBe("stale-cli-session");
expect(runCliAgentMock.mock.calls[1]?.[0]?.cliSessionId).toBeUndefined();
expect(sessionStore[sessionKey]?.cliSessionIds?.["claude-cli"]).toBeUndefined();
expect(sessionStore[sessionKey]?.claudeCliSessionId).toBeUndefined();
expect(sessionStore[sessionKey]?.cliSessionBindings?.["claude-cli"]).toBeUndefined();
const persisted = readStore();
expect(persisted[sessionKey]?.cliSessionIds?.["claude-cli"]).toBeUndefined();
expect(persisted[sessionKey]?.claudeCliSessionId).toBeUndefined();
expect(persisted[sessionKey]?.cliSessionBindings?.["claude-cli"]).toBeUndefined();
});
it("does not pass --resume when the stored Claude CLI transcript is missing", async () => {
@@ -275,8 +277,6 @@ describe("CLI attempt execution", () => {
authProfileId: "anthropic:claude-cli",
},
},
cliSessionIds: { "claude-cli": "phantom-claude-session" },
claudeCliSessionId: "phantom-claude-session",
};
const sessionStore: Record<string, SessionEntry> = { [sessionKey]: sessionEntry };
await writeStore(sessionStore);
@@ -294,13 +294,9 @@ describe("CLI attempt execution", () => {
expect(runCliAgentMock.mock.calls[0]?.[0]?.cliSessionId).toBeUndefined();
expect(runCliAgentMock.mock.calls[0]?.[0]?.cliSessionBinding).toBeUndefined();
expect(sessionStore[sessionKey]?.cliSessionBindings?.["claude-cli"]).toBeUndefined();
expect(sessionStore[sessionKey]?.cliSessionIds?.["claude-cli"]).toBeUndefined();
expect(sessionStore[sessionKey]?.claudeCliSessionId).toBeUndefined();
const persisted = readStore();
expect(persisted[sessionKey]?.cliSessionBindings?.["claude-cli"]).toBeUndefined();
expect(persisted[sessionKey]?.cliSessionIds?.["claude-cli"]).toBeUndefined();
expect(persisted[sessionKey]?.claudeCliSessionId).toBeUndefined();
});
it("keeps Claude CLI resume when the stored transcript has assistant content", async () => {
@@ -330,8 +326,6 @@ describe("CLI attempt execution", () => {
authProfileId: "anthropic:claude-cli",
},
},
cliSessionIds: { "claude-cli": cliSessionId },
claudeCliSessionId: cliSessionId,
};
const sessionStore: Record<string, SessionEntry> = { [sessionKey]: sessionEntry };
await writeStore(sessionStore);
@@ -351,8 +345,9 @@ describe("CLI attempt execution", () => {
sessionId: cliSessionId,
authProfileId: "anthropic:claude-cli",
});
expect(sessionStore[sessionKey]?.cliSessionIds?.["claude-cli"]).toBe(cliSessionId);
expect(sessionStore[sessionKey]?.claudeCliSessionId).toBe(cliSessionId);
expect(sessionStore[sessionKey]?.cliSessionBindings?.["claude-cli"]?.sessionId).toBe(
cliSessionId,
);
});
it("passes session-bound OpenAI Codex auth profile to codex-cli aliases", async () => {

View File

@@ -107,10 +107,6 @@ describe("runCliTurnCompactionLifecycle", () => {
cliSessionBindings: {
"claude-cli": { sessionId: "claude-session" },
},
cliSessionIds: {
"claude-cli": "claude-session",
},
claudeCliSessionId: "claude-session",
};
const sessionStore: Record<string, SessionEntry> = { [sessionKey]: sessionEntry };
upsertSessionEntry({ agentId: "main", sessionKey, entry: sessionEntry });
@@ -170,8 +166,6 @@ describe("runCliTurnCompactionLifecycle", () => {
);
expect(updatedEntry?.compactionCount).toBe(1);
expect(updatedEntry?.cliSessionBindings?.["claude-cli"]).toBeUndefined();
expect(updatedEntry?.cliSessionIds?.["claude-cli"]).toBeUndefined();
expect(updatedEntry?.claudeCliSessionId).toBeUndefined();
});
it("initializes built-in context engines before resolving CLI compaction engine", async () => {

View File

@@ -317,15 +317,11 @@ describe("updateSessionEntryAfterAgentRun", () => {
expect(sessionStore[sessionKey]?.cliSessionBindings?.["claude-cli"]).toEqual({
sessionId: "cli-session-123",
});
expect(sessionStore[sessionKey]?.cliSessionIds?.["claude-cli"]).toBe("cli-session-123");
expect(sessionStore[sessionKey]?.claudeCliSessionId).toBe("cli-session-123");
const persisted = readMockSessionEntries(agentId);
expect(persisted[sessionKey]?.cliSessionBindings?.["claude-cli"]).toEqual({
sessionId: "cli-session-123",
});
expect(persisted[sessionKey]?.cliSessionIds?.["claude-cli"]).toBe("cli-session-123");
expect(persisted[sessionKey]?.claudeCliSessionId).toBe("cli-session-123");
});
});
@@ -1163,11 +1159,6 @@ describe("clearCliSessionEntry", () => {
sessionId: "codex-session-1",
},
},
cliSessionIds: {
"claude-cli": "claude-session-1",
"codex-cli": "codex-session-1",
},
claudeCliSessionId: "claude-session-1",
};
const sessionStore: Record<string, SessionEntry> = { [sessionKey]: entry };
await replaceMockSessionEntries(agentId, sessionStore);
@@ -1182,9 +1173,6 @@ describe("clearCliSessionEntry", () => {
expect(cleared?.cliSessionBindings?.["codex-cli"]).toEqual({
sessionId: "codex-session-1",
});
expect(cleared?.cliSessionIds?.["claude-cli"]).toBeUndefined();
expect(cleared?.cliSessionIds?.["codex-cli"]).toBe("codex-session-1");
expect(cleared?.claudeCliSessionId).toBeUndefined();
expect(sessionStore[sessionKey]).toEqual(cleared);
const persisted = readMockSessionEntries(agentId)[sessionKey];
@@ -1192,9 +1180,6 @@ describe("clearCliSessionEntry", () => {
expect(persisted?.cliSessionBindings?.["codex-cli"]).toEqual({
sessionId: "codex-session-1",
});
expect(persisted?.cliSessionIds?.["claude-cli"]).toBeUndefined();
expect(persisted?.cliSessionIds?.["codex-cli"]).toBe("codex-session-1");
expect(persisted?.claudeCliSessionId).toBeUndefined();
});
});
@@ -1205,7 +1190,7 @@ describe("clearCliSessionEntry", () => {
[existingKey]: {
sessionId: "openclaw-session-1",
updatedAt: 1,
claudeCliSessionId: "claude-session-1",
cliSessionBindings: { "claude-cli": { sessionId: "claude-session-1" } },
},
};
await replaceMockSessionEntries(agentId, sessionStore);
@@ -1217,10 +1202,12 @@ describe("clearCliSessionEntry", () => {
});
expect(cleared).toBeUndefined();
expect(sessionStore[existingKey]?.claudeCliSessionId).toBe("claude-session-1");
expect(readMockSessionEntries(agentId)[existingKey]?.claudeCliSessionId).toBe(
expect(sessionStore[existingKey]?.cliSessionBindings?.["claude-cli"]?.sessionId).toBe(
"claude-session-1",
);
expect(
readMockSessionEntries(agentId)[existingKey]?.cliSessionBindings?.["claude-cli"]?.sessionId,
).toBe("claude-session-1");
});
});
});

View File

@@ -331,14 +331,12 @@ describe("handleCommands reset hooks", () => {
params.sessionEntry = {
sessionId: "session-1",
updatedAt: Date.now(),
cliSessionIds: { "claude-cli": "cli-session-1" },
cliSessionBindings: {
"claude-cli": {
sessionId: "cli-session-1",
extraSystemPromptHash: "prompt-hash",
},
},
claudeCliSessionId: "cli-session-1",
} as HandleCommandsParams["sessionEntry"];
const result = await maybeHandleResetCommand(params);
@@ -351,9 +349,7 @@ describe("handleCommands reset hooks", () => {
expect(params.command.resetHookTriggered).toBe(true);
expect(params.command.softResetTriggered).toBe(true);
expect(params.command.softResetTail).toBe("");
expect(params.sessionEntry?.cliSessionIds).toBeUndefined();
expect(params.sessionEntry?.cliSessionBindings).toBeUndefined();
expect(params.sessionEntry?.claudeCliSessionId).toBeUndefined();
expect(clearBootstrapSnapshotSpy).toHaveBeenCalledWith("agent:main:main");
});
@@ -392,39 +388,31 @@ describe("handleCommands reset hooks", () => {
params.sessionEntry = {
sessionId: "session-direct",
updatedAt: 1,
cliSessionIds: { "claude-cli": "cli-session-direct" },
cliSessionBindings: {
"claude-cli": {
sessionId: "cli-session-direct",
extraSystemPromptHash: "prompt-hash-direct",
},
},
claudeCliSessionId: "cli-session-direct",
} as HandleCommandsParams["sessionEntry"];
params.sessionStore = {
[params.sessionKey]: {
sessionId: "session-store",
updatedAt: 2,
cliSessionIds: { "claude-cli": "cli-session-store" },
cliSessionBindings: {
"claude-cli": {
sessionId: "cli-session-store",
extraSystemPromptHash: "prompt-hash-store",
},
},
claudeCliSessionId: "cli-session-store",
},
} as Record<string, NonNullable<HandleCommandsParams["sessionEntry"]>>;
const result = await maybeHandleResetCommand(params);
expect(result).toBeNull();
expect(params.sessionEntry?.cliSessionIds).toBeUndefined();
expect(params.sessionEntry?.cliSessionBindings).toBeUndefined();
expect(params.sessionEntry?.claudeCliSessionId).toBeUndefined();
expect(params.sessionStore?.[params.sessionKey]?.cliSessionIds).toBeUndefined();
expect(params.sessionStore?.[params.sessionKey]?.cliSessionBindings).toBeUndefined();
expect(params.sessionStore?.[params.sessionKey]?.claudeCliSessionId).toBeUndefined();
});
it("rejects soft reset for bound ACP sessions", async () => {

View File

@@ -82,8 +82,6 @@ export async function maybeHandleResetCommand(
clearAllCliSessions(next);
return {
cliSessionBindings: next.cliSessionBindings,
cliSessionIds: next.cliSessionIds,
claudeCliSessionId: next.claudeCliSessionId,
updatedAt: now,
lastInteractionAt: now,
};

View File

@@ -26,9 +26,7 @@ function applyCliSessionIdToSessionPatch(
setCliSessionBinding(nextEntry, cliProvider, params.cliSessionBinding);
return {
...patch,
cliSessionIds: nextEntry.cliSessionIds,
cliSessionBindings: nextEntry.cliSessionBindings,
claudeCliSessionId: nextEntry.claudeCliSessionId,
};
}
if (params.cliSessionId && cliProvider) {
@@ -36,9 +34,7 @@ function applyCliSessionIdToSessionPatch(
setCliSessionId(nextEntry, cliProvider, params.cliSessionId);
return {
...patch,
cliSessionIds: nextEntry.cliSessionIds,
cliSessionBindings: nextEntry.cliSessionBindings,
claudeCliSessionId: nextEntry.claudeCliSessionId,
};
}
return patch;

View File

@@ -2217,14 +2217,12 @@ describe("initSessionState preserves behavior overrides across /new and /reset",
authProfileOverride: "20251001",
authProfileOverrideSource: "user",
authProfileOverrideCompactionCount: 2,
cliSessionIds: { "claude-cli": "cli-session-123" },
cliSessionBindings: {
"claude-cli": {
sessionId: "cli-session-123",
authProfileId: "anthropic:default",
},
},
claudeCliSessionId: "cli-session-123",
} as const;
const cases = [
{
@@ -2274,14 +2272,10 @@ describe("initSessionState preserves behavior overrides across /new and /reset",
authProfileOverrideSource: overrides.authProfileOverrideSource,
authProfileOverrideCompactionCount: overrides.authProfileOverrideCompactionCount,
});
expect(result.sessionEntry.cliSessionIds).toBeUndefined();
expect(result.sessionEntry.cliSessionBindings).toBeUndefined();
expect(result.sessionEntry.claudeCliSessionId).toBeUndefined();
const stored = readSessionRowsForFixtureTarget(sessionRowsTarget);
expect(stored[sessionKey].cliSessionIds).toBeUndefined();
expect(stored[sessionKey].cliSessionBindings).toBeUndefined();
expect(stored[sessionKey].claudeCliSessionId).toBeUndefined();
}
});
@@ -2442,7 +2436,6 @@ describe("initSessionState preserves behavior overrides across /new and /reset",
sessionKey,
sessionId: existingSessionId,
overrides: {
cliSessionIds: { "claude-cli": "cli-session-1" },
cliSessionBindings: {
"claude-cli": {
sessionId: "cli-session-1",
@@ -2625,10 +2618,6 @@ describe("initSessionState preserves behavior overrides across /new and /reset",
cliSessionBindings: {
"claude-cli": cliBinding,
},
cliSessionIds: {
"claude-cli": cliBinding.sessionId,
},
claudeCliSessionId: cliBinding.sessionId,
},
});
replaceSqliteSessionTranscriptEvents({
@@ -2961,7 +2950,6 @@ describe("persistSessionUsageUpdate", () => {
const stored = readSessionRowsForFixtureTarget(sessionRowsTarget);
expect(stored[sessionKey].totalTokens).toBe(32_000);
expect(stored[sessionKey].totalTokensFresh).toBe(true);
expect(stored[sessionKey].cliSessionIds?.["claude-cli"]).toBe("cli-session-1");
expect(stored[sessionKey].cliSessionBindings?.["claude-cli"]).toEqual({
sessionId: "cli-session-1",
authProfileId: "anthropic:default",

View File

@@ -615,9 +615,7 @@ export async function initSessionState(params: {
persistedAuthProfileOverrideSource ?? baseEntry?.authProfileOverrideSource,
authProfileOverrideCompactionCount:
persistedAuthProfileOverrideCompactionCount ?? baseEntry?.authProfileOverrideCompactionCount,
cliSessionIds: baseEntry?.cliSessionIds,
cliSessionBindings: baseEntry?.cliSessionBindings,
claudeCliSessionId: baseEntry?.claudeCliSessionId,
label: persistedLabel ?? baseEntry?.label,
spawnedBy: persistedSpawnedBy ?? baseEntry?.spawnedBy,
spawnedWorkspaceDir: persistedSpawnedWorkspaceDir ?? baseEntry?.spawnedWorkspaceDir,

View File

@@ -342,9 +342,7 @@ export type SessionEntry = {
memoryFlushAt?: number;
memoryFlushCompactionCount?: number;
memoryFlushContextHash?: string;
cliSessionIds?: Record<string, string>;
cliSessionBindings?: Record<string, CliSessionBinding>;
claudeCliSessionId?: string;
label?: string;
displayName?: string;
channel?: string;

View File

@@ -35,9 +35,7 @@ function toNonResumableCronSessionEntry(entry: SessionEntry): SessionEntry {
delete next.sessionId;
delete next.sessionStartedAt;
delete next.lastInteractionAt;
delete next.cliSessionIds;
delete next.cliSessionBindings;
delete next.claudeCliSessionId;
return next as SessionEntry;
}

View File

@@ -318,7 +318,7 @@ describe("runCronIsolatedAgentTurn — skill filter", () => {
systemSent: false,
skillsSnapshot: undefined,
// A stored CLI session ID that should NOT be reused on fresh runs.
cliSessionIds: { "claude-cli": "prev-cli-session-abc" },
cliSessionBindings: { "claude-cli": { sessionId: "prev-cli-session-abc" } },
},
systemSent: false,
isNewSession: true,
@@ -348,7 +348,7 @@ describe("runCronIsolatedAgentTurn — skill filter", () => {
updatedAt: 0,
systemSent: false,
skillsSnapshot: undefined,
cliSessionIds: { "claude-cli": "existing-cli-session-def" },
cliSessionBindings: { "claude-cli": { sessionId: "existing-cli-session-def" } },
},
systemSent: false,
isNewSession: false,

View File

@@ -223,9 +223,7 @@ describe("resolveCronSession", () => {
modelProvider: "anthropic",
agentHarnessId: "claude-cli",
agentRuntimeOverride: "claude-cli",
cliSessionIds: { anthropic: "old-cli-session" },
cliSessionBindings: {},
claudeCliSessionId: "old-claude-session",
cliSessionBindings: { anthropic: { sessionId: "old-cli-session" } },
liveModelSwitchPending: true,
fallbackNoticeSelectedModel: "anthropic/claude-opus-4-6",
fallbackNoticeActiveModel: "anthropic/claude-sonnet-4-6",
@@ -311,9 +309,7 @@ describe("resolveCronSession", () => {
expect(result.sessionEntry.modelProvider).toBeUndefined();
expect(result.sessionEntry.agentHarnessId).toBeUndefined();
expect(result.sessionEntry.agentRuntimeOverride).toBeUndefined();
expect(result.sessionEntry.cliSessionIds).toBeUndefined();
expect(result.sessionEntry.cliSessionBindings).toBeUndefined();
expect(result.sessionEntry.claudeCliSessionId).toBeUndefined();
expect(result.sessionEntry.liveModelSwitchPending).toBeUndefined();
expect(result.sessionEntry.fallbackNoticeSelectedModel).toBeUndefined();
expect(result.sessionEntry.fallbackNoticeActiveModel).toBeUndefined();

View File

@@ -49,18 +49,7 @@ function resolveClaudeProjectsDir(homeDir?: string): string {
export function resolveClaudeCliBindingSessionId(
entry: SessionEntry | undefined,
): string | undefined {
const bindingSessionId = normalizeOptionalString(
entry?.cliSessionBindings?.[CLAUDE_CLI_PROVIDER]?.sessionId,
);
if (bindingSessionId) {
return bindingSessionId;
}
const legacyMapSessionId = normalizeOptionalString(entry?.cliSessionIds?.[CLAUDE_CLI_PROVIDER]);
if (legacyMapSessionId) {
return legacyMapSessionId;
}
const legacyClaudeSessionId = normalizeOptionalString(entry?.claudeCliSessionId);
return legacyClaudeSessionId || undefined;
return normalizeOptionalString(entry?.cliSessionBindings?.[CLAUDE_CLI_PROVIDER]?.sessionId);
}
function resolveFiniteNumber(value: unknown): number | undefined {

View File

@@ -351,48 +351,6 @@ describe("cli session history", () => {
expect(messages).toBe(localMessages);
});
});
it("falls back to legacy cliSessionIds when bindings are absent", async () => {
await withClaudeProjectsDir(async ({ homeDir, sessionId }) => {
const messages = augmentChatHistoryWithCliSessionImports({
entry: {
sessionId: "openclaw-session",
updatedAt: Date.now(),
cliSessionIds: {
"claude-cli": sessionId,
},
},
provider: "claude-cli",
localMessages: [],
homeDir,
});
expect(messages).toHaveLength(3);
expectFields(messages[1], {
role: "assistant",
});
expectFields(readRecord(messages[1])["__openclaw"], { cliSessionId: sessionId });
});
});
it("falls back to legacy claudeCliSessionId when newer fields are absent", async () => {
await withClaudeProjectsDir(async ({ homeDir, sessionId }) => {
const messages = augmentChatHistoryWithCliSessionImports({
entry: {
sessionId: "openclaw-session",
updatedAt: Date.now(),
claudeCliSessionId: sessionId,
},
provider: "claude-cli",
localMessages: [],
homeDir,
});
expect(messages).toHaveLength(3);
expectFields(messages[0], {
role: "user",
});
expectFields(readRecord(messages[0])["__openclaw"], { cliSessionId: sessionId });
});
});
});
describe("readClaudeCliFallbackSeed", () => {

View File

@@ -868,18 +868,15 @@ describe("gateway agent handler", () => {
});
});
it("preserves cliSessionIds from existing session entry", async () => {
const existingCliSessionIds = { "claude-cli": "abc-123-def" };
const existingClaudeCliSessionId = "abc-123-def";
it("preserves CLI session bindings from existing session entry", async () => {
const existingCliSessionBindings = { "claude-cli": { sessionId: "abc-123-def" } };
mockMainSessionEntry({
cliSessionIds: existingCliSessionIds,
claudeCliSessionId: existingClaudeCliSessionId,
cliSessionBindings: existingCliSessionBindings,
});
const capturedEntry = await runMainAgentAndCaptureEntry("test-idem");
expect(capturedEntry.cliSessionIds).toEqual(existingCliSessionIds);
expect(capturedEntry.claudeCliSessionId).toBe(existingClaudeCliSessionId);
expect(capturedEntry.cliSessionBindings).toEqual(existingCliSessionBindings);
});
it("reactivates completed subagent sessions and broadcasts send updates", async () => {
const childSessionKey = "agent:main:subagent:followup";
@@ -2544,13 +2541,12 @@ describe("gateway agent handler", () => {
expect(mocks.resolveVoiceWakeRouteByTrigger).not.toHaveBeenCalled();
});
it("handles missing cliSessionIds gracefully", async () => {
it("handles missing CLI session bindings gracefully", async () => {
mockMainSessionEntry({});
const capturedEntry = await runMainAgentAndCaptureEntry("test-idem-2");
// Should be undefined, not cause an error
expect(capturedEntry.cliSessionIds).toBeUndefined();
expect(capturedEntry.claudeCliSessionId).toBeUndefined();
expect(capturedEntry.cliSessionBindings).toBeUndefined();
});
it("leaves noncanonical main row cleanup to doctor when writing a canonical session entry", async () => {
mocks.loadSessionEntry.mockReturnValue({

View File

@@ -1103,9 +1103,7 @@ export const agentHandlers: GatewayRequestHandlers = {
groupChannel: resolvedGroupChannel,
space: resolvedGroupSpace,
...(pluginOwnerId ? { pluginOwnerId } : {}),
cliSessionIds: entry?.cliSessionIds,
cliSessionBindings: entry?.cliSessionBindings,
claudeCliSessionId: entry?.claudeCliSessionId,
};
sessionEntry = mergeSessionEntry(entry, nextEntryPatch);
if (request.deliver === true) {

View File

@@ -234,9 +234,6 @@ describe("gateway server agent", () => {
updatedAt: Date.now(),
modelProvider: "claude-cli",
model: "claude-opus-4-6",
cliSessionIds: {
"claude-cli": "cli-session-123",
},
cliSessionBindings: {
"claude-cli": {
sessionId: "cli-session-123",
@@ -245,7 +242,6 @@ describe("gateway server agent", () => {
mcpResumeHash: "mcp-resume-hash",
},
},
claudeCliSessionId: "cli-session-123",
},
},
});
@@ -267,10 +263,6 @@ describe("gateway server agent", () => {
mcpResumeHash: "mcp-resume-hash",
},
});
expect(stored?.cliSessionIds).toEqual({
"claude-cli": "cli-session-123",
});
expect(stored?.claudeCliSessionId).toBe("cli-session-123");
});
test("agent accepts built-in channel alias (imsg)", async () => {

View File

@@ -266,9 +266,6 @@ test("sessions.reset preserves spawned session ownership metadata", async () =>
execAsk: "on-miss",
execNode: "mac-mini",
displayName: "Ops Child",
cliSessionIds: {
"claude-cli": "cli-session-123",
},
cliSessionBindings: {
"claude-cli": {
sessionId: "cli-session-123",
@@ -276,7 +273,6 @@ test("sessions.reset preserves spawned session ownership metadata", async () =>
extraSystemPromptHash: "prompt-hash",
},
},
claudeCliSessionId: "cli-session-123",
deliveryContext: {
channel: "discord",
to: "discord:child",
@@ -334,8 +330,6 @@ test("sessions.reset preserves spawned session ownership metadata", async () =>
mcpConfigHash?: string;
}
>;
cliSessionIds?: Record<string, string>;
claudeCliSessionId?: string;
deliveryContext?: {
channel?: string;
to?: string;
@@ -388,10 +382,6 @@ test("sessions.reset preserves spawned session ownership metadata", async () =>
extraSystemPromptHash: "prompt-hash",
},
});
expect(reset.payload?.entry.cliSessionIds).toEqual({
"claude-cli": "cli-session-123",
});
expect(reset.payload?.entry.claudeCliSessionId).toBe("cli-session-123");
expect(reset.payload?.entry.deliveryContext).toEqual({
channel: "discord",
to: "discord:child",
@@ -440,10 +430,6 @@ test("sessions.reset preserves spawned session ownership metadata", async () =>
extraSystemPromptHash: "prompt-hash",
},
});
expect(stored?.cliSessionIds).toEqual({
"claude-cli": "cli-session-123",
});
expect(stored?.claudeCliSessionId).toBe("cli-session-123");
expect(stored?.deliveryContext).toEqual({
channel: "discord",
to: "discord:child",

View File

@@ -592,8 +592,6 @@ export async function performGatewaySessionReset(params: {
origin: snapshotSessionOrigin(currentEntry),
deliveryContext: currentEntry?.deliveryContext,
cliSessionBindings: currentEntry?.cliSessionBindings,
cliSessionIds: currentEntry?.cliSessionIds,
claudeCliSessionId: currentEntry?.claudeCliSessionId,
lastChannel: currentEntry?.lastChannel,
lastTo: currentEntry?.lastTo,
lastAccountId: currentEntry?.lastAccountId,

View File

@@ -93,9 +93,7 @@ const SESSION_ENTRY_RESERVED_SLOT_KEY_LIST = [
"memoryFlushAt",
"memoryFlushCompactionCount",
"memoryFlushContextHash",
"cliSessionIds",
"cliSessionBindings",
"claudeCliSessionId",
"label",
"displayName",
"channel",