mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-25 22:11:18 +00:00
* refactor(agents): privatize session state types * chore(deadcode): shrink agents export baseline
131 lines
4.2 KiB
TypeScript
131 lines
4.2 KiB
TypeScript
import { resolveInternalSessionEffectsIdentity } from "../config/sessions/internal-session-key.js";
|
|
/** Manages hidden SQLite sessions used for suppressed agent side effects. */
|
|
import {
|
|
applySessionEntryLifecycleMutation,
|
|
forkSessionFromParentTranscript,
|
|
loadExactSessionEntry,
|
|
replaceTranscriptEvents,
|
|
upsertSessionEntry,
|
|
} from "../config/sessions/session-accessor.js";
|
|
import { formatSqliteSessionFileMarker } from "../config/sessions/sqlite-marker.js";
|
|
import { createSessionTranscriptHeader } from "../config/sessions/transcript-header.js";
|
|
import type { SessionEntry } from "../config/sessions/types.js";
|
|
import type { AgentRunSessionTarget } from "./run-session-target.js";
|
|
|
|
type InternalSessionEffectsTarget = Required<
|
|
Pick<AgentRunSessionTarget, "agentId" | "sessionId" | "sessionKey" | "storePath">
|
|
> & {
|
|
sessionEntry: SessionEntry;
|
|
sessionFile: string;
|
|
};
|
|
|
|
type InternalSessionEffectsSource = Required<
|
|
Pick<AgentRunSessionTarget, "agentId" | "sessionId" | "sessionKey" | "storePath">
|
|
>;
|
|
|
|
/** Resolves the deterministic SQLite target owned by one internal-effects run. */
|
|
export function resolveInternalSessionEffectsTarget(params: {
|
|
agentId: string;
|
|
runId: string;
|
|
storePath: string;
|
|
}): Required<Pick<AgentRunSessionTarget, "agentId" | "sessionId" | "sessionKey" | "storePath">> {
|
|
return {
|
|
agentId: params.agentId,
|
|
storePath: params.storePath,
|
|
...resolveInternalSessionEffectsIdentity(params),
|
|
};
|
|
}
|
|
|
|
function toInternalSessionEffectsTarget(params: {
|
|
agentId: string;
|
|
entry: SessionEntry;
|
|
sessionKey: string;
|
|
storePath: string;
|
|
}): InternalSessionEffectsTarget {
|
|
return {
|
|
agentId: params.agentId,
|
|
sessionId: params.entry.sessionId,
|
|
sessionKey: params.sessionKey,
|
|
storePath: params.storePath,
|
|
sessionEntry: params.entry,
|
|
sessionFile: formatSqliteSessionFileMarker({
|
|
agentId: params.agentId,
|
|
sessionId: params.entry.sessionId,
|
|
storePath: params.storePath,
|
|
}),
|
|
};
|
|
}
|
|
|
|
/** Creates or reopens the hidden SQLite session owned by one internal-effects run. */
|
|
export async function prepareInternalSessionEffectsSession(params: {
|
|
agentId: string;
|
|
cwd?: string;
|
|
runId: string;
|
|
source?: InternalSessionEffectsSource;
|
|
storePath: string;
|
|
}): Promise<InternalSessionEffectsTarget> {
|
|
const scope = resolveInternalSessionEffectsTarget(params);
|
|
const existing = loadExactSessionEntry(scope)?.entry;
|
|
if (existing?.sessionId === scope.sessionId) {
|
|
return toInternalSessionEffectsTarget({
|
|
agentId: params.agentId,
|
|
entry: existing,
|
|
sessionKey: scope.sessionKey,
|
|
storePath: params.storePath,
|
|
});
|
|
}
|
|
|
|
const fork = params.source
|
|
? await forkSessionFromParentTranscript({
|
|
agentId: params.source.agentId,
|
|
parentEntry: { sessionId: params.source.sessionId, updatedAt: Date.now() },
|
|
parentSessionKey: params.source.sessionKey,
|
|
sessionKey: scope.sessionKey,
|
|
storePath: params.source.storePath,
|
|
targetSessionId: scope.sessionId,
|
|
targetStorePath: params.storePath,
|
|
})
|
|
: undefined;
|
|
if (fork?.status !== "created") {
|
|
await replaceTranscriptEvents(scope, [
|
|
createSessionTranscriptHeader({ cwd: params.cwd, sessionId: scope.sessionId }),
|
|
]);
|
|
}
|
|
const now = Date.now();
|
|
const entry = await upsertSessionEntry(scope, {
|
|
sessionId: scope.sessionId,
|
|
sessionStartedAt: now,
|
|
updatedAt: now,
|
|
});
|
|
if (!entry) {
|
|
throw new Error(`Failed to create internal SQLite session for run ${params.runId}`);
|
|
}
|
|
return toInternalSessionEffectsTarget({
|
|
agentId: params.agentId,
|
|
entry,
|
|
sessionKey: scope.sessionKey,
|
|
storePath: params.storePath,
|
|
});
|
|
}
|
|
|
|
/** Hard-deletes a run-owned hidden session and its SQLite transcript rows. */
|
|
export async function removeInternalSessionEffectsSession(
|
|
target: AgentRunSessionTarget | undefined,
|
|
): Promise<void> {
|
|
if (!target?.sessionKey || !target.storePath) {
|
|
return;
|
|
}
|
|
await applySessionEntryLifecycleMutation({
|
|
...(target.agentId ? { agentId: target.agentId } : {}),
|
|
storePath: target.storePath,
|
|
removals: [
|
|
{
|
|
sessionKey: target.sessionKey,
|
|
...(target.sessionId ? { expectedSessionId: target.sessionId } : {}),
|
|
archiveRemovedTranscript: false,
|
|
},
|
|
],
|
|
skipMaintenance: true,
|
|
});
|
|
}
|