Files
openclaw/src/agents/cli-session.ts
2026-04-07 08:40:34 +01:00

154 lines
5.4 KiB
TypeScript

import crypto from "node:crypto";
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) {
return undefined;
}
return crypto.createHash("sha256").update(trimmed).digest("hex");
}
export function getCliSessionBinding(
entry: SessionEntry | undefined,
provider: string,
): CliSessionBinding | undefined {
if (!entry) {
return undefined;
}
const normalized = normalizeProviderId(provider);
const fromBindings = entry.cliSessionBindings?.[normalized];
const bindingSessionId = normalizeOptionalString(fromBindings?.sessionId);
if (bindingSessionId) {
return {
sessionId: bindingSessionId,
authProfileId: normalizeOptionalString(fromBindings?.authProfileId),
authEpoch: normalizeOptionalString(fromBindings?.authEpoch),
extraSystemPromptHash: normalizeOptionalString(fromBindings?.extraSystemPromptHash),
mcpConfigHash: normalizeOptionalString(fromBindings?.mcpConfigHash),
};
}
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;
}
export function getCliSessionId(
entry: SessionEntry | undefined,
provider: string,
): string | undefined {
return getCliSessionBinding(entry, provider)?.sessionId;
}
export function setCliSessionId(entry: SessionEntry, provider: string, sessionId: string): void {
setCliSessionBinding(entry, provider, { sessionId });
}
export function setCliSessionBinding(
entry: SessionEntry,
provider: string,
binding: CliSessionBinding,
): void {
const normalized = normalizeProviderId(provider);
const trimmed = binding.sessionId.trim();
if (!trimmed) {
return;
}
entry.cliSessionBindings = {
...entry.cliSessionBindings,
[normalized]: {
sessionId: trimmed,
...(normalizeOptionalString(binding.authProfileId)
? { authProfileId: normalizeOptionalString(binding.authProfileId) }
: {}),
...(normalizeOptionalString(binding.authEpoch)
? { authEpoch: normalizeOptionalString(binding.authEpoch) }
: {}),
...(normalizeOptionalString(binding.extraSystemPromptHash)
? { extraSystemPromptHash: normalizeOptionalString(binding.extraSystemPromptHash) }
: {}),
...(normalizeOptionalString(binding.mcpConfigHash)
? { mcpConfigHash: normalizeOptionalString(binding.mcpConfigHash) }
: {}),
},
};
entry.cliSessionIds = { ...entry.cliSessionIds, [normalized]: trimmed };
if (normalized === CLAUDE_CLI_BACKEND_ID) {
entry.claudeCliSessionId = trimmed;
}
}
export function clearCliSession(entry: SessionEntry, provider: string): void {
const normalized = normalizeProviderId(provider);
if (entry.cliSessionBindings?.[normalized] !== undefined) {
const next = { ...entry.cliSessionBindings };
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) {
delete entry.claudeCliSessionId;
}
}
export function clearAllCliSessions(entry: SessionEntry): void {
delete entry.cliSessionBindings;
delete entry.cliSessionIds;
delete entry.claudeCliSessionId;
}
export function resolveCliSessionReuse(params: {
binding?: CliSessionBinding;
authProfileId?: string;
authEpoch?: string;
extraSystemPromptHash?: string;
mcpConfigHash?: string;
}): {
sessionId?: string;
invalidatedReason?: "auth-profile" | "auth-epoch" | "system-prompt" | "mcp";
} {
const binding = params.binding;
const sessionId = normalizeOptionalString(binding?.sessionId);
if (!sessionId) {
return {};
}
const currentAuthProfileId = normalizeOptionalString(params.authProfileId);
const currentAuthEpoch = normalizeOptionalString(params.authEpoch);
const currentExtraSystemPromptHash = normalizeOptionalString(params.extraSystemPromptHash);
const currentMcpConfigHash = normalizeOptionalString(params.mcpConfigHash);
const storedAuthProfileId = normalizeOptionalString(binding?.authProfileId);
if (storedAuthProfileId !== currentAuthProfileId) {
return { invalidatedReason: "auth-profile" };
}
const storedAuthEpoch = normalizeOptionalString(binding?.authEpoch);
if (storedAuthEpoch !== currentAuthEpoch) {
return { invalidatedReason: "auth-epoch" };
}
const storedExtraSystemPromptHash = normalizeOptionalString(binding?.extraSystemPromptHash);
if (storedExtraSystemPromptHash !== currentExtraSystemPromptHash) {
return { invalidatedReason: "system-prompt" };
}
const storedMcpConfigHash = normalizeOptionalString(binding?.mcpConfigHash);
if (storedMcpConfigHash !== currentMcpConfigHash) {
return { invalidatedReason: "mcp" };
}
return { sessionId };
}