refactor(runtime): hide default constants

This commit is contained in:
Vincent Koc
2026-06-17 18:20:05 +08:00
parent 392bd16a1d
commit 0842cb71eb
18 changed files with 37 additions and 26 deletions
+2 -2
View File
@@ -5,8 +5,8 @@ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coe
import type { MsgContext } from "../templating.js";
import type { HistoryEntry, HistoryMediaEntry } from "./history.types.js";
export const RECENT_HISTORY_IMAGE_TTL_MS = 30 * 60_000;
export const RECENT_HISTORY_IMAGE_LIMIT = 4;
const RECENT_HISTORY_IMAGE_TTL_MS = 30 * 60_000;
const RECENT_HISTORY_IMAGE_LIMIT = 4;
export type RecentInboundHistoryImage = {
path: string;
@@ -3,10 +3,9 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import {
DEFAULT_REPLAY_MAX_MESSAGES,
replayRecentUserAssistantMessages,
} from "./session-transcript-replay.js";
import { replayRecentUserAssistantMessages } from "./session-transcript-replay.js";
const DEFAULT_REPLAY_MAX_MESSAGES = 6;
const j = (obj: unknown): string => `${JSON.stringify(obj)}\n`;
@@ -5,7 +5,7 @@ import path from "node:path";
import { CURRENT_SESSION_VERSION } from "../../config/sessions/version.js";
/** Tail kept so DM continuity survives silent session rotations. */
export const DEFAULT_REPLAY_MAX_MESSAGES = 6;
const DEFAULT_REPLAY_MAX_MESSAGES = 6;
type SessionRecord = {
type?: unknown;
+1 -1
View File
@@ -18,7 +18,7 @@ export type TypingModeContext = {
};
/** Group chats default to message-triggered typing to avoid noisy indicators. */
export const DEFAULT_GROUP_TYPING_MODE: TypingMode = "message";
const DEFAULT_GROUP_TYPING_MODE: TypingMode = "message";
/** Resolves the effective typing mode for the current auto-reply turn. */
export function resolveTypingMode({
@@ -1,8 +1,9 @@
// Cron store migration tests cover doctor migration of persisted cron stores.
import { describe, expect, it } from "vitest";
import { DEFAULT_TOP_OF_HOUR_STAGGER_MS } from "../../../cron/stagger.js";
import { normalizeStoredCronJobs } from "./store-migration.js";
const DEFAULT_TOP_OF_HOUR_STAGGER_MS = 5 * 60 * 1000;
function makeLegacyJob(overrides: Record<string, unknown>): Record<string, unknown> {
return {
id: "job-legacy",
+1 -1
View File
@@ -6,7 +6,7 @@ import type { OpenClawConfig } from "../config/config.js";
// heartbeat delivery limits.
const DEFAULT_COMMITMENT_EXTRACTION_DEBOUNCE_MS = 15_000;
const DEFAULT_COMMITMENT_BATCH_MAX_ITEMS = 8;
export const DEFAULT_COMMITMENT_EXTRACTION_QUEUE_MAX_ITEMS = 64;
const DEFAULT_COMMITMENT_EXTRACTION_QUEUE_MAX_ITEMS = 64;
const DEFAULT_COMMITMENT_CONFIDENCE_THRESHOLD = 0.72;
const DEFAULT_COMMITMENT_CARE_CONFIDENCE_THRESHOLD = 0.86;
const DEFAULT_COMMITMENT_EXTRACTION_TIMEOUT_SECONDS = 45;
+2 -1
View File
@@ -5,7 +5,6 @@ import path from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import { captureEnv, setTestEnvValue } from "../test-utils/env.js";
import { DEFAULT_COMMITMENT_EXTRACTION_QUEUE_MAX_ITEMS } from "./config.js";
import {
configureCommitmentExtractionRuntime,
drainCommitmentExtractionQueue,
@@ -15,6 +14,8 @@ import {
import { loadCommitmentStore } from "./store.js";
import type { CommitmentExtractionBatchResult, CommitmentExtractionItem } from "./types.js";
const DEFAULT_COMMITMENT_EXTRACTION_QUEUE_MAX_ITEMS = 64;
const runEmbeddedAgentMock = vi.hoisted(() => vi.fn());
const resolveDefaultModelMock = vi.hoisted(() => vi.fn());
+2 -1
View File
@@ -5,7 +5,8 @@ import {
validateCronUpdateParams,
} from "../../packages/gateway-protocol/src/index.js";
import { normalizeCronJobCreate, normalizeCronJobPatch } from "./normalize.js";
import { DEFAULT_TOP_OF_HOUR_STAGGER_MS } from "./stagger.js";
const DEFAULT_TOP_OF_HOUR_STAGGER_MS = 5 * 60 * 1000;
function expectNormalizedAtSchedule(scheduleInput: Record<string, unknown>) {
const normalized = normalizeCronJobCreate({
+3 -2
View File
@@ -6,8 +6,6 @@ import { describe, expect, it } from "vitest";
import { migrateLegacyCronRunLogsToSqlite } from "../commands/doctor/cron/legacy-run-log-migration.js";
import {
appendCronRunLog,
DEFAULT_CRON_RUN_LOG_KEEP_LINES,
DEFAULT_CRON_RUN_LOG_MAX_BYTES,
getPendingCronRunLogWriteCountForTests,
readCronRunLogEntries,
readCronRunLogEntriesPage,
@@ -15,6 +13,9 @@ import {
resolveCronRunLogPruneOptions,
} from "./run-log.js";
const DEFAULT_CRON_RUN_LOG_MAX_BYTES = 2_000_000;
const DEFAULT_CRON_RUN_LOG_KEEP_LINES = 2_000;
describe("cron run log", () => {
it("resolves prune options from config with defaults", () => {
expect(resolveCronRunLogPruneOptions()).toEqual({
+2 -2
View File
@@ -80,9 +80,9 @@ export function isInvalidCronRunLogJobIdError(err: unknown): boolean {
const writesByTarget = new Map<string, Promise<void>>();
/** Legacy byte cap kept for config parsing compatibility with older file-backed run logs. */
export const DEFAULT_CRON_RUN_LOG_MAX_BYTES = 2_000_000;
const DEFAULT_CRON_RUN_LOG_MAX_BYTES = 2_000_000;
/** Default SQLite row retention per cron job when no explicit keepLines value is configured. */
export const DEFAULT_CRON_RUN_LOG_KEEP_LINES = 2_000;
const DEFAULT_CRON_RUN_LOG_KEEP_LINES = 2_000;
/** Resolves configured run-log pruning limits while preserving legacy maxBytes parsing. */
export function resolveCronRunLogPruneOptions(cfg?: CronConfig["runLog"]): {
+2 -1
View File
@@ -8,9 +8,10 @@ import {
recomputeNextRunsForMaintenance,
} from "./service/jobs.js";
import type { CronServiceState } from "./service/state.js";
import { DEFAULT_TOP_OF_HOUR_STAGGER_MS } from "./stagger.js";
import type { CronJob, CronJobPatch } from "./types.js";
const DEFAULT_TOP_OF_HOUR_STAGGER_MS = 5 * 60 * 1000;
function expectCronStaggerMs(job: CronJob, expected: number): void {
expect(job.schedule.kind).toBe("cron");
if (job.schedule.kind === "cron") {
@@ -2,9 +2,10 @@
import crypto from "node:crypto";
import { describe, expect, it, vi } from "vitest";
import { computeJobNextRunAtMs } from "./service/jobs.js";
import { DEFAULT_TOP_OF_HOUR_STAGGER_MS } from "./stagger.js";
import type { CronJob } from "./types.js";
const DEFAULT_TOP_OF_HOUR_STAGGER_MS = 5 * 60 * 1000;
function stableOffsetMs(jobId: string, windowMs: number) {
const digest = crypto.createHash("sha256").update(jobId).digest();
return digest.readUInt32BE(0) % windowMs;
+2 -1
View File
@@ -1,12 +1,13 @@
// Cron stagger tests cover deterministic schedule spreading across jobs.
import { describe, expect, it } from "vitest";
import {
DEFAULT_TOP_OF_HOUR_STAGGER_MS,
isRecurringTopOfHourCronExpr,
normalizeCronStaggerMs,
resolveCronStaggerMs,
} from "./stagger.js";
const DEFAULT_TOP_OF_HOUR_STAGGER_MS = 5 * 60 * 1000;
describe("cron stagger helpers", () => {
it("detects recurring top-of-hour cron expressions for 5-field and 6-field cron", () => {
expect(isRecurringTopOfHourCronExpr("0 * * * *")).toBe(true);
+1 -1
View File
@@ -3,7 +3,7 @@ import { parseStrictNonNegativeInteger } from "../infra/parse-finite-number.js";
import type { CronSchedule } from "./types.js";
/** Default jitter window applied to recurring top-of-hour cron schedules. */
export const DEFAULT_TOP_OF_HOUR_STAGGER_MS = 5 * 60 * 1000;
const DEFAULT_TOP_OF_HOUR_STAGGER_MS = 5 * 60 * 1000;
function parseCronFields(expr: string) {
return expr.trim().split(/\s+/).filter(Boolean);
+3 -1
View File
@@ -7,7 +7,9 @@ import {
summarizeTaskAuditFindings,
} from "./task-registry.audit.js";
import type { TaskRecord } from "./task-registry.types.js";
import { DEFAULT_TASK_RETENTION_MS, LOST_TASK_RETENTION_MS } from "./task-retention.js";
const DEFAULT_TASK_RETENTION_MS = 7 * 24 * 60 * 60_000;
const LOST_TASK_RETENTION_MS = 24 * 60 * 60_000;
function createTask(partial: Partial<TaskRecord>): TaskRecord {
return {
+3 -1
View File
@@ -72,7 +72,9 @@ import {
} from "./task-registry.maintenance.js";
import { configureTaskRegistryRuntime } from "./task-registry.store.js";
import type { TaskDeliveryState, TaskRecord } from "./task-registry.types.js";
import { DEFAULT_TASK_RETENTION_MS, LOST_TASK_RETENTION_MS } from "./task-retention.js";
const DEFAULT_TASK_RETENTION_MS = 7 * 24 * 60 * 60_000;
const LOST_TASK_RETENTION_MS = 24 * 60 * 60_000;
function createTaskRecord(params: Parameters<typeof createTaskRecordOrNull>[0]): TaskRecord {
const task = createTaskRecordOrNull(params);
+3 -2
View File
@@ -1,13 +1,14 @@
// Covers task retention pruning and stale-task cleanup windows.
import { describe, expect, it } from "vitest";
import {
DEFAULT_TASK_RETENTION_MS,
LOST_TASK_RETENTION_MS,
resolveEffectiveTaskCleanupAfter,
resolveTaskCleanupAfter,
resolveTaskRetentionMs,
} from "./task-retention.js";
const DEFAULT_TASK_RETENTION_MS = 7 * 24 * 60 * 60_000;
const LOST_TASK_RETENTION_MS = 24 * 60 * 60_000;
describe("task retention", () => {
it("keeps lost tasks on a shorter retention window", () => {
expect(resolveTaskRetentionMs("lost")).toBe(LOST_TASK_RETENTION_MS);
+2 -2
View File
@@ -2,8 +2,8 @@
import type { TaskRecord, TaskStatus } from "./task-registry.types.js";
/** Default retention for terminal task records before maintenance prunes them. */
export const DEFAULT_TASK_RETENTION_MS = 7 * 24 * 60 * 60_000;
export const LOST_TASK_RETENTION_MS = 24 * 60 * 60_000;
const DEFAULT_TASK_RETENTION_MS = 7 * 24 * 60 * 60_000;
const LOST_TASK_RETENTION_MS = 24 * 60 * 60_000;
export function resolveTaskRetentionMs(status: TaskStatus): number {
return status === "lost" ? LOST_TASK_RETENTION_MS : DEFAULT_TASK_RETENTION_MS;