| |
| |
| |
| import crypto from "node:crypto"; |
| import path from "node:path"; |
| import type { MsgContext } from "../../auto-reply/templating.js"; |
| import { |
| normalizeThinkLevel, |
| normalizeVerboseLevel, |
| type ThinkLevel, |
| type VerboseLevel, |
| } from "../../auto-reply/thinking.js"; |
| import { tryResolveLegacyCompatibilityAgentId } from "../../config/legacy.default-agent-owner.js"; |
| import { hasProviderOwnedSession } from "../../config/sessions/entry-freshness.js"; |
| import { isInternalSessionEffectsKey } from "../../config/sessions/internal-session-key.js"; |
| import { |
| hasTerminalMainSessionTranscriptNewerThanRegistrySync, |
| resolveSessionLifecycleTimestamps, |
| } from "../../config/sessions/lifecycle.js"; |
| import { |
| canonicalizeMainSessionAlias, |
| resolveAgentIdFromSessionKey, |
| resolveExplicitAgentSessionKey, |
| } from "../../config/sessions/main-session.js"; |
| import { resolveSessionStorePathCore } from "../../config/sessions/paths.js"; |
| import { |
| evaluateSessionFreshness, |
| resolveSessionResetPolicy, |
| } from "../../config/sessions/reset-policy.js"; |
| import { resolveChannelResetConfig, resolveSessionResetType } from "../../config/sessions/reset.js"; |
| import { |
| listSessionEntriesReadOnly, |
| loadExactSessionEntryReadOnly, |
| type SessionEntrySummary, |
| } from "../../config/sessions/session-accessor.js"; |
| import { resolveSessionKey } from "../../config/sessions/session-key.js"; |
| import { |
| resolvePersistedSessionStoreOwner, |
| resolvePersistedSessionStoreOwnerForKey, |
| } from "../../config/sessions/session-store-owner.js"; |
| import { normalizeStoreSessionKey } from "../../config/sessions/store-entry.js"; |
| import type { InternalSessionEntry } from "../../config/sessions/types.js"; |
| import type { OpenClawConfig } from "../../config/types.openclaw.js"; |
| import { |
| classifySessionKeyShape, |
| isUnscopedSessionKeySentinel, |
| normalizeAgentId, |
| normalizeMainKey, |
| parseAgentSessionKey, |
| } from "../../routing/session-key.js"; |
| import { isModelSelectionLocked } from "../../sessions/model-overrides.js"; |
| import { resolveSessionIdMatchSelection } from "../../sessions/session-id-resolution.js"; |
| import { sessionDeliveryChannel } from "../../utils/delivery-context.shared.js"; |
| import { |
| AgentSelectionRequiredError, |
| listAgentIds, |
| resolveDefaultAgentId, |
| } from "../agent-scope.js"; |
| import { clearBootstrapSnapshotOnSessionRollover } from "../bootstrap-cache.js"; |
| import { clearAllCliSessions } from "../cli-session.js"; |
| import { transitionMainSessionRecovery } from "../main-session-recovery/main-session-recovery-state.js"; |
|
|
| |
| type SessionResolution = { |
| sessionId: string; |
| sessionKey?: string; |
| sessionEntry?: InternalSessionEntry; |
| storePath: string; |
| isNewSession: boolean; |
| previousSessionId?: string; |
| persistedThinking?: ThinkLevel; |
| persistedVerbose?: VerboseLevel; |
| }; |
|
|
| type SessionKeyResolution = { |
| agentId?: string; |
| sessionKey?: string; |
| sessionEntry?: InternalSessionEntry; |
| storePath: string; |
| }; |
|
|
| export function clearRotatedSessionMetadata(entry: InternalSessionEntry): InternalSessionEntry { |
| const next = { |
| ...entry, |
| sessionFile: undefined, |
| status: undefined, |
| lifecycleRunId: undefined, |
| lastRunId: undefined, |
| startedAt: undefined, |
| endedAt: undefined, |
| runtimeMs: undefined, |
| abortedLastRun: undefined, |
| restartRecoveryForceSafeTools: undefined, |
| restartRecoveryDeliveryContext: undefined, |
| restartRecoveryDeliveryMediaUrls: undefined, |
| restartRecoveryDisableMessageTool: undefined, |
| restartRecoverySuppressTextDelivery: undefined, |
| restartRecoveryDeliveryRequestFingerprint: undefined, |
| restartRecoveryDeliveryRunId: undefined, |
| restartRecoveryDeliverySourceRunId: undefined, |
| restartRecoveryBeforeAgentReplyState: undefined, |
| restartRecoveryDeliveryReceiptState: undefined, |
| restartRecoveryDeliveryToolCallId: undefined, |
| restartRecoveryRequesterAccountId: undefined, |
| restartRecoveryRequesterSenderId: undefined, |
| restartRecoverySameChannelThreadRequired: undefined, |
| restartRecoverySourceIngress: undefined, |
| restartRecoverySourceReplyDeliveryMode: undefined, |
| restartRecoveryTerminalDeliveryEvidence: undefined, |
| restartRecoveryTerminalRunIds: undefined, |
| sessionStartedAt: undefined, |
| sessionDiffBaseline: undefined, |
| sessionDiffBaselineCapture: undefined, |
| lastInteractionAt: undefined, |
| pendingTranscriptRepair: undefined, |
| }; |
| transitionMainSessionRecovery(next, { kind: "clear" }); |
| clearAllCliSessions(next); |
| return next; |
| } |
|
|
| type SessionIdMatchSet = { |
| candidates: SessionIdMatchCandidate[]; |
| ownerConflict: boolean; |
| }; |
|
|
| type SessionIdMatchCandidate = { |
| sessionKey: string; |
| entry: InternalSessionEntry; |
| resolution: Omit<SessionKeyResolution, "sessionEntry">; |
| primary: boolean; |
| }; |
|
|
| function selectSessionIdMatchCandidate( |
| candidates: SessionIdMatchCandidate[], |
| sessionId: string, |
| ): SessionIdMatchCandidate | undefined { |
| const selection = resolveSessionIdMatchSelection( |
| candidates.map((candidate) => [candidate.sessionKey, candidate.entry]), |
| sessionId, |
| ); |
| if (selection.kind !== "selected") { |
| return undefined; |
| } |
| return candidates |
| .filter((candidate) => candidate.sessionKey === selection.sessionKey) |
| .toSorted((left, right) => { |
| const updatedAt = (right.entry.updatedAt ?? 0) - (left.entry.updatedAt ?? 0); |
| if (updatedAt !== 0) { |
| return updatedAt; |
| } |
| if (left.primary !== right.primary) { |
| return left.primary ? -1 : 1; |
| } |
| return (left.resolution.agentId ?? "").localeCompare(right.resolution.agentId ?? ""); |
| })[0]; |
| } |
|
|
| function loadCommandSessionEntries(params: { |
| agentId?: string; |
| storePath: string; |
| }): SessionEntrySummary[] { |
| return listSessionEntriesReadOnly({ |
| storePath: params.storePath, |
| ...(params.agentId ? { agentId: params.agentId } : {}), |
| clone: false, |
| }); |
| } |
|
|
| |
| export function buildExplicitSessionIdSessionKey(params: { |
| sessionId: string; |
| agentId?: string; |
| }): string { |
| return `agent:${normalizeAgentId(params.agentId)}:explicit:${params.sessionId.trim()}`; |
| } |
|
|
| function collectSessionIdMatchesForRequest(opts: { |
| cfg: OpenClawConfig; |
| sessionEntries: SessionEntrySummary[]; |
| storePath: string; |
| storeAgentId?: string; |
| sessionId: string; |
| searchOtherAgentStores: boolean; |
| }): SessionIdMatchSet { |
| const candidates: SessionIdMatchCandidate[] = []; |
| let ownerConflict = false; |
| const configuredAgentIds = listAgentIds(opts.cfg).map(normalizeAgentId); |
| const compatibilityAgentId = tryResolveLegacyCompatibilityAgentId(opts.cfg); |
| const persistedStoreOwner = resolvePersistedSessionStoreOwner(opts.cfg); |
| const configuredStoreOwners = new Map<string, Set<string>>(); |
| for (const agentId of configuredAgentIds) { |
| const configuredStorePath = path.resolve( |
| resolveSessionStorePathCore(opts.cfg.session?.store, { agentId }), |
| ); |
| const owners = configuredStoreOwners.get(configuredStorePath) ?? new Set<string>(); |
| owners.add(agentId); |
| configuredStoreOwners.set(configuredStorePath, owners); |
| } |
|
|
| const addMatches = ( |
| candidateEntries: SessionEntrySummary[], |
| candidateStorePath: string, |
| candidateAgentId: string | undefined, |
| options?: { primary?: boolean }, |
| ): void => { |
| for (const { sessionKey: candidateKey, entry: candidateEntry } of candidateEntries) { |
| if (candidateEntry?.sessionId !== opts.sessionId) { |
| continue; |
| } |
| const normalizedCandidateAgentId = candidateAgentId |
| ? normalizeAgentId(candidateAgentId) |
| : undefined; |
| const scopedCandidateAgentId = |
| normalizedCandidateAgentId && configuredAgentIds.includes(normalizedCandidateAgentId) |
| ? normalizedCandidateAgentId |
| : undefined; |
| const pathOwners = configuredStoreOwners.get(path.resolve(candidateStorePath)); |
| const pathOwnedAgentId = |
| pathOwners?.size === 1 ? pathOwners.values().next().value : undefined; |
| const parsedAgentId = parseAgentSessionKey(candidateKey)?.agentId; |
| const normalizedParsedAgentId = parsedAgentId ? normalizeAgentId(parsedAgentId) : undefined; |
| if (normalizedParsedAgentId && !configuredAgentIds.includes(normalizedParsedAgentId)) { |
| continue; |
| } |
| const isLegacyUnscopedKey = classifySessionKeyShape(candidateKey) === "legacy_or_alias"; |
| |
| |
| const legacyUnscopedOwner = isLegacyUnscopedKey |
| ? persistedStoreOwner.kind === "configured" |
| ? persistedStoreOwner.agentId |
| : persistedStoreOwner.kind === "retired" |
| ? undefined |
| : (pathOwnedAgentId ?? |
| (opts.searchOtherAgentStores ? undefined : scopedCandidateAgentId) ?? |
| compatibilityAgentId) |
| : undefined; |
| const matchedAgentId = |
| normalizedParsedAgentId ?? |
| (isLegacyUnscopedKey |
| ? legacyUnscopedOwner |
| : (scopedCandidateAgentId ?? compatibilityAgentId)); |
| if (isLegacyUnscopedKey && persistedStoreOwner.kind === "retired") { |
| ownerConflict = true; |
| continue; |
| } |
| if ( |
| !opts.searchOtherAgentStores && |
| scopedCandidateAgentId && |
| matchedAgentId && |
| normalizeAgentId(matchedAgentId) !== scopedCandidateAgentId |
| ) { |
| ownerConflict = true; |
| continue; |
| } |
| candidates.push({ |
| sessionKey: candidateKey, |
| entry: candidateEntry, |
| primary: options?.primary === true, |
| resolution: { |
| ...(matchedAgentId ? { agentId: normalizeAgentId(matchedAgentId) } : {}), |
| sessionKey: candidateKey, |
| storePath: candidateStorePath, |
| }, |
| }); |
| } |
| }; |
|
|
| addMatches(opts.sessionEntries, opts.storePath, opts.storeAgentId, { primary: true }); |
| if (!opts.searchOtherAgentStores) { |
| return { candidates, ownerConflict }; |
| } |
|
|
| for (const agentId of configuredAgentIds) { |
| if (agentId === opts.storeAgentId) { |
| continue; |
| } |
| const candidateStorePath = resolveSessionStorePathCore(opts.cfg.session?.store, { agentId }); |
| addMatches( |
| loadCommandSessionEntries({ |
| agentId, |
| storePath: candidateStorePath, |
| }), |
| candidateStorePath, |
| agentId, |
| ); |
| } |
|
|
| return { candidates, ownerConflict }; |
| } |
|
|
| |
| |
| |
| |
| |
| export function resolveStoredSessionKeyForSessionId(opts: { |
| cfg: OpenClawConfig; |
| sessionId: string; |
| agentId?: string; |
| }): SessionKeyResolution { |
| const sessionId = opts.sessionId.trim(); |
| const requestedAgentId = opts.agentId?.trim() ? normalizeAgentId(opts.agentId) : undefined; |
| const persistedStoreOwner = resolvePersistedSessionStoreOwner(opts.cfg); |
| const storeAgentId = |
| requestedAgentId ?? |
| (persistedStoreOwner.kind === "configured" ? persistedStoreOwner.agentId : undefined) ?? |
| tryResolveLegacyCompatibilityAgentId(opts.cfg) ?? |
| resolveDefaultAgentId(opts.cfg, { |
| surface: "stored session lookup", |
| hint: "Pass an explicit agent id when looking up a session by id.", |
| }); |
| const storePath = resolveSessionStorePathCore(opts.cfg.session?.store, { |
| agentId: storeAgentId, |
| }); |
| const sessionEntries = loadCommandSessionEntries({ |
| storePath, |
| agentId: storeAgentId, |
| }); |
| if (!sessionId) { |
| return { sessionKey: undefined, storePath }; |
| } |
|
|
| const resolveMatchedAgentId = (sessionKey: string): string | undefined => { |
| const scopedAgentId = parseAgentSessionKey(sessionKey)?.agentId; |
| if (scopedAgentId) { |
| return normalizeAgentId(scopedAgentId); |
| } |
| const persistedRowOwner = resolvePersistedSessionStoreOwnerForKey(opts.cfg, sessionKey); |
| return persistedRowOwner.kind === "configured" |
| ? persistedRowOwner.agentId |
| : persistedRowOwner.kind === "retired" |
| ? undefined |
| : (requestedAgentId ?? tryResolveLegacyCompatibilityAgentId(opts.cfg)); |
| }; |
| const sessionIdMatches = sessionEntries.filter(({ entry }) => entry.sessionId === sessionId); |
| const selectionMatches = requestedAgentId |
| ? sessionIdMatches.filter( |
| ({ sessionKey }) => resolveMatchedAgentId(sessionKey) === requestedAgentId, |
| ) |
| : sessionIdMatches; |
| if (requestedAgentId && selectionMatches.length === 0 && sessionIdMatches.length > 0) { |
| throw new AgentSelectionRequiredError(listAgentIds(opts.cfg), { |
| surface: `stored session id "${sessionId}"`, |
| hint: `The matching rows belong to a different agent than agent "${requestedAgentId}".`, |
| }); |
| } |
| const selection = resolveSessionIdMatchSelection( |
| selectionMatches.map(({ sessionKey, entry }) => [sessionKey, entry]), |
| sessionId, |
| ); |
| if (selection.kind !== "selected") { |
| return { agentId: requestedAgentId, sessionKey: undefined, storePath }; |
| } |
|
|
| const sessionKey = selection.sessionKey; |
| const persistedRowOwner = resolvePersistedSessionStoreOwnerForKey(opts.cfg, sessionKey); |
| const resolvedAgentId = resolveMatchedAgentId(sessionKey); |
| if (!resolvedAgentId) { |
| throw new AgentSelectionRequiredError(listAgentIds(opts.cfg), { |
| surface: `stored session key "${sessionKey}"`, |
| hint: |
| persistedRowOwner.kind === "retired" |
| ? `The shared fixed-store row belongs to retired agent "${persistedRowOwner.agentId}".` |
| : "Pass an explicit agent id when looking up an unscoped session by id.", |
| }); |
| } |
| if (requestedAgentId && requestedAgentId !== resolvedAgentId) { |
| throw new AgentSelectionRequiredError(listAgentIds(opts.cfg), { |
| surface: `stored session key "${sessionKey}"`, |
| hint: `The matching row belongs to agent "${resolvedAgentId}", not agent "${requestedAgentId}".`, |
| }); |
| } |
| return { |
| agentId: resolvedAgentId, |
| sessionKey, |
| sessionEntry: structuredClone( |
| selectionMatches.find((match) => match.sessionKey === sessionKey)?.entry, |
| ), |
| storePath, |
| }; |
| } |
|
|
| function resolveSessionKeyForRequestInternal(opts: { |
| cfg: OpenClawConfig; |
| to?: string; |
| sessionId?: string; |
| sessionKey?: string; |
| agentId?: string; |
| createMissingSessionId: boolean; |
| }): SessionKeyResolution { |
| const sessionCfg = opts.cfg.session; |
| const scope = sessionCfg?.scope ?? "per-sender"; |
| const mainKey = normalizeMainKey(sessionCfg?.mainKey); |
| const requestedAgentId = opts.agentId?.trim() ? normalizeAgentId(opts.agentId) : undefined; |
| const requestedSessionId = opts.sessionId?.trim() || undefined; |
| const requestedSessionKey = opts.sessionKey?.trim() || undefined; |
| const toSessionKey = |
| !requestedSessionKey && !requestedSessionId && classifySessionKeyShape(opts.to) === "agent" |
| ? opts.to?.trim() |
| : undefined; |
| const explicitSessionKey = |
| requestedSessionKey || |
| toSessionKey || |
| (!requestedSessionId |
| ? resolveExplicitAgentSessionKey({ |
| cfg: opts.cfg, |
| agentId: requestedAgentId, |
| }) |
| : undefined); |
| const scopedSessionAgentId = parseAgentSessionKey(explicitSessionKey)?.agentId; |
| const explicitKeyStoreOwner = resolvePersistedSessionStoreOwnerForKey( |
| opts.cfg, |
| explicitSessionKey, |
| ); |
| if ( |
| explicitKeyStoreOwner.kind === "configured" && |
| requestedAgentId && |
| requestedAgentId !== explicitKeyStoreOwner.agentId |
| ) { |
| throw new AgentSelectionRequiredError(listAgentIds(opts.cfg), { |
| surface: `session key "${explicitSessionKey}"`, |
| hint: `The shared fixed-store row belongs to agent "${explicitKeyStoreOwner.agentId}", not --agent "${requestedAgentId}".`, |
| }); |
| } |
| if (explicitKeyStoreOwner.kind === "retired") { |
| throw new AgentSelectionRequiredError(listAgentIds(opts.cfg), { |
| surface: `session key "${explicitSessionKey}"`, |
| hint: `The shared fixed-store row belongs to retired agent "${explicitKeyStoreOwner.agentId}".`, |
| }); |
| } |
| const knownAgentId = |
| requestedAgentId ?? |
| scopedSessionAgentId ?? |
| (explicitKeyStoreOwner.kind === "configured" ? explicitKeyStoreOwner.agentId : undefined) ?? |
| tryResolveLegacyCompatibilityAgentId(opts.cfg); |
| const unownedBareSessionKey = Boolean( |
| requestedSessionId && |
| explicitSessionKey && |
| classifySessionKeyShape(explicitSessionKey) === "legacy_or_alias" && |
| !knownAgentId, |
| ); |
| |
| |
| const sessionIdScanAnchor = requestedSessionId |
| ? (knownAgentId ?? listAgentIds(opts.cfg)[0]) |
| : undefined; |
| const defaultAgentId = knownAgentId |
| ? normalizeAgentId(knownAgentId) |
| : requestedSessionId |
| ? undefined |
| : normalizeAgentId( |
| resolveDefaultAgentId(opts.cfg, { |
| surface: "agent command session routing", |
| hint: "Pass --agent <id> or an agent-prefixed --session-key.", |
| }), |
| ); |
| const storeAgentId = explicitSessionKey |
| ? unownedBareSessionKey |
| ? sessionIdScanAnchor |
| : isUnscopedSessionKeySentinel(explicitSessionKey) |
| ? (requestedAgentId ?? defaultAgentId) |
| : resolveAgentIdFromSessionKey(explicitSessionKey, defaultAgentId) |
| : (requestedAgentId ?? defaultAgentId ?? sessionIdScanAnchor); |
| if (!storeAgentId) { |
| throw new AgentSelectionRequiredError(listAgentIds(opts.cfg), { |
| surface: "agent command session routing", |
| hint: "Pass --agent <id> or an agent-prefixed --session-key.", |
| }); |
| } |
| const storePath = resolveSessionStorePathCore(sessionCfg?.store, { |
| agentId: storeAgentId, |
| }); |
| const ctx: MsgContext | undefined = opts.to?.trim() ? { From: opts.to } : undefined; |
| let sessionKey: string | undefined = |
| (!unownedBareSessionKey && explicitSessionKey |
| ? canonicalizeMainSessionAlias({ |
| cfg: opts.cfg, |
| agentId: storeAgentId, |
| sessionKey: explicitSessionKey, |
| }) |
| : undefined) ?? |
| (!unownedBareSessionKey && ctx |
| ? resolveSessionKey(scope, ctx, mainKey, storeAgentId) |
| : undefined); |
|
|
| |
| |
| |
| const storeSessionKey = sessionKey ? normalizeStoreSessionKey(sessionKey) : undefined; |
| const sessionEntry = |
| storeSessionKey && !isInternalSessionEffectsKey(storeSessionKey) |
| ? loadExactSessionEntryReadOnly({ |
| agentId: storeAgentId, |
| storePath, |
| sessionKey: storeSessionKey, |
| })?.entry |
| : undefined; |
|
|
| |
| |
| |
| |
| if ( |
| requestedSessionId && |
| (!explicitSessionKey || unownedBareSessionKey) && |
| (!sessionKey || sessionEntry?.sessionId !== requestedSessionId) |
| ) { |
| const { candidates, ownerConflict } = collectSessionIdMatchesForRequest({ |
| cfg: opts.cfg, |
| sessionEntries: loadCommandSessionEntries({ storePath, agentId: storeAgentId }), |
| storePath, |
| storeAgentId, |
| sessionId: requestedSessionId, |
| searchOtherAgentStores: requestedAgentId === undefined, |
| }); |
| const selectedMatch = selectSessionIdMatchCandidate( |
| candidates.filter((candidate) => candidate.resolution.agentId !== undefined), |
| requestedSessionId, |
| ); |
| if (selectedMatch) { |
| return { |
| ...selectedMatch.resolution, |
| sessionEntry: structuredClone(selectedMatch.entry), |
| }; |
| } |
| if (ownerConflict) { |
| throw new AgentSelectionRequiredError(listAgentIds(opts.cfg), { |
| surface: `session id "${requestedSessionId}"`, |
| hint: requestedAgentId |
| ? `The matching session belongs to a different agent than --agent "${requestedAgentId}".` |
| : "The matching unscoped session belongs to a retired fixed-store owner.", |
| }); |
| } |
| } |
|
|
| if (requestedSessionId && !sessionKey && opts.createMissingSessionId) { |
| const explicitSessionAgentId = |
| requestedAgentId ?? |
| tryResolveLegacyCompatibilityAgentId(opts.cfg) ?? |
| resolveDefaultAgentId(opts.cfg, { |
| surface: "agent command session creation", |
| hint: "Pass --agent <id> when creating a session from --session-id.", |
| }); |
| sessionKey = buildExplicitSessionIdSessionKey({ |
| sessionId: requestedSessionId, |
| agentId: explicitSessionAgentId, |
| }); |
| return { |
| agentId: explicitSessionAgentId, |
| sessionKey, |
| storePath, |
| }; |
| } |
|
|
| return { agentId: storeAgentId, sessionKey, sessionEntry, storePath }; |
| } |
|
|
| |
| export function resolveExistingSessionKeyForRequest(opts: { |
| cfg: OpenClawConfig; |
| sessionId: string; |
| agentId?: string; |
| }): SessionKeyResolution { |
| return resolveSessionKeyForRequestInternal({ ...opts, createMissingSessionId: false }); |
| } |
|
|
| |
| function resolveSessionKeyForRequest(opts: { |
| cfg: OpenClawConfig; |
| to?: string; |
| sessionId?: string; |
| sessionKey?: string; |
| agentId?: string; |
| }): SessionKeyResolution { |
| return resolveSessionKeyForRequestInternal({ ...opts, createMissingSessionId: true }); |
| } |
|
|
| |
| export function resolveSessionKeyForRequestCore( |
| opts: Parameters<typeof resolveSessionKeyForRequest>[0], |
| ): SessionKeyResolution { |
| return resolveSessionKeyForRequest(opts); |
| } |
|
|
| |
| export function resolveSession(opts: { |
| cfg: OpenClawConfig; |
| to?: string; |
| sessionId?: string; |
| sessionKey?: string; |
| agentId?: string; |
| }): SessionResolution { |
| const sessionCfg = opts.cfg.session; |
| const { |
| agentId: resolvedAgentId, |
| sessionKey, |
| sessionEntry, |
| storePath, |
| } = resolveSessionKeyForRequestCore({ |
| cfg: opts.cfg, |
| to: opts.to, |
| sessionId: opts.sessionId, |
| sessionKey: opts.sessionKey, |
| agentId: opts.agentId, |
| }); |
| const now = Date.now(); |
|
|
| const sessionAgentId = |
| (opts.agentId?.trim() ? normalizeAgentId(opts.agentId) : undefined) ?? |
| resolvedAgentId ?? |
| parseAgentSessionKey(sessionKey)?.agentId ?? |
| tryResolveLegacyCompatibilityAgentId(opts.cfg) ?? |
| resolveDefaultAgentId(opts.cfg, { |
| surface: "agent command session ownership", |
| hint: "Pass --agent <id> or an agent-prefixed --session-key.", |
| }); |
|
|
| const resetType = resolveSessionResetType({ sessionKey }); |
| const channelReset = resolveChannelResetConfig({ |
| sessionCfg, |
| channel: sessionDeliveryChannel(sessionEntry), |
| }); |
| const resetPolicy = resolveSessionResetPolicy({ |
| sessionCfg, |
| resetType, |
| resetOverride: channelReset, |
| }); |
| const requestedSessionId = opts.sessionId?.trim() || undefined; |
| const terminalMainTranscriptNewerThanRegistry = |
| sessionEntry && !requestedSessionId |
| ? hasTerminalMainSessionTranscriptNewerThanRegistrySync({ |
| entry: sessionEntry, |
| sessionScope: sessionCfg?.scope, |
| sessionKey, |
| agentId: sessionAgentId, |
| mainKey: sessionCfg?.mainKey, |
| storePath, |
| }) |
| : false; |
| const lockedModelSelection = isModelSelectionLocked(sessionEntry); |
| const skipImplicitExpiry = |
| resetPolicy.configured !== true && hasProviderOwnedSession(sessionEntry); |
| const fresh = sessionEntry |
| ? lockedModelSelection || |
| (!terminalMainTranscriptNewerThanRegistry && |
| (skipImplicitExpiry || |
| evaluateSessionFreshness({ |
| updatedAt: sessionEntry.updatedAt, |
| ...resolveSessionLifecycleTimestamps({ |
| entry: sessionEntry, |
| agentId: sessionAgentId, |
| sessionKey, |
| storePath, |
| }), |
| now, |
| policy: resetPolicy, |
| }).fresh)) |
| : false; |
| const sessionId = |
| requestedSessionId || (fresh ? sessionEntry?.sessionId : undefined) || crypto.randomUUID(); |
| const isNewSession = !fresh && !requestedSessionId; |
| const resolvedSessionEntry = |
| isNewSession && sessionEntry ? clearRotatedSessionMetadata(sessionEntry) : sessionEntry; |
|
|
| clearBootstrapSnapshotOnSessionRollover({ |
| sessionKey, |
| previousSessionId: isNewSession ? sessionEntry?.sessionId : undefined, |
| }); |
|
|
| |
| |
| const persistedThinking = sessionEntry?.thinkingLevel |
| ? normalizeThinkLevel(sessionEntry.thinkingLevel) |
| : undefined; |
| const persistedVerbose = sessionEntry?.verboseLevel |
| ? normalizeVerboseLevel(sessionEntry.verboseLevel) |
| : undefined; |
|
|
| return { |
| sessionId, |
| sessionKey, |
| sessionEntry: resolvedSessionEntry, |
| storePath, |
| isNewSession, |
| previousSessionId: isNewSession ? sessionEntry?.sessionId : undefined, |
| persistedThinking, |
| persistedVerbose, |
| }; |
| } |
|
|