feat(settings): storage budgets and retention in settings UI, tmdbMaxSize default 5000 (INT-3)
- Automation section gets storage budget, retention and cache TTL cards bound to settings.storage - Metadata section drops deprecated cache.tmdbTtlHours / cache.emptyResultTtlSec / identity.poolArchiveDays inputs - cache.tmdbMaxSize default 256 -> 5000; migration 0051 bumps stored values still at the old default Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
0a8bfbb63e
commit
fe05138c9c
7 files changed
+119
-31
No files matched your search
@@ -5,11 +5,11 @@ import { useUpdateSettings } from "~/api/settings.ts";
|
||||
import { Switch } from "~/components/ui/switch.tsx";
|
||||
import { errorMessage } from "~/lib/api.ts";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
import { num } from "./resource-section.tsx";
|
||||
import { type FormValues, num } from "./resource-section.tsx";
|
||||
import { SettingsBlock } from "./settings-block.tsx";
|
||||
import { type CardSpec, n, SettingsCard, SettingsGate } from "./settings-card.tsx";
|
||||
|
||||
// 自动化分区:总开关、只读对账、缓存水位、每日下载预算、保留天数
|
||||
// 自动化分区:总开关、只读对账、缓存水位、每日下载预算、保留天数、存储预算与保留(CACHE-2)
|
||||
|
||||
const GiB = 1024 ** 3;
|
||||
|
||||
@@ -89,6 +89,88 @@ const RETENTION_CARD: CardSpec = {
|
||||
}),
|
||||
};
|
||||
|
||||
// CACHE-2:存储预算、流水保留期、缓存有效期(settings.storage,docs/runbook/storage.md)
|
||||
const gbField = (k: string, label: string, hint?: string) => ({
|
||||
name: `storage.budgets.${k}`,
|
||||
label,
|
||||
kind: "number" as const,
|
||||
hint,
|
||||
});
|
||||
const dayField = (group: "retentionDays" | "cacheTtl", k: string, label: string, hint?: string) => ({
|
||||
name: `storage.${group}.${k}`,
|
||||
label,
|
||||
kind: "number" as const,
|
||||
hint,
|
||||
});
|
||||
const pick = (v: FormValues, prefix: string, keys: readonly string[]) =>
|
||||
Object.fromEntries(keys.map((k) => [k, num(v[`${prefix}.${k}`])]));
|
||||
|
||||
const BUDGET_KEYS = ["pgDataGb", "pgDataWarnGb", "imagesGb", "backupsGb", "sessionsEvidenceGb"] as const;
|
||||
const STORAGE_BUDGET_CARD: CardSpec = {
|
||||
anchor: "storage",
|
||||
title: "存储预算",
|
||||
description: "超过预算时健康页告警;图片缓存超出容量按最久未访问删除。单位 GB。",
|
||||
fields: [
|
||||
gbField("pgDataGb", "数据库预算", "超过为严重"),
|
||||
gbField("pgDataWarnGb", "数据库告警线", "不高于数据库预算"),
|
||||
gbField("imagesGb", "图片缓存容量"),
|
||||
gbField("backupsGb", "备份目录预算"),
|
||||
gbField("sessionsEvidenceGb", "Agent 会话与截图证据预算"),
|
||||
],
|
||||
fromSettings: (s) => Object.fromEntries(BUDGET_KEYS.map((k) => [`storage.budgets.${k}`, n(s.storage.budgets[k])])),
|
||||
toPatch: (v) => ({ storage: { budgets: pick(v, "storage.budgets", BUDGET_KEYS) } }),
|
||||
};
|
||||
|
||||
const RETENTION_KEYS = [
|
||||
"observation",
|
||||
"sseEvent",
|
||||
"heartbeatHours",
|
||||
"taskRun",
|
||||
"agentEvent",
|
||||
"audit",
|
||||
"capabilityStats",
|
||||
"identityPoolArchive",
|
||||
] as const;
|
||||
const STORAGE_RETENTION_CARD: CardSpec = {
|
||||
anchor: "storage-retention",
|
||||
title: "流水数据保留",
|
||||
description: "到期由定时清理任务分批删除。单位天,心跳为小时。",
|
||||
fields: [
|
||||
dayField("retentionDays", "observation", "Feed 观察"),
|
||||
dayField("retentionDays", "sseEvent", "实时事件"),
|
||||
dayField("retentionDays", "heartbeatHours", "进程心跳(小时)"),
|
||||
dayField("retentionDays", "taskRun", "任务运行记录"),
|
||||
dayField("retentionDays", "agentEvent", "Agent 会话事件", "只删已结束的会话"),
|
||||
dayField("retentionDays", "audit", "审计日志", "能力调用审计除外"),
|
||||
dayField("retentionDays", "capabilityStats", "能力调用统计"),
|
||||
dayField(
|
||||
"retentionDays",
|
||||
"identityPoolArchive",
|
||||
"待识别池归档",
|
||||
"未命中的条目这么久没有新证据就归档,仍可手动指定",
|
||||
),
|
||||
],
|
||||
fromSettings: (s) =>
|
||||
Object.fromEntries(RETENTION_KEYS.map((k) => [`storage.retentionDays.${k}`, n(s.storage.retentionDays[k])])),
|
||||
toPatch: (v) => ({ storage: { retentionDays: pick(v, "storage.retentionDays", RETENTION_KEYS) } }),
|
||||
};
|
||||
|
||||
const TTL_KEYS = ["tmdbSearchDays", "tmdbDetailDays", "tmdbMissDays", "siteDetailDays", "webSearchDays"] as const;
|
||||
const STORAGE_TTL_CARD: CardSpec = {
|
||||
anchor: "storage-ttl",
|
||||
title: "缓存有效期",
|
||||
description: "单位天。追踪中的作品命中 TMDB 详情缓存时自动续期。",
|
||||
fields: [
|
||||
dayField("cacheTtl", "tmdbSearchDays", "TMDB 搜索与识别结果"),
|
||||
dayField("cacheTtl", "tmdbDetailDays", "TMDB 详情"),
|
||||
dayField("cacheTtl", "tmdbMissDays", "TMDB 空结果", "搜索无结果、未识别时的负缓存"),
|
||||
dayField("cacheTtl", "siteDetailDays", "站点详情页内容"),
|
||||
dayField("cacheTtl", "webSearchDays", "网页搜索结果"),
|
||||
],
|
||||
fromSettings: (s) => Object.fromEntries(TTL_KEYS.map((k) => [`storage.cacheTtl.${k}`, n(s.storage.cacheTtl[k])])),
|
||||
toPatch: (v) => ({ storage: { cacheTtl: pick(v, "storage.cacheTtl", TTL_KEYS) } }),
|
||||
};
|
||||
|
||||
function ToggleRow({
|
||||
id,
|
||||
icon,
|
||||
@@ -181,6 +263,9 @@ export function AutomationSection() {
|
||||
<SettingsCard section="automation" spec={CACHE_CARD} settings={s} />
|
||||
<SettingsCard section="automation" spec={BUDGET_CARD} settings={s} />
|
||||
<SettingsCard section="automation" spec={RETENTION_CARD} settings={s} />
|
||||
<SettingsCard section="automation" spec={STORAGE_BUDGET_CARD} settings={s} />
|
||||
<SettingsCard section="automation" spec={STORAGE_RETENTION_CARD} settings={s} />
|
||||
<SettingsCard section="automation" spec={STORAGE_TTL_CARD} settings={s} />
|
||||
</>
|
||||
)}
|
||||
</SettingsGate>
|
||||
|
||||
Reference in new issue
Block a user