docs: document bootstrap cache helpers

This commit is contained in:
Peter Steinberger
2026-06-03 22:56:27 -04:00
parent c7a8114f54
commit 83eab79d15
6 changed files with 29 additions and 0 deletions
+3
View File
@@ -4,6 +4,9 @@ import { createInternalHookEvent, triggerInternalHook } from "../hooks/internal-
import { resolveAgentIdFromSessionKey } from "../routing/session-key.js";
import type { WorkspaceBootstrapFile } from "./workspace.js";
// Applies internal hook overrides to the workspace bootstrap file set before a
// session starts. Hooks can add/remove bootstrap files for agent-specific setup.
/** Run bootstrap hooks and return the effective bootstrap file list. */
export async function applyBootstrapHookOverrides(params: {
files: WorkspaceBootstrapFile[];
workspaceDir: string;
+4
View File
@@ -1,5 +1,8 @@
// Bootstrap mode resolver for deciding whether a run gets full, limited, or no
// workspace bootstrap files.
export type BootstrapMode = "full" | "limited" | "none";
/** Resolve the bootstrap mode for one agent run. */
export function resolveBootstrapMode(params: {
bootstrapPending: boolean;
runKind?: "default" | "heartbeat" | "cron";
@@ -12,6 +15,7 @@ export function resolveBootstrapMode(params: {
return "none";
}
if (params.runKind === "heartbeat" || params.runKind === "cron") {
// Background maintenance turns should not consume or mutate bootstrap state.
return "none";
}
if (!params.isPrimaryRun || !params.isInteractiveUserFacing) {
+7
View File
@@ -11,6 +11,8 @@ import type { AgentMessage, StreamFn } from "./runtime/index.js";
import { stableStringify } from "./stable-stringify.js";
import { buildAgentTraceBase } from "./trace-base.js";
// Optional cache-trace diagnostics for prompt/session/cache debugging. Payloads
// are redacted before JSONL output while stable digests preserve correlation.
type CacheTraceStage =
| "cache:result"
| "cache:state"
@@ -119,6 +121,8 @@ function summarizeMessages(messages: AgentMessage[]): {
messageFingerprints: string[];
messagesDigest: string;
} {
// Hash each message and then the ordered fingerprint list so traces can detect
// prompt drift without writing full messages when disabled.
const messageFingerprints = messages.map((msg) => digest(msg));
return {
messageCount: messages.length,
@@ -128,6 +132,7 @@ function summarizeMessages(messages: AgentMessage[]): {
};
}
/** Create a cache trace recorder when diagnostics config/env enables it. */
export function createCacheTrace(params: CacheTraceInit): CacheTrace | null {
const cfg = resolveCacheTraceConfig(params);
if (!cfg.enabled) {
@@ -169,6 +174,8 @@ export function createCacheTrace(params: CacheTraceInit): CacheTrace | null {
event.messageFingerprints = summary.messageFingerprints;
event.messagesDigest = summary.messagesDigest;
if (cfg.includeMessages) {
// Full messages are optional; summaries/digests are always recorded when
// message payloads are supplied.
event.messages = sanitizeDiagnosticPayload(messages) as AgentMessage[];
}
}
+12
View File
@@ -24,6 +24,8 @@ import type {
AgentRuntimeCacheWriteOptions,
} from "./agent-cache-store.js";
// SQLite-backed agent runtime cache. Entries are scoped per agent/scope pair and
// can store JSON values, binary blobs, and optional expiration timestamps.
export type SqliteAgentCacheStoreOptions = OpenClawAgentDatabaseOptions & {
scope: string;
now?: () => number;
@@ -48,6 +50,8 @@ function normalizeScopeValue(value: string): string {
}
function normalizeKey(value: string): string {
// Scope/key values become SQLite unique keys; reject empty/NUL values before
// they reach the database layer.
const key = value.trim();
if (!key) {
throw new Error("SQLite agent cache key is required.");
@@ -138,6 +142,7 @@ function resolveExpiresAt(options: AgentRuntimeCacheWriteOptions, now: number):
return null;
}
/** Upsert one SQLite cache entry and return the normalized cache value. */
export function writeSqliteAgentCacheEntry(
options: WriteSqliteAgentCacheEntryOptions,
): AgentRuntimeCacheValue {
@@ -187,6 +192,7 @@ export function writeSqliteAgentCacheEntry(
};
}
/** Read one non-expired SQLite cache entry by key. */
export function readSqliteAgentCacheEntry(
options: SqliteAgentCacheStoreOptions & { key: string },
): AgentRuntimeCacheValue | null {
@@ -209,6 +215,7 @@ export function readSqliteAgentCacheEntry(
return rowToCacheValue(row, scope);
}
/** List non-expired SQLite cache entries for the configured scope. */
export function listSqliteAgentCacheEntries(
options: SqliteAgentCacheStoreOptions,
): AgentRuntimeCacheValue[] {
@@ -228,6 +235,7 @@ export function listSqliteAgentCacheEntries(
.map((row) => rowToCacheValue(row, scope));
}
/** Delete one SQLite cache entry by key. */
export function deleteSqliteAgentCacheEntry(
options: SqliteAgentCacheStoreOptions & { key: string },
): boolean {
@@ -243,6 +251,7 @@ export function deleteSqliteAgentCacheEntry(
}, toDatabaseOptions(options));
}
/** Clear all SQLite cache entries for the configured scope. */
export function clearSqliteAgentCacheEntries(options: SqliteAgentCacheStoreOptions): number {
const scope = normalizeScope(options);
return runOpenClawAgentWriteTransaction((database) => {
@@ -255,6 +264,7 @@ export function clearSqliteAgentCacheEntries(options: SqliteAgentCacheStoreOptio
}, toDatabaseOptions(options));
}
/** Delete expired or invalid-expiration SQLite cache entries for the scope. */
export function clearExpiredSqliteAgentCacheEntries(
options: SqliteAgentCacheStoreOptions & { currentTime?: number },
): number {
@@ -283,6 +293,7 @@ export function clearExpiredSqliteAgentCacheEntries(
}, toDatabaseOptions(options));
}
/** Agent runtime cache store implementation backed by OpenClaw's SQLite DB. */
export class SqliteAgentCacheStore implements AgentRuntimeCacheStore {
readonly #options: SqliteAgentCacheStoreOptions;
@@ -332,6 +343,7 @@ export class SqliteAgentCacheStore implements AgentRuntimeCacheStore {
}
}
/** Create a SQLite-backed agent runtime cache store. */
export function createSqliteAgentCacheStore(
options: SqliteAgentCacheStoreOptions,
): SqliteAgentCacheStore {
+2
View File
@@ -1,3 +1,5 @@
// Agent runtime cache store contract. Implementations persist scoped key/value
// data plus optional blobs and expiration metadata.
export type AgentRuntimeCacheValue = {
agentId: string;
scope: string;
+1
View File
@@ -1,3 +1,4 @@
// Default watchdog timing bounds for CLI-backed agent sessions.
export const CLI_WATCHDOG_MIN_TIMEOUT_MS = 1_000;
export const CLI_FRESH_WATCHDOG_DEFAULTS = {