mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
refactor: burn down export name collision baseline (#121870)
* refactor(sessions): distinguish persistence owners * refactor(config): consolidate legacy record helper * refactor(sessions): name sqlite number coercion * chore(scripts): ratchet export collision baseline
This commit is contained in:
committed by
GitHub
parent
e7350b4ac6
commit
5f562e65f6
@@ -262,13 +262,6 @@
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "ensureRecord",
|
||||
"files": [
|
||||
"src/commands/doctor/shared/legacy-config-record-shared.ts",
|
||||
"src/config/legacy.shared.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "extractAssistantVisibleText",
|
||||
"files": [
|
||||
@@ -681,13 +674,6 @@
|
||||
"src/cron/run-diagnostics.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "normalizeSqliteNumber",
|
||||
"files": [
|
||||
"src/config/sessions/session-accessor.sqlite-normalize.ts",
|
||||
"src/infra/sqlite-number.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "normalizeStringRecord",
|
||||
"files": [
|
||||
@@ -793,14 +779,6 @@
|
||||
"src/gateway/server-methods/__mocks__/tools-effective.runtime.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "persistSessionEntry",
|
||||
"files": [
|
||||
"src/agents/command/attempt-execution.shared.ts",
|
||||
"src/agents/command/session-helpers.ts",
|
||||
"src/auto-reply/reply/commands-session-store.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "planPluginUninstall",
|
||||
"files": [
|
||||
|
||||
@@ -162,7 +162,7 @@ vi.mock("./command/attempt-execution.shared.js", async () => {
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
persistSessionEntry: (...args: unknown[]) => state.persistSessionEntryMock(...args),
|
||||
persistAgentSession: (...args: unknown[]) => state.persistSessionEntryMock(...args),
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -37,13 +37,14 @@ import {
|
||||
} from "./agent-command-restart-recovery.js";
|
||||
import { runAcpAgentCommand } from "./command/acp-execution.js";
|
||||
import { repairPendingAssistantTranscriptTurns } from "./command/assistant-transcript-repair.js";
|
||||
import { persistAgentSession } from "./command/attempt-execution.shared.js";
|
||||
import { emitIngressModelUsageDiagnostic } from "./command/ingress-diagnostics.js";
|
||||
import { resolveEmbeddedModelSelection } from "./command/model-selection.js";
|
||||
import { finalizeEmbeddedAgentCommand } from "./command/post-run.js";
|
||||
import { prepareAgentCommandExecution } from "./command/prepare.js";
|
||||
import { runEmbeddedAgentAttempt } from "./command/run-embedded-attempt.js";
|
||||
import { loadSessionStoreRuntime, resolveAgentCommandDeps } from "./command/runtime-loaders.js";
|
||||
import { persistSessionEntry, prepareCurrentRunDelivery } from "./command/session-helpers.js";
|
||||
import { prepareCurrentRunDelivery } from "./command/session-helpers.js";
|
||||
import { prepareEmbeddedSessionState } from "./command/session-preparation.js";
|
||||
import { clearRotatedSessionMetadata } from "./command/session.js";
|
||||
import type {
|
||||
@@ -354,7 +355,7 @@ async function agentCommandInternal(
|
||||
suppressTextDelivery: opts.internalDeliverySuppressText,
|
||||
}),
|
||||
};
|
||||
const persisted = await persistSessionEntry({
|
||||
const persisted = await persistAgentSession({
|
||||
sessionStore,
|
||||
sessionKey,
|
||||
storePath,
|
||||
@@ -566,7 +567,7 @@ async function agentCommandInternal(
|
||||
}),
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
const persisted = await persistSessionEntry({
|
||||
const persisted = await persistAgentSession({
|
||||
sessionStore,
|
||||
sessionKey,
|
||||
storePath,
|
||||
|
||||
@@ -15,14 +15,14 @@ import type { EmbeddedAgentRunResult } from "../embedded-agent.js";
|
||||
import type { loadManifestModelCatalog } from "../model-catalog.js";
|
||||
import type { persistCliTurnTranscript } from "./attempt-execution.js";
|
||||
import type { runAgentAttempt } from "./attempt-execution.runtime.js";
|
||||
import type { persistSessionEntry } from "./session-helpers.js";
|
||||
import type { persistAgentSession } from "./attempt-execution.shared.js";
|
||||
|
||||
type ProviderModelNormalizationParams = { provider: string; context: { modelId: string } };
|
||||
type LoadManifestModelCatalogParams = Parameters<typeof loadManifestModelCatalog>[0];
|
||||
type RunAgentAttempt = typeof runAgentAttempt;
|
||||
type PersistCliTurnTranscript = typeof persistCliTurnTranscript;
|
||||
type AppendExactAssistantMessage = typeof appendExactAssistantMessageToSessionTranscript;
|
||||
type PersistSessionEntry = typeof persistSessionEntry;
|
||||
type PersistSessionEntry = typeof persistAgentSession;
|
||||
type CliCompactionParams = {
|
||||
sessionEntry?: SessionEntry;
|
||||
sessionKey: string;
|
||||
@@ -205,13 +205,14 @@ vi.mock("../../config/sessions/transcript.runtime.js", async () => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("./session-helpers.js", async () => {
|
||||
const actual =
|
||||
await vi.importActual<typeof import("./session-helpers.js")>("./session-helpers.js");
|
||||
vi.mock("./attempt-execution.shared.js", async () => {
|
||||
const actual = await vi.importActual<typeof import("./attempt-execution.shared.js")>(
|
||||
"./attempt-execution.shared.js",
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
persistSessionEntry: (...args: Parameters<typeof actual.persistSessionEntry>) => {
|
||||
state.persistSessionEntryReal = actual.persistSessionEntry;
|
||||
persistAgentSession: (...args: Parameters<typeof actual.persistAgentSession>) => {
|
||||
state.persistSessionEntryReal = actual.persistAgentSession;
|
||||
return state.persistSessionEntryMock(...args);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -4,8 +4,8 @@ import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import { formatErrorMessage } from "../../infra/errors.js";
|
||||
import { createSubsystemLogger } from "../../logging/subsystem.js";
|
||||
import { runAgentHarnessBeforeMessageWriteHook } from "../harness/hook-helpers.js";
|
||||
import { persistAgentSession } from "./attempt-execution.shared.js";
|
||||
import { loadTranscriptAppendRuntime } from "./runtime-loaders.js";
|
||||
import { persistSessionEntry } from "./session-helpers.js";
|
||||
|
||||
const log = createSubsystemLogger("agents/assistant-transcript-repair");
|
||||
|
||||
@@ -58,7 +58,7 @@ export async function persistAssistantTranscriptRepairRecord(params: {
|
||||
createdAt: now,
|
||||
};
|
||||
try {
|
||||
await persistSessionEntry({
|
||||
await persistAgentSession({
|
||||
sessionStore: context.sessionStore,
|
||||
sessionKey: context.sessionKey,
|
||||
storePath: context.storePath,
|
||||
@@ -148,7 +148,7 @@ export async function repairPendingAssistantTranscriptTurns(params: {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await persistSessionEntry({
|
||||
await persistAgentSession({
|
||||
sessionStore: context.sessionStore,
|
||||
sessionKey: context.sessionKey,
|
||||
storePath: context.storePath,
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
INTERNAL_RUNTIME_CONTEXT_END,
|
||||
} from "../internal-runtime-context.js";
|
||||
import {
|
||||
persistSessionEntry,
|
||||
persistAgentSession,
|
||||
resolveAcpPromptBody,
|
||||
resolveInternalEventTranscriptBody,
|
||||
} from "./attempt-execution.shared.js";
|
||||
@@ -90,7 +90,7 @@ describe("attempt execution prompt materialization", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("persistSessionEntry", () => {
|
||||
describe("persistAgentSession", () => {
|
||||
const sessionKey = "agent:main:main";
|
||||
|
||||
it("clears stale local entries when guarded persistence sees no persisted entry", async () => {
|
||||
@@ -106,7 +106,7 @@ describe("persistSessionEntry", () => {
|
||||
|
||||
// A guarded write can decline persistence after rereading disk; local
|
||||
// memory must be cleared too so later turns do not reuse stale entries.
|
||||
const persisted = await persistSessionEntry({
|
||||
const persisted = await persistAgentSession({
|
||||
sessionStore,
|
||||
sessionKey,
|
||||
storePath,
|
||||
@@ -160,7 +160,7 @@ describe("persistSessionEntry", () => {
|
||||
await replaceSessionEntry({ sessionKey, storePath }, currentEntry);
|
||||
const sessionStore = { [sessionKey]: staleEntry };
|
||||
|
||||
const persisted = await persistSessionEntry({
|
||||
const persisted = await persistAgentSession({
|
||||
sessionStore,
|
||||
sessionKey,
|
||||
storePath,
|
||||
@@ -206,7 +206,7 @@ describe("persistSessionEntry", () => {
|
||||
await replaceSessionEntry({ sessionKey, storePath }, currentEntry);
|
||||
const sessionStore = { [sessionKey]: initialEntry };
|
||||
|
||||
const persisted = await persistSessionEntry({
|
||||
const persisted = await persistAgentSession({
|
||||
sessionStore,
|
||||
sessionKey,
|
||||
storePath,
|
||||
@@ -244,7 +244,7 @@ describe("persistSessionEntry", () => {
|
||||
};
|
||||
const sessionStore = { [sessionKey]: staleEntry };
|
||||
|
||||
const persisted = await persistSessionEntry({
|
||||
const persisted = await persistAgentSession({
|
||||
sessionStore,
|
||||
sessionKey,
|
||||
storePath,
|
||||
@@ -275,14 +275,14 @@ describe("persistSessionEntry", () => {
|
||||
};
|
||||
const sessionStore = { [sessionKey]: staleEntry };
|
||||
|
||||
const first = await persistSessionEntry({
|
||||
const first = await persistAgentSession({
|
||||
sessionStore,
|
||||
sessionKey,
|
||||
storePath,
|
||||
initialEntry: staleEntry,
|
||||
entry: staleEntry,
|
||||
});
|
||||
const second = await persistSessionEntry({
|
||||
const second = await persistAgentSession({
|
||||
sessionStore,
|
||||
sessionKey,
|
||||
storePath,
|
||||
@@ -314,7 +314,7 @@ describe("persistSessionEntry", () => {
|
||||
updatedAt: 1,
|
||||
};
|
||||
|
||||
const persisted = await persistSessionEntry({
|
||||
const persisted = await persistAgentSession({
|
||||
sessionStore,
|
||||
sessionKey,
|
||||
storePath,
|
||||
|
||||
@@ -26,7 +26,7 @@ type PersistSessionEntryParams = {
|
||||
};
|
||||
|
||||
/** Persists one session entry while keeping the caller's in-memory store aligned. */
|
||||
export async function persistSessionEntry(
|
||||
export async function persistAgentSession(
|
||||
params: PersistSessionEntryParams,
|
||||
): Promise<SessionEntry | undefined> {
|
||||
let rejectedMissingEntry = false;
|
||||
|
||||
@@ -59,6 +59,7 @@ import {
|
||||
normalizeThinkingCatalogProviders,
|
||||
resolveEffectiveAgentRuntime,
|
||||
} from "../thinking-runtime.js";
|
||||
import { persistAgentSession } from "./attempt-execution.shared.js";
|
||||
import {
|
||||
normalizeAgentCommandDefaultModelRef,
|
||||
normalizeAgentCommandModelRef,
|
||||
@@ -67,7 +68,6 @@ import {
|
||||
import { normalizeExplicitOverrideInput } from "./prepare.js";
|
||||
import type { resolveAgentRunContext } from "./run-context.js";
|
||||
import { loadTranscriptResolveRuntime } from "./runtime-loaders.js";
|
||||
import { persistSessionEntry } from "./session-helpers.js";
|
||||
import type { AgentCommandOpts } from "./types.js";
|
||||
|
||||
type AgentRunContext = ReturnType<typeof resolveAgentRunContext>;
|
||||
@@ -219,7 +219,7 @@ export async function resolveEmbeddedModelSelection(params: {
|
||||
}
|
||||
}
|
||||
if (entryUpdated) {
|
||||
sessionEntry = await persistSessionEntry({
|
||||
sessionEntry = await persistAgentSession({
|
||||
sessionStore: params.sessionStore,
|
||||
sessionKey: params.sessionKey,
|
||||
storePath: params.storePath,
|
||||
@@ -596,7 +596,7 @@ export async function resolveEmbeddedModelSelection(params: {
|
||||
thinkingLevel: params.thinkOverride,
|
||||
};
|
||||
sessionEntry =
|
||||
(await persistSessionEntry({
|
||||
(await persistAgentSession({
|
||||
sessionStore: params.sessionStore,
|
||||
sessionKey: params.sessionKey,
|
||||
storePath: params.storePath,
|
||||
|
||||
@@ -19,6 +19,7 @@ import { persistPendingFinalDeliveryMarker } from "../pending-final-delivery-mar
|
||||
import type { AgentRunSessionTarget } from "../run-session-target.js";
|
||||
import { throwAgentRunRestartAbortReason } from "../run-termination.js";
|
||||
import { persistAssistantTranscriptRepairRecord } from "./assistant-transcript-repair.js";
|
||||
import { persistAgentSession } from "./attempt-execution.shared.js";
|
||||
import type { PreparedAgentCommandExecution } from "./prepare.js";
|
||||
import type { EmbeddedAgentAttempt } from "./run-embedded-attempt.js";
|
||||
import {
|
||||
@@ -26,7 +27,7 @@ import {
|
||||
loadDeliveryRuntime,
|
||||
loadSessionStoreRuntime,
|
||||
} from "./runtime-loaders.js";
|
||||
import { clearPendingFinalDelivery, persistSessionEntry } from "./session-helpers.js";
|
||||
import { clearPendingFinalDelivery } from "./session-helpers.js";
|
||||
import type { EmbeddedSessionState } from "./session-preparation.js";
|
||||
import type { AgentCommandOpts } from "./types.js";
|
||||
|
||||
@@ -383,7 +384,7 @@ export async function finalizeEmbeddedAgentCommand(params: {
|
||||
!pendingFinalDeliveryMarker.hasSendableFinalPayload &&
|
||||
entry.pendingFinalDelivery?.kind === "transport-only";
|
||||
if (deliveryResult?.deliverySucceeded === true || clearStaleTransportOnly) {
|
||||
sessionEntry = await persistSessionEntry({
|
||||
sessionEntry = await persistAgentSession({
|
||||
sessionStore,
|
||||
sessionKey,
|
||||
storePath,
|
||||
|
||||
@@ -51,12 +51,13 @@ import {
|
||||
createAgentAttemptLifecycleCallbacks,
|
||||
type AgentAttemptLifecycleState,
|
||||
} from "./attempt-callbacks.js";
|
||||
import { persistAgentSession } from "./attempt-execution.shared.js";
|
||||
import { createAgentCommandLifecycle } from "./lifecycle.js";
|
||||
import { normalizeAgentCommandModelRef } from "./model-ref.js";
|
||||
import type { EmbeddedModelSelection } from "./model-selection.js";
|
||||
import type { PreparedAgentCommandExecution } from "./prepare.js";
|
||||
import { loadAttemptExecutionRuntime, type AgentAttemptResult } from "./runtime-loaders.js";
|
||||
import { persistSessionEntry, resolveInternalSessionEffectsSource } from "./session-helpers.js";
|
||||
import { resolveInternalSessionEffectsSource } from "./session-helpers.js";
|
||||
import type { EmbeddedSessionState } from "./session-preparation.js";
|
||||
import type { AgentCommandOpts } from "./types.js";
|
||||
|
||||
@@ -313,7 +314,7 @@ export async function runEmbeddedAgentAttempt(params: {
|
||||
}
|
||||
const nextSessionEntry = { ...sessionEntry };
|
||||
clearAutoFallbackPrimaryProbeSelection(nextSessionEntry);
|
||||
sessionEntry = await persistSessionEntry({
|
||||
sessionEntry = await persistAgentSession({
|
||||
sessionStore,
|
||||
sessionKey,
|
||||
storePath,
|
||||
|
||||
@@ -19,25 +19,8 @@ import {
|
||||
isDeliverableMessageChannel,
|
||||
} from "../../utils/message-channel.js";
|
||||
import type { AgentRunSessionTarget } from "../run-session-target.js";
|
||||
import { persistSessionEntry as persistSessionEntryBase } from "./attempt-execution.shared.js";
|
||||
import type { AgentCommandOpts } from "./types.js";
|
||||
|
||||
type PersistSessionEntryParams = {
|
||||
sessionStore: Record<string, SessionEntry>;
|
||||
sessionKey: string;
|
||||
storePath: string;
|
||||
initialEntry: SessionEntry;
|
||||
entry: SessionEntry;
|
||||
};
|
||||
|
||||
export async function persistSessionEntry(
|
||||
params: PersistSessionEntryParams & {
|
||||
shouldPersist?: (entry: SessionEntry | undefined) => boolean;
|
||||
},
|
||||
): Promise<SessionEntry | undefined> {
|
||||
return await persistSessionEntryBase(params);
|
||||
}
|
||||
|
||||
export function clearPendingFinalDelivery(entry: SessionEntry, updatedAt: number): SessionEntry {
|
||||
return {
|
||||
...entry,
|
||||
|
||||
@@ -6,9 +6,9 @@ import { registerAgentRunContext } from "../../infra/agent-run-registry.js";
|
||||
import { applyVerboseOverride } from "../../sessions/level-overrides.js";
|
||||
import { recordSessionHumanDirectMessage } from "../../sessions/session-state-events.js";
|
||||
import { resolveEffectiveAgentSkillFilter } from "../../skills/discovery/agent-filter.js";
|
||||
import { persistAgentSession } from "./attempt-execution.shared.js";
|
||||
import { resolveAgentRunContext } from "./run-context.js";
|
||||
import { loadExecDefaultsRuntime, loadSkillsRuntime } from "./runtime-loaders.js";
|
||||
import { persistSessionEntry } from "./session-helpers.js";
|
||||
import type { AgentCommandOpts } from "./types.js";
|
||||
|
||||
export async function prepareEmbeddedSessionState(params: {
|
||||
@@ -100,7 +100,7 @@ export async function prepareEmbeddedSessionState(params: {
|
||||
sessionStartedAt: current.sessionStartedAt ?? now,
|
||||
skillsSnapshot,
|
||||
};
|
||||
sessionEntry = await persistSessionEntry({
|
||||
sessionEntry = await persistAgentSession({
|
||||
sessionStore: params.sessionStore,
|
||||
sessionKey: params.sessionKey,
|
||||
storePath: params.storePath,
|
||||
@@ -131,7 +131,7 @@ export async function prepareEmbeddedSessionState(params: {
|
||||
agentStatus: undefined,
|
||||
};
|
||||
applyVerboseOverride(next, params.verboseOverride);
|
||||
sessionEntry = await persistSessionEntry({
|
||||
sessionEntry = await persistAgentSession({
|
||||
sessionStore: params.sessionStore,
|
||||
sessionKey: params.sessionKey,
|
||||
storePath: params.storePath,
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
import type { SessionEntry } from "../config/sessions/types.js";
|
||||
import { isSubagentSessionKey } from "../routing/session-key.js";
|
||||
import type { DeliveryContext } from "../utils/delivery-context.shared.js";
|
||||
import { persistSessionEntry } from "./command/attempt-execution.shared.js";
|
||||
import { persistAgentSession } from "./command/attempt-execution.shared.js";
|
||||
|
||||
type PersistPendingFinalDeliveryMarkerParams = {
|
||||
deliver: boolean;
|
||||
@@ -65,7 +65,7 @@ export async function persistPendingFinalDeliveryMarker(
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
const persisted = await persistSessionEntry({
|
||||
const persisted = await persistAgentSession({
|
||||
sessionStore: params.sessionStore,
|
||||
sessionKey: params.sessionKey,
|
||||
storePath: params.storePath,
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import { resolveTextCommand } from "../commands-registry.js";
|
||||
import { resolveCommandSurfaceChannel } from "./channel-context.js";
|
||||
import { commandReply, defineAuthorizedTextCommand } from "./command-gates.js";
|
||||
import { persistSessionEntry } from "./commands-session-store.js";
|
||||
import { persistCommandSession } from "./commands-session-store.js";
|
||||
import type { CommandHandler, HandleCommandsParams } from "./commands-types.js";
|
||||
|
||||
const DOCK_KEY_PREFIX = "dock:";
|
||||
@@ -165,7 +165,7 @@ export const handleDockCommand: CommandHandler = defineAuthorizedTextCommand(
|
||||
origin: sessionDeliveryOrigin(sessionEntry),
|
||||
});
|
||||
params.sessionEntry = sessionEntry;
|
||||
const persisted = await persistSessionEntry({
|
||||
const persisted = await persistCommandSession({
|
||||
...params,
|
||||
touchedFields: ["delivery"],
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ import path from "node:path";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { loadSessionEntry, replaceSessionEntry } from "../../config/sessions/session-accessor.js";
|
||||
import type { SessionEntry } from "../../config/sessions/types.js";
|
||||
import { persistAbortTargetEntry, persistSessionEntry } from "./commands-session-store.js";
|
||||
import { persistAbortTargetEntry, persistCommandSession } from "./commands-session-store.js";
|
||||
|
||||
async function withTempStore<T>(run: (storePath: string) => Promise<T>): Promise<T> {
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-command-session-store-"));
|
||||
@@ -27,7 +27,7 @@ describe("commands session store persistence", () => {
|
||||
const sessionStore: Record<string, SessionEntry> = { [sessionKey]: entry };
|
||||
|
||||
await expect(
|
||||
persistSessionEntry({
|
||||
persistCommandSession({
|
||||
allowCreateSessionEntry: true,
|
||||
sessionEntry: entry,
|
||||
sessionStore,
|
||||
@@ -60,7 +60,7 @@ describe("commands session store persistence", () => {
|
||||
const sessionStore: Record<string, SessionEntry> = { [sessionKey]: entry };
|
||||
|
||||
await expect(
|
||||
persistSessionEntry({
|
||||
persistCommandSession({
|
||||
sessionEntry: entry,
|
||||
sessionStore,
|
||||
sessionKey,
|
||||
@@ -88,7 +88,7 @@ describe("commands session store persistence", () => {
|
||||
delivery: { kind: "none" },
|
||||
};
|
||||
const seedEntry = { ...entry };
|
||||
await persistSessionEntry({
|
||||
await persistCommandSession({
|
||||
allowCreateSessionEntry: true,
|
||||
sessionEntry: seedEntry,
|
||||
sessionStore: { [sessionKey]: seedEntry },
|
||||
@@ -99,7 +99,7 @@ describe("commands session store persistence", () => {
|
||||
const sessionStore: Record<string, SessionEntry> = { [sessionKey]: entry };
|
||||
|
||||
await expect(
|
||||
persistSessionEntry({
|
||||
persistCommandSession({
|
||||
sessionEntry: entry,
|
||||
sessionStore,
|
||||
sessionKey,
|
||||
@@ -147,7 +147,7 @@ describe("commands session store persistence", () => {
|
||||
label: "After rename",
|
||||
pinnedAt: undefined,
|
||||
};
|
||||
await persistSessionEntry({
|
||||
await persistCommandSession({
|
||||
allowCreateSessionEntry: true,
|
||||
sessionEntry: concurrentEntry,
|
||||
sessionStore: { [sessionKey]: concurrentEntry },
|
||||
@@ -160,7 +160,7 @@ describe("commands session store persistence", () => {
|
||||
|
||||
try {
|
||||
await expect(
|
||||
persistSessionEntry({
|
||||
persistCommandSession({
|
||||
sessionEntry: entry,
|
||||
sessionStore,
|
||||
sessionKey,
|
||||
@@ -214,7 +214,7 @@ describe("commands session store persistence", () => {
|
||||
const sessionStore = { [sessionKey]: sessionEntry };
|
||||
|
||||
await expect(
|
||||
persistSessionEntry({
|
||||
persistCommandSession({
|
||||
initialSessionEntry: initialEntry,
|
||||
sessionEntry,
|
||||
sessionStore,
|
||||
@@ -246,7 +246,7 @@ describe("commands session store persistence", () => {
|
||||
const sessionStore = { [sessionKey]: sessionEntry };
|
||||
|
||||
await expect(
|
||||
persistSessionEntry({
|
||||
persistCommandSession({
|
||||
initialSessionEntry: initialEntry,
|
||||
sessionEntry,
|
||||
sessionStore,
|
||||
@@ -286,7 +286,7 @@ describe("commands session store persistence", () => {
|
||||
const sessionStore = { [sessionKey]: sessionEntry };
|
||||
|
||||
await expect(
|
||||
persistSessionEntry({
|
||||
persistCommandSession({
|
||||
initialSessionEntry: initialEntry,
|
||||
sessionEntry,
|
||||
sessionStore,
|
||||
|
||||
@@ -35,7 +35,7 @@ export function resolveCommandSessionEntryForKey(
|
||||
};
|
||||
}
|
||||
|
||||
export async function persistSessionEntry(params: PersistSessionEntryParams): Promise<boolean> {
|
||||
export async function persistCommandSession(params: PersistSessionEntryParams): Promise<boolean> {
|
||||
if (!params.sessionEntry || !params.sessionStore || !params.sessionKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ const persistenceConflictReply = vi.hoisted(() => ({
|
||||
}));
|
||||
|
||||
vi.mock("./commands-session-store.js", () => ({
|
||||
persistSessionEntry: persistSessionEntryMock,
|
||||
persistCommandSession: persistSessionEntryMock,
|
||||
sessionEntryPersistenceConflictReply: () => persistenceConflictReply,
|
||||
}));
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ import {
|
||||
} from "./command-gates.js";
|
||||
import { handleAbortTrigger, handleStopCommand } from "./commands-session-abort.js";
|
||||
import {
|
||||
persistSessionEntry,
|
||||
persistCommandSession,
|
||||
sessionEntryPersistenceConflictReply,
|
||||
} from "./commands-session-store.js";
|
||||
import type { CommandHandler, HandleCommandsParams } from "./commands-types.js";
|
||||
@@ -237,7 +237,7 @@ export const handleActivationCommand: CommandHandler = async (params, allowTextC
|
||||
params.sessionEntry.groupActivation = activationCommand.mode;
|
||||
params.sessionEntry.groupActivationNeedsSystemIntro = true;
|
||||
if (
|
||||
!(await persistSessionEntry({
|
||||
!(await persistCommandSession({
|
||||
...params,
|
||||
touchedFields: ["groupActivation", "groupActivationNeedsSystemIntro"],
|
||||
}))
|
||||
@@ -267,7 +267,7 @@ export const handleSendPolicyCommand: CommandHandler = defineAuthorizedTextComma
|
||||
} else {
|
||||
params.sessionEntry.sendPolicy = sendPolicyCommand.mode;
|
||||
}
|
||||
if (!(await persistSessionEntry({ ...params, touchedFields: ["sendPolicy"] }))) {
|
||||
if (!(await persistCommandSession({ ...params, touchedFields: ["sendPolicy"] }))) {
|
||||
return sessionEntryPersistenceConflictReply();
|
||||
}
|
||||
}
|
||||
@@ -366,7 +366,7 @@ export const handleUsageCommand: CommandHandler = defineAuthorizedTextCommand(
|
||||
delete targetSessionEntry.responseUsage;
|
||||
params.sessionStore[params.sessionKey] = targetSessionEntry;
|
||||
if (
|
||||
!(await persistSessionEntry({
|
||||
!(await persistCommandSession({
|
||||
...params,
|
||||
sessionEntry: targetSessionEntry,
|
||||
touchedFields: ["responseUsage"],
|
||||
@@ -392,7 +392,7 @@ export const handleUsageCommand: CommandHandler = defineAuthorizedTextCommand(
|
||||
targetSessionEntry.responseUsage = next;
|
||||
params.sessionStore[params.sessionKey] = targetSessionEntry;
|
||||
if (
|
||||
!(await persistSessionEntry({
|
||||
!(await persistCommandSession({
|
||||
...params,
|
||||
sessionEntry: targetSessionEntry,
|
||||
touchedFields: ["responseUsage"],
|
||||
@@ -440,7 +440,7 @@ export const handleFastCommand: CommandHandler = defineAuthorizedTextCommand(
|
||||
if (targetSessionEntry && params.sessionStore && params.sessionKey) {
|
||||
delete targetSessionEntry.fastMode;
|
||||
if (
|
||||
!(await persistSessionEntry({
|
||||
!(await persistCommandSession({
|
||||
...params,
|
||||
sessionEntry: targetSessionEntry,
|
||||
touchedFields: ["fastMode"],
|
||||
@@ -457,7 +457,7 @@ export const handleFastCommand: CommandHandler = defineAuthorizedTextCommand(
|
||||
if (targetSessionEntry && params.sessionStore && params.sessionKey) {
|
||||
targetSessionEntry.fastMode = nextMode;
|
||||
if (
|
||||
!(await persistSessionEntry({
|
||||
!(await persistCommandSession({
|
||||
...params,
|
||||
sessionEntry: targetSessionEntry,
|
||||
touchedFields: ["fastMode"],
|
||||
|
||||
@@ -43,7 +43,7 @@ import {
|
||||
matchCommandPrefix,
|
||||
} from "./command-gates.js";
|
||||
import {
|
||||
persistSessionEntry,
|
||||
persistCommandSession,
|
||||
sessionEntryPersistenceConflictReply,
|
||||
} from "./commands-session-store.js";
|
||||
import type { CommandHandler, CommandHandlerResult } from "./commands-types.js";
|
||||
@@ -205,7 +205,7 @@ async function handleTtsChatAction(
|
||||
return { shouldContinue: false, reply: ttsUsage() };
|
||||
}
|
||||
|
||||
if (!(await persistSessionEntry({ ...params, touchedFields: ["ttsAuto"] }))) {
|
||||
if (!(await persistCommandSession({ ...params, touchedFields: ["ttsAuto"] }))) {
|
||||
return sessionEntryPersistenceConflictReply();
|
||||
}
|
||||
return stopWithText(replyText);
|
||||
@@ -257,7 +257,7 @@ async function handleTtsLatestAction(
|
||||
params.sessionEntry.lastTtsReadLatestHash = hash;
|
||||
params.sessionEntry.lastTtsReadLatestAt = Date.now();
|
||||
if (
|
||||
!(await persistSessionEntry({
|
||||
!(await persistCommandSession({
|
||||
...params,
|
||||
touchedFields: ["lastTtsReadLatestHash", "lastTtsReadLatestAt"],
|
||||
}))
|
||||
|
||||
@@ -11,17 +11,6 @@ export function cloneRecord<T extends JsonRecord>(value: T | undefined): T {
|
||||
return { ...value } as T;
|
||||
}
|
||||
|
||||
/** Ensure a nested config value is a mutable record and return it. */
|
||||
export function ensureRecord(target: JsonRecord, key: string): JsonRecord {
|
||||
const current = target[key];
|
||||
if (isRecord(current)) {
|
||||
return current;
|
||||
}
|
||||
const next: JsonRecord = {};
|
||||
target[key] = next;
|
||||
return next;
|
||||
}
|
||||
|
||||
/** Own-property guard used by migrations that must preserve falsy values. */
|
||||
export function hasOwnKey(target: JsonRecord, key: string): boolean {
|
||||
return Object.hasOwn(target, key);
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Legacy web tool config migrations into plugin-owned provider config.
|
||||
import { mergeMissing } from "../../../config/legacy.shared.js";
|
||||
import { ensureRecord, mergeMissing } from "../../../config/legacy.shared.js";
|
||||
import {
|
||||
cloneRecord,
|
||||
ensureRecord,
|
||||
hasOwnKey,
|
||||
isRecord,
|
||||
type JsonRecord,
|
||||
|
||||
@@ -11,7 +11,7 @@ import type {
|
||||
SessionTranscriptReadScope,
|
||||
TranscriptEvent,
|
||||
} from "./session-accessor.sqlite-contract.js";
|
||||
import { normalizeSqliteNumber } from "./session-accessor.sqlite-normalize.js";
|
||||
import { coerceSqliteNumber } from "./session-accessor.sqlite-normalize.js";
|
||||
import {
|
||||
getSessionKysely,
|
||||
resolveSqliteTranscriptReadScope,
|
||||
@@ -183,7 +183,7 @@ function readRawDeltaInTransaction(
|
||||
.limit(1),
|
||||
);
|
||||
const maxSeq = Math.min(
|
||||
frontier ? normalizeSqliteNumber(frontier.seq) : -1,
|
||||
frontier ? coerceSqliteNumber(frontier.seq) : -1,
|
||||
beforeEventSeq === undefined ? Number.POSITIVE_INFINITY : beforeEventSeq - 1,
|
||||
);
|
||||
if (cursor.lastSeq > maxSeq) {
|
||||
@@ -210,8 +210,8 @@ function readRawDeltaInTransaction(
|
||||
.orderBy("seq", "asc")
|
||||
.limit(maxEvents + 1),
|
||||
).rows.map((row) => ({
|
||||
seq: normalizeSqliteNumber(row.seq),
|
||||
serializedBytes: normalizeSqliteNumber(row.serialized_bytes),
|
||||
seq: coerceSqliteNumber(row.seq),
|
||||
serializedBytes: coerceSqliteNumber(row.serialized_bytes),
|
||||
}));
|
||||
|
||||
let serializedBytes = 0;
|
||||
@@ -239,7 +239,7 @@ function readRawDeltaInTransaction(
|
||||
.orderBy("seq", "asc"),
|
||||
).rows.map((row) => ({
|
||||
event: JSON.parse(row.event_json) as TranscriptEvent,
|
||||
seq: normalizeSqliteNumber(row.seq),
|
||||
seq: coerceSqliteNumber(row.seq),
|
||||
}));
|
||||
const nextCursor = encodeRawTranscriptCursor({ ...cursor, lastSeq });
|
||||
const requiredBytes =
|
||||
|
||||
@@ -51,7 +51,7 @@ import {
|
||||
} from "./session-accessor.sqlite-maintenance.js";
|
||||
import {
|
||||
createFallbackSessionEntry,
|
||||
normalizeSqliteNumber,
|
||||
coerceSqliteNumber,
|
||||
} from "./session-accessor.sqlite-normalize.js";
|
||||
import {
|
||||
cloneSessionEntry,
|
||||
@@ -297,7 +297,7 @@ export function countSqliteSessionEntryRowsReadOnly(scope: SessionEntryListScope
|
||||
.selectFrom("session_nodes")
|
||||
.select((expression) => expression.fn.countAll<number | bigint>().as("count")),
|
||||
);
|
||||
return row ? normalizeSqliteNumber(row.count) : 0;
|
||||
return row ? coerceSqliteNumber(row.count) : 0;
|
||||
}, toDatabaseOptions(resolved));
|
||||
return result.found ? result.value : 0;
|
||||
}
|
||||
@@ -411,7 +411,7 @@ export function readSqliteSessionUpdatedAt(scope: SessionAccessScope): number |
|
||||
const resolved = resolveSqliteScope(scope);
|
||||
const database = openOpenClawAgentDatabase(toDatabaseOptions(resolved));
|
||||
const row = readSessionEntryRow(database, resolved.sessionKey)?.row;
|
||||
return row ? normalizeSqliteNumber(row.updated_at) : undefined;
|
||||
return row ? coerceSqliteNumber(row.updated_at) : undefined;
|
||||
}
|
||||
|
||||
/** Applies a partial entry update to the additive SQLite session store. */
|
||||
|
||||
@@ -31,7 +31,7 @@ import type {
|
||||
SqliteProjectedLifecycleMutation,
|
||||
SqliteSessionEntryRemovalPlan,
|
||||
} from "./session-accessor.sqlite-lifecycle-types.js";
|
||||
import { normalizeSqliteNumber } from "./session-accessor.sqlite-normalize.js";
|
||||
import { coerceSqliteNumber } from "./session-accessor.sqlite-normalize.js";
|
||||
import { loadSqliteTranscriptEventsFromDatabase } from "./session-accessor.sqlite-read.js";
|
||||
import { collectSqliteSessionStateIdsForEntry } from "./session-accessor.sqlite-references.js";
|
||||
import { cloneSessionEntry, getSessionKysely } from "./session-accessor.sqlite-scope.js";
|
||||
@@ -103,7 +103,7 @@ function readSessionTranscriptUpdatedAt(
|
||||
if (row?.updated_at === null || row?.updated_at === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return normalizeSqliteNumber(row.updated_at);
|
||||
return coerceSqliteNumber(row.updated_at);
|
||||
}
|
||||
|
||||
function sqliteTranscriptStateIsReclaimable(params: {
|
||||
@@ -611,7 +611,7 @@ export function planSqliteSessionLifecycleArtifactCleanup(
|
||||
!sqliteTranscriptStateIsReclaimable({
|
||||
database,
|
||||
// Admission updates the node even when a run has no event yet or reuses old events.
|
||||
sessionUpdatedAt: normalizeSqliteNumber(row.updated_at),
|
||||
sessionUpdatedAt: coerceSqliteNumber(row.updated_at),
|
||||
sessionId: row.current_session_id,
|
||||
nowMs: params.nowMs,
|
||||
orphanTranscriptMinAgeMs: params.orphanTranscriptMinAgeMs,
|
||||
|
||||
@@ -21,6 +21,6 @@ export function normalizeSqliteChatType(value: unknown): "direct" | "group" | "c
|
||||
return null;
|
||||
}
|
||||
|
||||
export function normalizeSqliteNumber(value: number | bigint): number {
|
||||
export function coerceSqliteNumber(value: number | bigint): number {
|
||||
return typeof value === "bigint" ? Number(value) : value;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import type {
|
||||
SessionTranscriptStats,
|
||||
TranscriptEvent,
|
||||
} from "./session-accessor.sqlite-contract.js";
|
||||
import { normalizeSqliteNumber } from "./session-accessor.sqlite-normalize.js";
|
||||
import { coerceSqliteNumber } from "./session-accessor.sqlite-normalize.js";
|
||||
import {
|
||||
getSessionKysely,
|
||||
resolveSqliteTranscriptReadScope,
|
||||
@@ -127,7 +127,7 @@ export function loadSqliteTranscriptEventRowsAfterSeqSync(
|
||||
}
|
||||
return executeSqliteQuerySync(database.db, query.orderBy("seq", "asc")).rows.map((row) => ({
|
||||
event: JSON.parse(row.event_json) as TranscriptEvent,
|
||||
seq: normalizeSqliteNumber(row.seq),
|
||||
seq: coerceSqliteNumber(row.seq),
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ export function readSqliteTranscriptEventAtSeqSync(
|
||||
return row
|
||||
? {
|
||||
event: JSON.parse(row.event_json) as TranscriptEvent,
|
||||
seq: normalizeSqliteNumber(row.seq),
|
||||
seq: coerceSqliteNumber(row.seq),
|
||||
}
|
||||
: undefined;
|
||||
}
|
||||
@@ -200,7 +200,7 @@ export function readSqliteTranscriptEventRows(
|
||||
).rows;
|
||||
return rows.map((row) => ({
|
||||
eventJson: row.event_json,
|
||||
seq: normalizeSqliteNumber(row.seq),
|
||||
seq: coerceSqliteNumber(row.seq),
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -219,9 +219,9 @@ export function readSqliteTranscriptStorageRows(
|
||||
.orderBy("seq", "asc"),
|
||||
).rows;
|
||||
return rows.map((row) => ({
|
||||
createdAt: normalizeSqliteNumber(row.created_at),
|
||||
createdAt: coerceSqliteNumber(row.created_at),
|
||||
eventJson: row.event_json,
|
||||
seq: normalizeSqliteNumber(row.seq),
|
||||
seq: coerceSqliteNumber(row.seq),
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from "../../infra/kysely-sync.js";
|
||||
import type { OpenClawAgentDatabase } from "../../state/openclaw-agent-db.js";
|
||||
import { publishSqliteSessionEntryCacheInvalidation } from "./session-accessor.sqlite-entry-cache.js";
|
||||
import { normalizeSqliteNumber } from "./session-accessor.sqlite-normalize.js";
|
||||
import { coerceSqliteNumber } from "./session-accessor.sqlite-normalize.js";
|
||||
import { getSessionKysely, type ResolvedTranscriptScope } from "./session-accessor.sqlite-scope.js";
|
||||
import { parseSqliteSessionEntryJson } from "./session-accessor.sqlite-status.js";
|
||||
import {
|
||||
@@ -203,7 +203,7 @@ export function readNextTranscriptSeq(database: OpenClawAgentDatabase, sessionId
|
||||
.where("session_id", "=", sessionId),
|
||||
);
|
||||
const maxSeq =
|
||||
row?.max_seq === null || row?.max_seq === undefined ? -1 : normalizeSqliteNumber(row.max_seq);
|
||||
row?.max_seq === null || row?.max_seq === undefined ? -1 : coerceSqliteNumber(row.max_seq);
|
||||
return maxSeq + 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user