From 83eab79d150349cd71936704f8ec89ee0019b64e Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 3 Jun 2026 22:56:27 -0400 Subject: [PATCH] docs: document bootstrap cache helpers --- src/agents/bootstrap-hooks.ts | 3 +++ src/agents/bootstrap-mode.ts | 4 ++++ src/agents/cache-trace.ts | 7 +++++++ src/agents/cache/agent-cache-store.sqlite.ts | 12 ++++++++++++ src/agents/cache/agent-cache-store.ts | 2 ++ src/agents/cli-watchdog-defaults.ts | 1 + 6 files changed, 29 insertions(+) diff --git a/src/agents/bootstrap-hooks.ts b/src/agents/bootstrap-hooks.ts index ccfa9c0523ef..667eadff2ce1 100644 --- a/src/agents/bootstrap-hooks.ts +++ b/src/agents/bootstrap-hooks.ts @@ -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; diff --git a/src/agents/bootstrap-mode.ts b/src/agents/bootstrap-mode.ts index 9618795bb6a2..65a712afc59d 100644 --- a/src/agents/bootstrap-mode.ts +++ b/src/agents/bootstrap-mode.ts @@ -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) { diff --git a/src/agents/cache-trace.ts b/src/agents/cache-trace.ts index a06fd57a2dd8..62d672ad575a 100644 --- a/src/agents/cache-trace.ts +++ b/src/agents/cache-trace.ts @@ -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[]; } } diff --git a/src/agents/cache/agent-cache-store.sqlite.ts b/src/agents/cache/agent-cache-store.sqlite.ts index 42d70518e1fd..6e241d6a7db1 100644 --- a/src/agents/cache/agent-cache-store.sqlite.ts +++ b/src/agents/cache/agent-cache-store.sqlite.ts @@ -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 { diff --git a/src/agents/cache/agent-cache-store.ts b/src/agents/cache/agent-cache-store.ts index 16b527aa5bec..4f97cfac5d1a 100644 --- a/src/agents/cache/agent-cache-store.ts +++ b/src/agents/cache/agent-cache-store.ts @@ -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; diff --git a/src/agents/cli-watchdog-defaults.ts b/src/agents/cli-watchdog-defaults.ts index c96f87e30b07..b268c0528c8d 100644 --- a/src/agents/cli-watchdog-defaults.ts +++ b/src/agents/cli-watchdog-defaults.ts @@ -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 = {