fix: satisfy rebased CI guardrails

This commit is contained in:
Peter Steinberger
2026-05-08 23:40:52 +01:00
parent 09aeef894c
commit 9876a921c1
33 changed files with 417 additions and 237 deletions

View File

@@ -1,6 +1,6 @@
import { resetPluginStateStoreForTests } from "openclaw/plugin-sdk/plugin-state-runtime";
import { withOpenClawTestState } from "openclaw/plugin-sdk/test-env";
import { afterEach, describe, expect, it } from "vitest";
import { withOpenClawTestState } from "../../../src/test-utils/openclaw-test-state.js";
import { createAcpxProcessLeaseStore, type AcpxProcessLease } from "./process-lease.js";
function makeLease(index: number): AcpxProcessLease {

View File

@@ -6,10 +6,12 @@ import {
type EmbeddedRunAttemptParams,
} from "openclaw/plugin-sdk/agent-harness";
import { AUTH_PROFILE_RUNTIME_CONTRACT } from "openclaw/plugin-sdk/agent-runtime-test-contracts";
import { createSqliteSessionTranscriptLocator } from "openclaw/plugin-sdk/session-store-runtime";
import {
closeOpenClawAgentDatabasesForTest,
closeOpenClawStateDatabaseForTest,
createSqliteSessionTranscriptLocator,
} from "openclaw/plugin-sdk/session-store-runtime";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { closeOpenClawAgentDatabasesForTest } from "../../../../src/state/openclaw-agent-db.js";
import { closeOpenClawStateDatabaseForTest } from "../../../../src/state/openclaw-state-db.js";
import { runCodexAppServerAttempt, __testing } from "./run-attempt.js";
import { readCodexAppServerBinding, writeCodexAppServerBinding } from "./session-binding.js";
import { createCodexTestModel } from "./test-support.js";

View File

@@ -9,10 +9,12 @@ import {
SessionManager,
type HarnessContextEngine as ContextEngine,
} from "openclaw/plugin-sdk/agent-harness-runtime";
import {
closeOpenClawAgentDatabasesForTest,
closeOpenClawStateDatabaseForTest,
replaceSqliteSessionTranscriptEvents,
} from "openclaw/plugin-sdk/session-store-runtime";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { replaceSqliteSessionTranscriptEvents } from "../../../../src/config/sessions/transcript-store.sqlite.js";
import { closeOpenClawAgentDatabasesForTest } from "../../../../src/state/openclaw-agent-db.js";
import { closeOpenClawStateDatabaseForTest } from "../../../../src/state/openclaw-state-db.js";
import type { CodexServerNotification } from "./protocol.js";
import { runCodexAppServerAttempt, __testing } from "./run-attempt.js";
import { createCodexTestModel } from "./test-support.js";

View File

@@ -16,6 +16,7 @@ import {
resetGlobalHookRunner,
} from "openclaw/plugin-sdk/hook-runtime";
import { createMockPluginRegistry } from "openclaw/plugin-sdk/plugin-test-runtime";
import { replaceSqliteSessionTranscriptEvents } from "openclaw/plugin-sdk/session-store-runtime";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
function queueActiveRunMessageForTest(
@@ -23,7 +24,7 @@ function queueActiveRunMessageForTest(
): boolean {
return queueAgentHarnessMessage(...args);
}
import { replaceSqliteSessionTranscriptEvents } from "../../../../src/config/sessions/transcript-store.sqlite.js";
import { CODEX_GPT5_BEHAVIOR_CONTRACT } from "../../prompt-overlay.js";
import {
buildCodexAppInventoryCacheKey,

View File

@@ -1,10 +1,12 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { listTrajectoryRuntimeEvents } from "openclaw/plugin-sdk/agent-harness-runtime";
import {
closeOpenClawAgentDatabasesForTest,
closeOpenClawStateDatabaseForTest,
} from "openclaw/plugin-sdk/session-store-runtime";
import { afterEach, describe, expect, it } from "vitest";
import { closeOpenClawAgentDatabasesForTest } from "../../../../src/state/openclaw-agent-db.js";
import { closeOpenClawStateDatabaseForTest } from "../../../../src/state/openclaw-state-db.js";
import { listTrajectoryRuntimeEvents } from "../../../../src/trajectory/runtime-store.sqlite.js";
import { createCodexTrajectoryRecorder } from "./trajectory.js";
type CodexTrajectoryRecorder = NonNullable<ReturnType<typeof createCodexTrajectoryRecorder>>;

View File

@@ -8,17 +8,17 @@ import {
resetGlobalHookRunner,
} from "openclaw/plugin-sdk/hook-runtime";
import { createMockPluginRegistry } from "openclaw/plugin-sdk/plugin-test-runtime";
import {
closeOpenClawStateDatabaseForTest,
loadSqliteSessionTranscriptEvents,
replaceSqliteSessionTranscriptEvents,
} from "openclaw/plugin-sdk/session-store-runtime";
import {
castAgentMessage,
makeAgentAssistantMessage,
makeAgentUserMessage,
} from "openclaw/plugin-sdk/test-fixtures";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
loadSqliteSessionTranscriptEvents,
replaceSqliteSessionTranscriptEvents,
} from "../../../../src/config/sessions/transcript-store.sqlite.js";
import { closeOpenClawStateDatabaseForTest } from "../../../../src/state/openclaw-state-db.js";
import { attachCodexMirrorIdentity, mirrorCodexAppServerTranscript } from "./transcript-mirror.js";
type MirroredAgentMessage = Extract<AgentMessage, { role: "user" | "assistant" | "toolResult" }>;

View File

@@ -6,10 +6,12 @@ import {
createEmptyPluginRegistry,
setActivePluginRegistry,
} from "openclaw/plugin-sdk/plugin-test-runtime";
import { upsertSessionEntry } from "openclaw/plugin-sdk/session-store-runtime";
import {
closeOpenClawAgentDatabasesForTest,
closeOpenClawStateDatabaseForTest,
upsertSessionEntry,
} from "openclaw/plugin-sdk/session-store-runtime";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { closeOpenClawAgentDatabasesForTest } from "../../../../src/state/openclaw-agent-db.js";
import { closeOpenClawStateDatabaseForTest } from "../../../../src/state/openclaw-state-db.js";
import { ChannelType, type AutocompleteInteraction } from "../internal/discord.js";
import { createNoopThreadBindingManager } from "./thread-bindings.js";

View File

@@ -89,7 +89,7 @@ describe("Matrix IndexedDB persistence", () => {
it("returns false and logs a warning for malformed snapshots", async () => {
const snapshot = snapshotPath("bad-snapshot.json");
const store = createPluginBlobStore<Record<string, unknown>>("matrix", {
const store = createPluginBlobStore("matrix", {
namespace: MATRIX_IDB_SNAPSHOT_NAMESPACE,
maxEntries: 1_000,
});
@@ -110,7 +110,7 @@ describe("Matrix IndexedDB persistence", () => {
it("returns false for empty snapshot payloads without restoring databases", async () => {
const snapshot = snapshotPath("empty-snapshot.json");
const store = createPluginBlobStore<Record<string, unknown>>("matrix", {
const store = createPluginBlobStore("matrix", {
namespace: MATRIX_IDB_SNAPSHOT_NAMESPACE,
maxEntries: 1_000,
});

View File

@@ -7,14 +7,14 @@ import {
listRegisteredMemoryEmbeddingProviderAdapters as listRegisteredAdapters,
registerMemoryEmbeddingProvider as registerAdapter,
} from "openclaw/plugin-sdk/memory-core-host-engine-embeddings";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { replaceSqliteSessionTranscriptEvents } from "../../../../src/config/sessions/transcript-store.sqlite.js";
import {
closeOpenClawAgentDatabasesForTest,
closeOpenClawStateDatabaseForTest,
openOpenClawAgentDatabase,
replaceSqliteSessionTranscriptEvents,
resolveOpenClawAgentSqlitePath,
} from "../../../../src/state/openclaw-agent-db.js";
import { closeOpenClawStateDatabaseForTest } from "../../../../src/state/openclaw-state-db.js";
} from "openclaw/plugin-sdk/session-store-runtime";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import "./test-runtime-mocks.js";
import type { MemoryIndexManager } from "./index.js";
import { closeAllMemorySearchManagers, getMemorySearchManager } from "./index.js";

View File

@@ -4,11 +4,13 @@ import os from "node:os";
import path from "node:path";
import type { DatabaseSync } from "node:sqlite";
import { setTimeout as scheduleNativeTimeout } from "node:timers";
import {
closeOpenClawAgentDatabasesForTest,
closeOpenClawStateDatabaseForTest,
replaceSqliteSessionTranscriptEvents,
} from "openclaw/plugin-sdk/session-store-runtime";
import type { Mock } from "vitest";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { replaceSqliteSessionTranscriptEvents } from "../../../../src/config/sessions/transcript-store.sqlite.js";
import { closeOpenClawAgentDatabasesForTest } from "../../../../src/state/openclaw-agent-db.js";
import { closeOpenClawStateDatabaseForTest } from "../../../../src/state/openclaw-state-db.js";
const { logWarnMock, logDebugMock, logInfoMock } = vi.hoisted(() => ({
logWarnMock: vi.fn(),

View File

@@ -56,7 +56,7 @@ const matrixStorageMetaStore = createPluginStateKeyedStore<MatrixQaStorageMetada
maxEntries: 10_000,
});
const matrixIdbSnapshotStore = createPluginBlobStore<Record<string, unknown>>("matrix", {
const matrixIdbSnapshotStore = createPluginBlobStore("matrix", {
namespace: MATRIX_IDB_SNAPSHOT_NAMESPACE,
maxEntries: 1_000,
});

View File

@@ -1,11 +1,11 @@
import fs from "node:fs/promises";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import {
closeOpenClawStateDatabaseForTest,
openOpenClawStateDatabase,
} from "../../../src/state/openclaw-state-db.js";
import { createTrackedTempDirs } from "../../../src/test-utils/tracked-temp-dirs.js";
} from "openclaw/plugin-sdk/session-store-runtime";
import { createTrackedTempDirs } from "openclaw/plugin-sdk/test-env";
import { afterEach, describe, expect, it } from "vitest";
import { detectQQBotLegacyStateMigrations } from "./state-migrations.js";
const tempDirs = createTrackedTempDirs();

View File

@@ -13,6 +13,8 @@ export {
loadSqliteSessionTranscriptEvents,
onSessionTranscriptUpdate,
parseUsageCountedSessionIdFromFileName,
closeOpenClawStateDatabaseForTest,
replaceSqliteSessionTranscriptEvents,
resolveSqliteSessionTranscriptScopeForPath,
stripInboundMetadata,
stripInternalRuntimeContext,

View File

@@ -5,7 +5,7 @@ import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from
import {
closeOpenClawStateDatabaseForTest,
replaceSqliteSessionTranscriptEvents,
} from "./openclaw-runtime.js";
} from "./openclaw-runtime-session.js";
import {
buildSessionTranscriptEntry,
listSessionTranscriptsForAgent,

View File

@@ -0,0 +1,122 @@
import type { AgentMessage, AgentToolResult } from "./agent-core-contract.js";
import type { Api, Model } from "./pi-ai-contract.js";
export type AgentSessionEventListener<TEvent = unknown> = {
bivarianceHack(event: TEvent): void;
}["bivarianceHack"];
export type AgentSession = {
agent: {
state: {
systemPrompt: string;
};
};
messages: AgentMessage[];
sessionFile?: string;
isCompacting: boolean;
subscribe(listener: AgentSessionEventListener): () => void;
abortCompaction(): void;
setActiveToolsByName(toolNames: string[]): void;
};
export type FileOperations = {
read: Iterable<string>;
written: Iterable<string>;
edited: Iterable<string>;
};
export type ContextUsage = {
tokens: number | null;
contextWindow: number;
percent: number | null;
};
export type CompactOptions = {
customInstructions?: string;
onComplete?: (result: { summary: string }) => void;
onError?: (error: Error) => void;
};
export type ExtensionContext = {
cwd: string;
sessionManager: object;
modelRegistry: unknown;
model: Model<Api> | undefined;
isIdle(): boolean;
signal: AbortSignal | undefined;
abort(): void;
hasPendingMessages(): boolean;
shutdown(): void;
getContextUsage(): ContextUsage | undefined;
compact(options?: CompactOptions): void;
getSystemPrompt(): string;
};
export type ContextEvent = {
type: "context";
messages: AgentMessage[];
};
export type ContextEventResult = {
messages?: AgentMessage[];
};
export type CompactionPreparation = {
messagesToSummarize: AgentMessage[];
turnPrefixMessages?: AgentMessage[];
previousSummary?: string;
firstKeptEntryId: string;
tokensBefore: number;
fileOps: FileOperations;
isSplitTurn?: boolean;
settings: {
reserveTokens: number;
};
};
export type SessionBeforeCompactEvent = {
type: "session_before_compact";
preparation: CompactionPreparation;
customInstructions?: string;
signal: AbortSignal;
};
export type SessionBeforeCompactResult = {
cancel?: boolean;
compaction?: {
summary: string;
firstKeptEntryId: string;
tokensBefore: number;
details?: unknown;
};
};
export type ToolResultEvent = {
type: "tool_result";
toolCallId: string;
toolName: string;
input: Record<string, unknown>;
content: AgentToolResult["content"];
details?: unknown;
isError: boolean;
};
export type ToolResultEventResult = {
content?: AgentToolResult["content"];
details?: unknown;
isError?: boolean;
};
export type ExtensionHandler<E, R = undefined> = (
event: E,
ctx: ExtensionContext,
) => Promise<R | void> | R | void;
export type ExtensionAPI = {
on(event: "context", handler: ExtensionHandler<ContextEvent, ContextEventResult>): void;
on(
event: "session_before_compact",
handler: ExtensionHandler<SessionBeforeCompactEvent, SessionBeforeCompactResult>,
): void;
on(event: "tool_result", handler: ExtensionHandler<ToolResultEvent, ToolResultEventResult>): void;
};

View File

@@ -1,7 +1,7 @@
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { ExtensionContext } from "./agent-extension-contract.js";
import * as piCodingAgent from "./pi-coding-agent-contract.js";
import type { ExtensionContext } from "./transcript/session-transcript-contract.js";
vi.mock("./pi-coding-agent-contract.js", async () => {
const actual = await vi.importActual<typeof piCodingAgent>("./pi-coding-agent-contract.js");

View File

@@ -1,9 +1,9 @@
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { retryAsync } from "../infra/retry.js";
import type { ExtensionContext } from "./agent-extension-contract.js";
import type { AssistantMessage, UserMessage } from "./pi-ai-contract.js";
import * as piCodingAgent from "./pi-coding-agent-contract.js";
import type { ExtensionContext } from "./transcript/session-transcript-contract.js";
// Mock the external generateSummary function
vi.mock("./pi-coding-agent-contract.js", async () => {

View File

@@ -1,8 +1,8 @@
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { summarizeWithFallback } from "./compaction.js";
import type { ExtensionContext } from "./agent-extension-contract.js";
import type { UserMessage } from "./pi-ai-contract.js";
import type { ExtensionContext } from "./transcript/session-transcript-contract.js";
const piCodingAgentMocks = vi.hoisted(() => ({
generateSummary: vi.fn(),

View File

@@ -5,6 +5,7 @@ import {
textToolResult,
} from "openclaw/plugin-sdk/agent-runtime-test-contracts";
import { afterEach, describe, expect, it, vi } from "vitest";
import type { ExtensionContext } from "./agent-extension-contract.js";
import type { MessagingToolSend } from "./pi-embedded-messaging.types.js";
import {
handleToolExecutionEnd,
@@ -17,7 +18,6 @@ import type {
import { toToolDefinitions } from "./pi-tool-definition-adapter.js";
import { createBaseToolHandlerState } from "./pi-tool-handler-state.test-helpers.js";
import { wrapToolWithBeforeToolCallHook } from "./pi-tools.before-tool-call.js";
import type { ExtensionContext } from "./transcript/session-transcript-contract.js";
function createContractTool(name: string, execute: AgentTool["execute"]): AgentTool {
return {

View File

@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { clearMemoryPluginState, registerMemoryPromptSection } from "../../plugins/memory-state.js";
import type { AgentSession } from "../transcript/session-transcript-contract.js";
import type { AgentSession } from "../agent-extension-contract.js";
import {
applySystemPromptOverrideToSession,
buildEmbeddedSystemPrompt,

View File

@@ -8,11 +8,11 @@ import {
clearCompactionProviders,
registerCompactionProvider,
} from "../../plugins/compaction-provider.js";
import type { ExtensionAPI, ExtensionContext } from "../agent-extension-contract.js";
import * as compactionModule from "../compaction.js";
import type { Api, Model } from "../pi-ai-contract.js";
import { buildEmbeddedExtensionFactories } from "../pi-embedded-runner/extensions.js";
import { castAgentMessage } from "../test-helpers/agent-message-fixtures.js";
import type { ExtensionAPI, ExtensionContext } from "../transcript/session-transcript-contract.js";
import {
consumeCompactionSafeguardCancelReason,
getCompactionSafeguardRuntime,

View File

@@ -1,7 +1,7 @@
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { describe, expect, it } from "vitest";
import type { ExtensionAPI, ExtensionContext } from "../agent-extension-contract.js";
import type { ToolResultMessage } from "../pi-ai-contract.js";
import type { ExtensionAPI, ExtensionContext } from "../transcript/session-transcript-contract.js";
import {
computeEffectiveSettings,
default as contextPruningExtension,

View File

@@ -1,6 +1,6 @@
import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { describe, expect, it } from "vitest";
import type { ExtensionContext } from "../../transcript/session-transcript-contract.js";
import type { ExtensionContext } from "../../agent-extension-contract.js";
import { pruneContextMessages } from "./pruner.js";
import { DEFAULT_CONTEXT_PRUNING_SETTINGS } from "./settings.js";

View File

@@ -13,6 +13,7 @@ import {
resolveSqliteSessionTranscriptScopeForPath,
} from "../../config/sessions/transcript-store.sqlite.js";
import { DEFAULT_AGENT_ID } from "../../routing/session-key.js";
import { CURRENT_SESSION_VERSION } from "./session-transcript-format.js";
import type {
FileEntry,
SessionContext,
@@ -22,8 +23,7 @@ import type {
SessionListProgress,
SessionManager,
SessionTreeNode,
} from "./session-transcript-contract.js";
import { CURRENT_SESSION_VERSION } from "./session-transcript-format.js";
} from "./session-transcript-types.js";
import { TranscriptState } from "./transcript-state.js";
function createSessionHeader(params: {

View File

@@ -1,192 +1,48 @@
import type { AgentMessage } from "../agent-core-contract.js";
import type { ImageContent, TextContent } from "../pi-ai-contract.js";
import { SessionManagerValue } from "./session-manager.js";
import type {
SessionInfo,
SessionListProgress,
SessionManager as SessionManagerType,
} from "./session-transcript-types.js";
export {
buildSessionContext,
CURRENT_SESSION_VERSION,
migrateSessionEntries,
parseSessionEntries,
} from "./session-transcript-format.js";
export type { AgentSession, ExtensionAPI, ExtensionContext } from "../agent-extension-contract.js";
export type {
AgentSession,
ExtensionAPI,
ExtensionContext,
} from "../agent-extension-public-types.js";
export type {
BranchSummaryEntry,
CompactionEntry,
CustomEntry,
CustomMessageEntry,
FileEntry,
LabelEntry,
ModelChangeEntry,
SessionContext,
SessionEntry,
SessionEntryBase,
SessionHeader,
SessionInfo,
SessionInfoEntry,
SessionListProgress,
SessionMessageEntry,
SessionTreeNode,
ThinkingLevelChangeEntry,
} from "./session-transcript-types.js";
export type SessionHeader = {
type: "session";
version?: number;
id: string;
timestamp: string;
cwd: string;
parentSession?: string;
};
export type SessionEntryBase = {
type: string;
id: string;
parentId: string | null;
timestamp: string;
};
export type SessionMessageEntry = SessionEntryBase & {
type: "message";
message: AgentMessage;
};
export type ThinkingLevelChangeEntry = SessionEntryBase & {
type: "thinking_level_change";
thinkingLevel: string;
};
export type ModelChangeEntry = SessionEntryBase & {
type: "model_change";
provider: string;
modelId: string;
};
export type CompactionEntry<T = unknown> = SessionEntryBase & {
type: "compaction";
summary: string;
firstKeptEntryId: string;
tokensBefore: number;
details?: T;
fromHook?: boolean;
};
export type BranchSummaryEntry<T = unknown> = SessionEntryBase & {
type: "branch_summary";
fromId: string;
summary: string;
details?: T;
fromHook?: boolean;
};
export type CustomEntry<T = unknown> = SessionEntryBase & {
type: "custom";
customType: string;
data?: T;
};
export type LabelEntry = SessionEntryBase & {
type: "label";
targetId: string;
label: string | undefined;
};
export type SessionInfoEntry = SessionEntryBase & {
type: "session_info";
name?: string;
};
export type CustomMessageEntry<T = unknown> = SessionEntryBase & {
type: "custom_message";
customType: string;
content: string | (TextContent | ImageContent)[];
details?: T;
display: boolean;
};
export type SessionEntry =
| SessionMessageEntry
| ThinkingLevelChangeEntry
| ModelChangeEntry
| CompactionEntry
| BranchSummaryEntry
| CustomEntry
| CustomMessageEntry
| LabelEntry
| SessionInfoEntry;
export type FileEntry = SessionHeader | SessionEntry;
export type SessionTreeNode = {
entry: SessionEntry;
children: SessionTreeNode[];
label?: string;
labelTimestamp?: string;
};
export type SessionContext = {
messages: AgentMessage[];
thinkingLevel: string;
model: { provider: string; modelId: string } | null;
};
export type SessionInfo = {
path: string;
id: string;
cwd: string;
name?: string;
parentSessionPath?: string;
created: Date;
modified: Date;
messageCount: number;
firstMessage: string;
allMessagesText: string;
};
export type SessionListProgress = (loaded: number, total: number) => void;
type PersistableSessionMessage = Exclude<
AgentMessage,
{ role: "branchSummary" | "compactionSummary" }
>;
export type SessionManager = {
setSessionFile(sessionFile: string): void;
newSession(options?: { id?: string; parentSession?: string }): string | undefined;
isPersisted(): boolean;
getCwd(): string;
getSessionId(): string;
getSessionFile(): string | undefined;
appendMessage(message: PersistableSessionMessage): string;
appendThinkingLevelChange(thinkingLevel: string): string;
appendModelChange(provider: string, modelId: string): string;
appendCompaction(
summary: string,
firstKeptEntryId: string,
tokensBefore: number,
details?: unknown,
fromHook?: boolean,
): string;
appendCustomEntry(customType: string, data?: unknown): string;
appendSessionInfo(name: string): string;
getSessionName(): string | undefined;
appendCustomMessageEntry(
customType: string,
content: string | (TextContent | ImageContent)[],
display: boolean,
details?: unknown,
): string;
getLeafId(): string | null;
getLeafEntry(): SessionEntry | undefined;
getEntry(id: string): SessionEntry | undefined;
getChildren(parentId: string): SessionEntry[];
getLabel(id: string): string | undefined;
appendLabelChange(targetId: string, label: string | undefined): string;
getBranch(fromId?: string): SessionEntry[];
buildSessionContext(): SessionContext;
getHeader(): SessionHeader | null;
getEntries(): SessionEntry[];
getTree(): SessionTreeNode[];
branch(branchFromId: string): void;
resetLeaf(): void;
removeTailEntries(
shouldRemove: (entry: SessionEntry) => boolean,
options?: { maxEntries?: number; minEntries?: number },
): number;
branchWithSummary(
branchFromId: string | null,
summary: string,
details?: unknown,
fromHook?: boolean,
): string;
createBranchedSession(leafId: string): string | undefined;
};
export type SessionManager = SessionManagerType;
export const SessionManager = SessionManagerValue as {
create(cwd: string): SessionManager;
open(path: string, cwdOverride?: string): SessionManager;
continueRecent(cwd: string): SessionManager;
inMemory(cwd?: string): SessionManager;
forkFrom(sourcePath: string, targetCwd: string): SessionManager;
create(cwd: string): SessionManagerType;
open(path: string, cwdOverride?: string): SessionManagerType;
continueRecent(cwd: string): SessionManagerType;
inMemory(cwd?: string): SessionManagerType;
forkFrom(sourcePath: string, targetCwd: string): SessionManagerType;
list(cwd: string, onProgress?: SessionListProgress): Promise<SessionInfo[]>;
listAll(onProgress?: SessionListProgress): Promise<SessionInfo[]>;
};

View File

@@ -8,7 +8,7 @@ import type {
SessionContext,
SessionEntry,
SessionHeader,
} from "./session-transcript-contract.js";
} from "./session-transcript-types.js";
export const CURRENT_SESSION_VERSION = 3;

View File

@@ -0,0 +1,174 @@
import type { AgentMessage } from "../agent-core-contract.js";
import type { ImageContent, TextContent } from "../pi-ai-contract.js";
export type SessionHeader = {
type: "session";
version?: number;
id: string;
timestamp: string;
cwd: string;
parentSession?: string;
};
export type SessionEntryBase = {
type: string;
id: string;
parentId: string | null;
timestamp: string;
};
export type SessionMessageEntry = SessionEntryBase & {
type: "message";
message: AgentMessage;
};
export type ThinkingLevelChangeEntry = SessionEntryBase & {
type: "thinking_level_change";
thinkingLevel: string;
};
export type ModelChangeEntry = SessionEntryBase & {
type: "model_change";
provider: string;
modelId: string;
};
export type CompactionEntry<T = unknown> = SessionEntryBase & {
type: "compaction";
summary: string;
firstKeptEntryId: string;
tokensBefore: number;
details?: T;
fromHook?: boolean;
};
export type BranchSummaryEntry<T = unknown> = SessionEntryBase & {
type: "branch_summary";
fromId: string;
summary: string;
details?: T;
fromHook?: boolean;
};
export type CustomEntry<T = unknown> = SessionEntryBase & {
type: "custom";
customType: string;
data?: T;
};
export type LabelEntry = SessionEntryBase & {
type: "label";
targetId: string;
label: string | undefined;
};
export type SessionInfoEntry = SessionEntryBase & {
type: "session_info";
name?: string;
};
export type CustomMessageEntry<T = unknown> = SessionEntryBase & {
type: "custom_message";
customType: string;
content: string | (TextContent | ImageContent)[];
details?: T;
display: boolean;
};
export type SessionEntry =
| SessionMessageEntry
| ThinkingLevelChangeEntry
| ModelChangeEntry
| CompactionEntry
| BranchSummaryEntry
| CustomEntry
| CustomMessageEntry
| LabelEntry
| SessionInfoEntry;
export type FileEntry = SessionHeader | SessionEntry;
export type SessionTreeNode = {
entry: SessionEntry;
children: SessionTreeNode[];
label?: string;
labelTimestamp?: string;
};
export type SessionContext = {
messages: AgentMessage[];
thinkingLevel: string;
model: { provider: string; modelId: string } | null;
};
export type SessionInfo = {
path: string;
id: string;
cwd: string;
name?: string;
parentSessionPath?: string;
created: Date;
modified: Date;
messageCount: number;
firstMessage: string;
allMessagesText: string;
};
export type SessionListProgress = (loaded: number, total: number) => void;
type PersistableSessionMessage = Exclude<
AgentMessage,
{ role: "branchSummary" | "compactionSummary" }
>;
export type SessionManager = {
setSessionFile(sessionFile: string): void;
newSession(options?: { id?: string; parentSession?: string }): string | undefined;
isPersisted(): boolean;
getCwd(): string;
getSessionId(): string;
getSessionFile(): string | undefined;
appendMessage(message: PersistableSessionMessage): string;
appendThinkingLevelChange(thinkingLevel: string): string;
appendModelChange(provider: string, modelId: string): string;
appendCompaction(
summary: string,
firstKeptEntryId: string,
tokensBefore: number,
details?: unknown,
fromHook?: boolean,
): string;
appendCustomEntry(customType: string, data?: unknown): string;
appendSessionInfo(name: string): string;
getSessionName(): string | undefined;
appendCustomMessageEntry(
customType: string,
content: string | (TextContent | ImageContent)[],
display: boolean,
details?: unknown,
): string;
getLeafId(): string | null;
getLeafEntry(): SessionEntry | undefined;
getEntry(id: string): SessionEntry | undefined;
getChildren(parentId: string): SessionEntry[];
getLabel(id: string): string | undefined;
appendLabelChange(targetId: string, label: string | undefined): string;
getBranch(fromId?: string): SessionEntry[];
buildSessionContext(): SessionContext;
getHeader(): SessionHeader | null;
getEntries(): SessionEntry[];
getTree(): SessionTreeNode[];
branch(branchFromId: string): void;
resetLeaf(): void;
removeTailEntries(
shouldRemove: (entry: SessionEntry) => boolean,
options?: { maxEntries?: number; minEntries?: number },
): number;
branchWithSummary(
branchFromId: string | null,
summary: string,
details?: unknown,
fromHook?: boolean,
): string;
createBranchedSession(leafId: string): string | undefined;
};

View File

@@ -1,24 +1,24 @@
import { randomUUID } from "node:crypto";
import path from "node:path";
import { isSqliteSessionTranscriptLocator } from "../../config/sessions.js";
import { isSqliteSessionTranscriptLocator } from "../../config/sessions/paths.js";
import {
appendSqliteSessionTranscriptEvent,
loadSqliteSessionTranscriptEvents,
replaceSqliteSessionTranscriptEvents,
resolveSqliteSessionTranscriptScopeForPath,
} from "../../config/sessions/transcript-store.sqlite.js";
import {
buildSessionContext,
CURRENT_SESSION_VERSION,
migrateSessionEntries,
} from "./session-transcript-format.js";
import type {
FileEntry,
SessionContext,
SessionEntry,
SessionHeader,
SessionTreeNode,
} from "./session-transcript-contract.js";
import {
buildSessionContext,
CURRENT_SESSION_VERSION,
migrateSessionEntries,
} from "./session-transcript-format.js";
} from "./session-transcript-types.js";
type BranchSummaryEntry = Extract<SessionEntry, { type: "branch_summary" }>;
type CompactionEntry = Extract<SessionEntry, { type: "compaction" }>;

View File

@@ -243,7 +243,7 @@ export type SessionEntry = {
/** Epoch ms cutoff paired with abortCutoffMessageSid when available. */
abortCutoffTimestamp?: number;
chatType?: SessionChatType;
/** Legacy alias migrated to lastChannel by doctor session migration. */
/** @deprecated Legacy alias migrated to lastChannel by doctor session migration. */
lastProvider?: string;
thinkingLevel?: string;
fastMode?: boolean;

View File

@@ -43,6 +43,7 @@ export type { HeartbeatToolResponse } from "../auto-reply/heartbeat-tool-respons
export type { AgentApprovalEventData, AgentEventPayload } from "../infra/agent-events.js";
export type { ExecApprovalDecision } from "../infra/exec-approvals.js";
export type { NormalizedUsage } from "../agents/usage.js";
export { listTrajectoryRuntimeEvents } from "../trajectory/runtime-store.sqlite.js";
export type {
AgentToolResultMiddleware,
AgentToolResultMiddlewareContext,

View File

@@ -1,6 +1,14 @@
// Narrow SQLite session row helpers for channel hot paths.
export { closeOpenClawAgentDatabasesForTest } from "../state/openclaw-agent-db.js";
export {
closeOpenClawAgentDatabasesForTest,
openOpenClawAgentDatabase,
resolveOpenClawAgentSqlitePath,
} from "../state/openclaw-agent-db.js";
export {
closeOpenClawStateDatabaseForTest,
openOpenClawStateDatabase,
} from "../state/openclaw-state-db.js";
export { resolveSessionRowEntry } from "../config/sessions/store-entry.js";
export { createSqliteSessionTranscriptLocator } from "../config/sessions/paths.js";
export { resolveAndPersistSessionTranscriptLocator } from "../config/sessions/session-locator.js";
@@ -17,6 +25,10 @@ export {
updateLastRoute,
upsertSessionEntry,
} from "../config/sessions/store.js";
export {
loadSqliteSessionTranscriptEvents,
replaceSqliteSessionTranscriptEvents,
} from "../config/sessions/transcript-store.sqlite.js";
export {
evaluateSessionFreshness,
resolveChannelResetConfig,

View File

@@ -62,6 +62,8 @@ export { createMockServerResponse } from "../test-utils/mock-http-response.js";
export { createTempHomeEnv, type TempHomeEnv } from "../test-utils/temp-home.js";
export { withTempDir } from "../test-utils/temp-dir.js";
export { useFrozenTime, useRealTime } from "../test-utils/frozen-time.js";
export { withOpenClawTestState } from "../test-utils/openclaw-test-state.js";
export { createTrackedTempDirs } from "../test-utils/tracked-temp-dirs.js";
export { withServer } from "./test-helpers/http-test-server.js";
export { createMockIncomingRequest } from "./test-helpers/mock-incoming-request.js";
export { withTempHome } from "./test-helpers/temp-home.js";

View File

@@ -4,9 +4,9 @@ import type { PluginCompatCode } from "./compat/registry.js";
import type { PluginCandidate } from "./discovery.js";
import type { PluginInstallSourceInfo } from "./install-source-info.js";
import type { InstalledPluginFileSignature } from "./installed-plugin-index-hash.js";
import type { PluginManifestRecord } from "./manifest-registry.js";
import type { PluginDiagnostic } from "./manifest-types.js";
import type { PluginDiagnostic, PluginBundleFormat, PluginFormat } from "./manifest-types.js";
import type { PluginPackageChannel } from "./manifest.js";
import type { PluginOrigin } from "./plugin-origin.types.js";
export const INSTALLED_PLUGIN_INDEX_VERSION = 1;
export const INSTALLED_PLUGIN_INDEX_MIGRATION_VERSION = 1;
@@ -88,8 +88,8 @@ export type InstalledPluginIndexRecord = {
manifestPath: string;
manifestHash: string;
manifestFile?: InstalledPluginFileSignature;
format?: PluginManifestRecord["format"];
bundleFormat?: PluginManifestRecord["bundleFormat"];
format?: PluginFormat;
bundleFormat?: PluginBundleFormat;
source?: string;
setupSource?: string;
packageJson?: {
@@ -98,7 +98,7 @@ export type InstalledPluginIndexRecord = {
fileSignature?: InstalledPluginFileSignature;
};
rootDir: string;
origin: PluginManifestRecord["origin"];
origin: PluginOrigin;
enabled: boolean;
enabledByDefault?: boolean;
enabledByDefaultOnPlatforms?: readonly string[];