mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-21 21:56:46 +00:00
refactor: remove transcript locator from session rows
This commit is contained in:
@@ -759,10 +759,12 @@ describe("spawnAcpDirect", () => {
|
||||
sessionKey: accepted.childSessionKey,
|
||||
entry: expect.objectContaining({
|
||||
sessionId: "sess-123",
|
||||
sessionFile: "sess-123",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
for (const call of hoisted.upsertSessionEntryMock.mock.calls) {
|
||||
expect(call[0].entry).not.toHaveProperty("transcriptLocator");
|
||||
}
|
||||
});
|
||||
|
||||
it("allows ACP resume IDs recorded for the requester session", async () => {
|
||||
@@ -1567,10 +1569,12 @@ describe("spawnAcpDirect", () => {
|
||||
agentId: "codex",
|
||||
entry: expect.objectContaining({
|
||||
sessionId: "sess-123",
|
||||
sessionFile: "sess-123",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
expect(hoisted.upsertSessionEntryMock.mock.calls[0]?.[0].entry).not.toHaveProperty(
|
||||
"transcriptLocator",
|
||||
);
|
||||
});
|
||||
|
||||
it("binds ACP sessions through the configured default account when accountId is omitted", async () => {
|
||||
@@ -1931,10 +1935,12 @@ describe("spawnAcpDirect", () => {
|
||||
agentId: "codex",
|
||||
entry: expect.objectContaining({
|
||||
sessionId: "sess-123",
|
||||
sessionFile: "sess-123",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
expect(hoisted.upsertSessionEntryMock.mock.calls.at(-1)?.[0].entry).not.toHaveProperty(
|
||||
"transcriptLocator",
|
||||
);
|
||||
}
|
||||
expectAgentGatewayCall(expectedAgentCall);
|
||||
});
|
||||
|
||||
@@ -521,7 +521,6 @@ async function persistAcpSpawnSessionRowBestEffort(params: {
|
||||
sessionStartedAt: now,
|
||||
}),
|
||||
sessionId: params.sessionId,
|
||||
sessionFile: params.sessionId,
|
||||
};
|
||||
upsertSessionEntry({
|
||||
agentId: params.agentId,
|
||||
|
||||
@@ -366,7 +366,6 @@ async function prepareSubagentSessionContext(params: {
|
||||
}
|
||||
const nextChildEntry = mergeSessionEntry(childEntry, {
|
||||
sessionId: forked.sessionId,
|
||||
transcriptLocator: forked.transcriptLocator,
|
||||
forkedFromParent: true,
|
||||
});
|
||||
await subagentSpawnDeps.upsertSessionEntry({
|
||||
|
||||
@@ -141,7 +141,6 @@ export function createSessionsListTool(opts?: {
|
||||
row: SessionListRow;
|
||||
titleEntry: SessionEntry;
|
||||
sessionId: string;
|
||||
sessionFile?: string;
|
||||
agentId: string;
|
||||
}> = [];
|
||||
|
||||
@@ -217,8 +216,6 @@ export function createSessionsListTool(opts?: {
|
||||
});
|
||||
|
||||
const sessionId = readStringValue(entry.sessionId);
|
||||
const sessionFileRaw = (entry as { sessionFile?: unknown }).sessionFile;
|
||||
const sessionFile = readStringValue(sessionFileRaw);
|
||||
const resolvedAgentId = resolveAgentIdFromSessionKey(key);
|
||||
|
||||
const row: SessionListRow = {
|
||||
@@ -314,7 +311,6 @@ export function createSessionsListTool(opts?: {
|
||||
updatedAt: typeof row.updatedAt === "number" ? row.updatedAt : 0,
|
||||
},
|
||||
sessionId,
|
||||
...(sessionFile ? { sessionFile } : {}),
|
||||
agentId: resolvedAgentId,
|
||||
});
|
||||
}
|
||||
@@ -342,7 +338,7 @@ export function createSessionsListTool(opts?: {
|
||||
const target = titleTargets[next];
|
||||
const fields = await readSessionTitleFieldsFromTranscriptAsync(
|
||||
target.sessionId,
|
||||
target.sessionFile,
|
||||
undefined,
|
||||
target.agentId,
|
||||
);
|
||||
if (includeDerivedTitles && !target.row.derivedTitle) {
|
||||
|
||||
@@ -554,7 +554,7 @@ export async function runPreflightCompactionIfNeeded(params: {
|
||||
}) ??
|
||||
resolveSessionLogPath(
|
||||
entry.sessionId,
|
||||
{ ...entry, transcriptLocator: params.followupRun.run.transcriptLocator },
|
||||
entry,
|
||||
params.sessionKey ?? params.followupRun.run.sessionKey,
|
||||
);
|
||||
const result = await memoryDeps.compactEmbeddedPiSession({
|
||||
|
||||
@@ -285,7 +285,10 @@ export async function incrementCompactionCount(params: {
|
||||
updates.cacheRead = undefined;
|
||||
updates.cacheWrite = undefined;
|
||||
}
|
||||
const { transcriptLocator: _derivedTranscriptLocator, ...entryWithoutLocator } = entry;
|
||||
const { transcriptLocator: _derivedTranscriptLocator, ...entryWithoutLocator } =
|
||||
entry as SessionEntry & {
|
||||
transcriptLocator?: unknown;
|
||||
};
|
||||
sessionStore[sessionKey] = {
|
||||
...entryWithoutLocator,
|
||||
...updates,
|
||||
|
||||
@@ -197,7 +197,7 @@ export async function repairHeartbeatPoisonedMainSession(params: {
|
||||
try {
|
||||
transcriptPath = resolveSessionTranscriptLocator(
|
||||
mainEntry.sessionId,
|
||||
mainEntry,
|
||||
undefined,
|
||||
params.sessionPathOpts,
|
||||
);
|
||||
} catch {
|
||||
@@ -207,13 +207,7 @@ export async function repairHeartbeatPoisonedMainSession(params: {
|
||||
resolveHeartbeatMainSessionRepairCandidate({
|
||||
entry,
|
||||
transcriptPath,
|
||||
}) ??
|
||||
(mainEntry.sessionFile && mainEntry.sessionFile !== transcriptPath
|
||||
? resolveHeartbeatMainSessionRepairCandidate({
|
||||
entry,
|
||||
transcriptPath: mainEntry.sessionFile,
|
||||
})
|
||||
: null);
|
||||
});
|
||||
const candidate = resolveCandidate(mainEntry);
|
||||
if (!candidate) {
|
||||
return;
|
||||
|
||||
@@ -73,7 +73,7 @@ export function isSqliteSessionTranscriptLocator(locator: string | undefined): b
|
||||
|
||||
export function resolveSessionTranscriptLocator(
|
||||
sessionId: string,
|
||||
entry?: { transcriptLocator?: string },
|
||||
entry?: unknown,
|
||||
opts?: SessionTranscriptLocatorOptions,
|
||||
): string {
|
||||
void entry;
|
||||
|
||||
@@ -34,8 +34,11 @@ export async function resolveAndPersistSessionTranscriptIdentity(params: {
|
||||
sessionStartedAt: baseEntry.sessionId === sessionId ? (baseEntry.sessionStartedAt ?? now) : now,
|
||||
};
|
||||
const { transcriptLocator: _derivedTranscriptLocator, ...entryWithoutDerivedLocator } =
|
||||
persistedEntry;
|
||||
if (baseEntry.sessionId !== sessionId || baseEntry.transcriptLocator) {
|
||||
persistedEntry as SessionEntry & { transcriptLocator?: unknown };
|
||||
if (
|
||||
baseEntry.sessionId !== sessionId ||
|
||||
"transcriptLocator" in (baseEntry as SessionEntry & { transcriptLocator?: unknown })
|
||||
) {
|
||||
upsertSessionEntry({
|
||||
agentId,
|
||||
sessionKey,
|
||||
|
||||
@@ -57,7 +57,9 @@ function stripDerivedTranscriptLocator(entry: SessionEntry | null): SessionEntry
|
||||
if (!entry) {
|
||||
return null;
|
||||
}
|
||||
const { transcriptLocator: _derivedTranscriptLocator, ...rest } = entry;
|
||||
const { transcriptLocator: _derivedTranscriptLocator, ...rest } = entry as SessionEntry & {
|
||||
transcriptLocator?: unknown;
|
||||
};
|
||||
return rest;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ export type SessionCompactionCheckpointReason =
|
||||
|
||||
export type SessionCompactionTranscriptReference = {
|
||||
sessionId: string;
|
||||
sessionFile?: string;
|
||||
transcriptLocator?: string;
|
||||
leafId?: string;
|
||||
entryId?: string;
|
||||
};
|
||||
@@ -195,7 +195,6 @@ export type SessionEntry = {
|
||||
pluginNextTurnInjections?: Record<string, SessionPluginNextTurnInjection[]>;
|
||||
sessionId: string;
|
||||
updatedAt: number;
|
||||
sessionFile?: string;
|
||||
/** Parent session key that spawned this session (used for sandbox session-tool scoping). */
|
||||
spawnedBy?: string;
|
||||
/** Workspace inherited by spawned sessions and reused on later turns for the same child session. */
|
||||
@@ -486,7 +485,7 @@ function normalizeMergedUpdatedAt(value: number | undefined, now: number): numbe
|
||||
}
|
||||
|
||||
function stripDerivedSessionEntryFields<T extends SessionEntry>(entry: T): T {
|
||||
delete entry.transcriptLocator;
|
||||
delete (entry as T & { transcriptLocator?: unknown }).transcriptLocator;
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,16 +106,10 @@ export function createCronPromptExecutor(params: {
|
||||
Partial<Omit<CronAgentExecutionPhaseUpdate, "jobId" | "phase">>,
|
||||
) => void;
|
||||
}) {
|
||||
const sessionFile =
|
||||
params.cronSession.sessionEntry.sessionFile?.trim() ||
|
||||
createSqliteSessionTranscriptLocator({
|
||||
sessionId: params.cronSession.sessionEntry.sessionId,
|
||||
agentId: params.agentId,
|
||||
});
|
||||
// Fallback for callers that bypass prepareCronRunContext before persisting retries.
|
||||
if (!params.cronSession.sessionEntry.sessionFile?.trim()) {
|
||||
params.cronSession.sessionEntry.sessionFile = sessionFile;
|
||||
}
|
||||
const transcriptLocator = createSqliteSessionTranscriptLocator({
|
||||
sessionId: params.cronSession.sessionEntry.sessionId,
|
||||
agentId: params.agentId,
|
||||
});
|
||||
const cronFallbacksOverride = resolveCronFallbacksOverride({
|
||||
cfg: params.cfg,
|
||||
job: params.job,
|
||||
@@ -162,7 +156,7 @@ export function createCronPromptExecutor(params: {
|
||||
agentId: params.agentId,
|
||||
trigger: "cron",
|
||||
jobId: params.job.id,
|
||||
sessionFile,
|
||||
transcriptLocator,
|
||||
workspaceDir: params.workspaceDir,
|
||||
config: params.cfgWithAgentDefaults,
|
||||
prompt: promptText,
|
||||
@@ -210,7 +204,7 @@ export function createCronPromptExecutor(params: {
|
||||
messageTo: params.resolvedDelivery.to,
|
||||
messageThreadId: params.resolvedDelivery.threadId,
|
||||
currentChannelId,
|
||||
sessionFile,
|
||||
transcriptLocator,
|
||||
agentDir: params.agentDir,
|
||||
workspaceDir: params.workspaceDir,
|
||||
config: params.cfgWithAgentDefaults,
|
||||
|
||||
@@ -31,7 +31,7 @@ function cronTranscriptExists(params: { sessionKey: string; entry: SessionEntry
|
||||
}
|
||||
|
||||
function toNonResumableCronSessionEntry(entry: SessionEntry): SessionEntry {
|
||||
const next = { ...entry } as Partial<SessionEntry>;
|
||||
const next = { ...entry } as Partial<SessionEntry> & { transcriptLocator?: unknown };
|
||||
delete next.sessionId;
|
||||
delete next.sessionFile;
|
||||
delete next.sessionStartedAt;
|
||||
|
||||
@@ -66,7 +66,6 @@ import {
|
||||
resolveHookExternalContentSource,
|
||||
isThinkingLevelSupported,
|
||||
resolveSupportedThinkingLevel,
|
||||
createSqliteSessionTranscriptLocator,
|
||||
resolveThinkingDefault,
|
||||
setSessionRuntimeModel,
|
||||
} from "./run.runtime.js";
|
||||
@@ -536,12 +535,6 @@ async function prepareCronRunContext(params: {
|
||||
forceNew: input.job.sessionTarget === "isolated",
|
||||
});
|
||||
const runSessionId = cronSession.sessionEntry.sessionId;
|
||||
if (!cronSession.sessionEntry.sessionFile?.trim()) {
|
||||
cronSession.sessionEntry.sessionFile = createSqliteSessionTranscriptLocator({
|
||||
sessionId: runSessionId,
|
||||
agentId,
|
||||
});
|
||||
}
|
||||
const runSessionKey = baseSessionKey.startsWith("cron:")
|
||||
? `${agentSessionKey}:run:${runSessionId}`
|
||||
: agentSessionKey;
|
||||
|
||||
@@ -2385,7 +2385,7 @@ export const chatHandlers: GatewayRequestHandlers = {
|
||||
message: transcriptReply,
|
||||
...(persistedContentForAppend?.length ? { content: persistedContentForAppend } : {}),
|
||||
sessionId,
|
||||
transcriptLocator: resolvedTranscriptLocator,
|
||||
transcriptLocator: resolvedTranscriptLocator ?? undefined,
|
||||
agentId,
|
||||
createIfMissing: true,
|
||||
idempotencyKey: `${clientRunId}:assistant-media`,
|
||||
@@ -2614,7 +2614,7 @@ export const chatHandlers: GatewayRequestHandlers = {
|
||||
? { content: persistedContentForAppend }
|
||||
: {}),
|
||||
sessionId,
|
||||
transcriptLocator: resolvedTranscriptLocator,
|
||||
transcriptLocator: resolvedTranscriptLocator ?? undefined,
|
||||
agentId,
|
||||
createIfMissing: true,
|
||||
cfg,
|
||||
|
||||
@@ -13,7 +13,6 @@ const SESSION_ENTRY_RESERVED_SLOT_KEY_LIST = [
|
||||
"pluginNextTurnInjections",
|
||||
"sessionId",
|
||||
"updatedAt",
|
||||
"sessionFile",
|
||||
"spawnedBy",
|
||||
"spawnedWorkspaceDir",
|
||||
"parentSessionKey",
|
||||
|
||||
@@ -265,7 +265,7 @@ const readUsageFromSessionLog = (
|
||||
agentId ?? (sessionKey ? resolveAgentIdFromSessionKey(sessionKey) : undefined);
|
||||
const snapshot = readRecentSessionUsageFromTranscript(
|
||||
sessionId,
|
||||
sessionEntry?.sessionFile,
|
||||
undefined,
|
||||
resolvedAgentId,
|
||||
256 * 1024,
|
||||
);
|
||||
|
||||
@@ -4,10 +4,7 @@ import {
|
||||
forkSessionFromParent,
|
||||
resolveParentForkDecision,
|
||||
} from "../auto-reply/reply/session-fork.js";
|
||||
import {
|
||||
createSqliteSessionTranscriptLocator,
|
||||
isSqliteSessionTranscriptLocator,
|
||||
} from "../config/sessions/paths.js";
|
||||
import { createSqliteSessionTranscriptLocator } from "../config/sessions/paths.js";
|
||||
import { parseSessionThreadInfoFast } from "../config/sessions/thread-info.js";
|
||||
import type { SessionEntry } from "../config/sessions/types.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
@@ -167,7 +164,6 @@ async function resolveRealtimeVoiceAgentConsultSessionEntry(params: {
|
||||
...existing,
|
||||
...deliveryFields,
|
||||
sessionId: fork.sessionId,
|
||||
sessionFile: fork.sessionFile,
|
||||
spawnedBy: requesterSessionKey,
|
||||
forkedFromParent: true,
|
||||
updatedAt: now,
|
||||
@@ -220,7 +216,6 @@ export async function consultRealtimeVoiceAgent(params: {
|
||||
provider?: RunEmbeddedPiAgentParams["provider"];
|
||||
model?: RunEmbeddedPiAgentParams["model"];
|
||||
thinkLevel?: RunEmbeddedPiAgentParams["thinkLevel"];
|
||||
fastMode?: RunEmbeddedPiAgentParams["fastMode"];
|
||||
timeoutMs?: number;
|
||||
toolsAllow?: string[];
|
||||
extraSystemPrompt?: string;
|
||||
@@ -250,14 +245,10 @@ export async function consultRealtimeVoiceAgent(params: {
|
||||
resolvedDeliveryContext ?? deliveryContextFromSession(sessionEntry);
|
||||
const sessionId = sessionEntry.sessionId;
|
||||
|
||||
const persistedSessionFile = sessionEntry.sessionFile?.trim();
|
||||
const sessionFile =
|
||||
persistedSessionFile && isSqliteSessionTranscriptLocator(persistedSessionFile)
|
||||
? persistedSessionFile
|
||||
: createSqliteSessionTranscriptLocator({
|
||||
agentId,
|
||||
sessionId,
|
||||
});
|
||||
const transcriptLocator = createSqliteSessionTranscriptLocator({
|
||||
agentId,
|
||||
sessionId,
|
||||
});
|
||||
const result = await params.agentRuntime.runEmbeddedPiAgent({
|
||||
sessionId,
|
||||
sessionKey: params.sessionKey,
|
||||
@@ -273,7 +264,7 @@ export async function consultRealtimeVoiceAgent(params: {
|
||||
consultDeliveryContext?.threadId != null
|
||||
? String(consultDeliveryContext.threadId)
|
||||
: undefined,
|
||||
sessionFile,
|
||||
transcriptLocator,
|
||||
workspaceDir,
|
||||
config: params.cfg,
|
||||
prompt: buildRealtimeVoiceAgentConsultPrompt({
|
||||
@@ -287,7 +278,6 @@ export async function consultRealtimeVoiceAgent(params: {
|
||||
provider: params.provider,
|
||||
model: params.model,
|
||||
thinkLevel: params.thinkLevel ?? "high",
|
||||
fastMode: params.fastMode,
|
||||
verboseLevel: "off",
|
||||
reasoningLevel: "off",
|
||||
toolResultFormat: "plain",
|
||||
|
||||
@@ -207,7 +207,7 @@ export class EmbeddedTuiBackend implements TuiBackend {
|
||||
const max = Math.min(1000, typeof opts.limit === "number" ? opts.limit : 200);
|
||||
const maxHistoryBytes = getMaxChatHistoryMessagesBytes();
|
||||
const localMessages = sessionId
|
||||
? await readSessionMessagesAsync(sessionId, entry?.sessionFile, {
|
||||
? await readSessionMessagesAsync(sessionId, undefined, {
|
||||
agentId: sessionAgentId,
|
||||
mode: "recent",
|
||||
maxMessages: max,
|
||||
|
||||
Reference in New Issue
Block a user