- 下载面板:下载盘只显示「已用 x / 总量」与进度条,暂停线 / 在途 / 预留 / 可清理 / 做种保留收进详情; 阈值文案统一「暂停线 / 恢复线 / 下载盘满暂停」 - RSS 页去掉与站点页重复的站点表,节标题「RSS 地址」;用途只在非通用时显示 - 订阅:一条都没有时不铺筛选;表单里「空 = 24;0 = 关」等等式改成 placeholder + 一句说明 - 设置:浏览器服务、元数据识别、MCP 说明去掉组件名与实现细节;会话目录与 fake 脚本只在开发构建显示; API Key scope 前加中文名;命名模板变量去掉「MP 无」 - 待处理顶部计数卡改成一行筛选按钮 - 智能体悬浮按钮只在没有侧栏的窄屏出现,抽屉打开时不再显示「收起」胶囊 Co-Authored-By: Claude Opus 5.5 <[email protected]>
236 lines
9.0 KiB
TypeScript
236 lines
9.0 KiB
TypeScript
import { AgentToolsBlock } from "./agent-tools.tsx";
|
||
import { WEBSEARCH_CARD } from "./agent-websearch.tsx";
|
||
import { PiUpstreamsBlock } from "./pi-upstreams.tsx";
|
||
import type { FieldSpec, FieldValue } from "./resource-section.tsx";
|
||
import { num, str } from "./resource-section.tsx";
|
||
import { type CardSpec, n, SettingsCard, SettingsGate } from "./settings-card.tsx";
|
||
|
||
// Agent 分区:上游(pi_upstream)+ 上下文与子代理(pi)+ 预算(budget.agent* 与单次上限)+ 自动调查 + 网页搜索 + 高级
|
||
|
||
/** 可清空的数字:空串 → null */
|
||
const nullNum = (v: FieldValue | undefined) => (str(v) === "" ? null : Number(str(v)));
|
||
|
||
const RUNTIME_CARD: CardSpec = {
|
||
anchor: "runtime",
|
||
title: "上下文与子会话",
|
||
fields: [
|
||
{
|
||
name: "pi.contextBudget",
|
||
label: "上下文预算(token)",
|
||
kind: "number",
|
||
hint: "4096–2000000,超过模型窗口时按窗口算",
|
||
},
|
||
{ name: "pi.subagentsEnabled", label: "允许子会话", kind: "switch" },
|
||
{ name: "pi.compaction.enabled", label: "上下文压缩", kind: "switch" },
|
||
{
|
||
name: "pi.compaction.thresholdRatio",
|
||
label: "压缩触发比例",
|
||
kind: "number",
|
||
hint: "0.3–0.95,用到预算的这个比例时压缩",
|
||
visible: (v) => v["pi.compaction.enabled"] === true,
|
||
},
|
||
],
|
||
fromSettings: (s) => ({
|
||
"pi.contextBudget": n(s.pi.contextBudget),
|
||
"pi.subagentsEnabled": s.pi.subagentsEnabled,
|
||
"pi.compaction.enabled": s.pi.compaction.enabled,
|
||
"pi.compaction.thresholdRatio": n(s.pi.compaction.thresholdRatio),
|
||
}),
|
||
toPatch: (v) => ({
|
||
pi: {
|
||
contextBudget: num(v["pi.contextBudget"]),
|
||
subagentsEnabled: v["pi.subagentsEnabled"] === true,
|
||
compaction: {
|
||
enabled: v["pi.compaction.enabled"] === true,
|
||
thresholdRatio: num(v["pi.compaction.thresholdRatio"]),
|
||
},
|
||
},
|
||
}),
|
||
};
|
||
|
||
const BUDGET_CARD: CardSpec = {
|
||
anchor: "budget",
|
||
title: "预算",
|
||
description: "超出每日预算的运行停在「超出预算」,等你放行。",
|
||
fields: [
|
||
{ name: "budget.agentMaxRunsPerDay", label: "每日运行次数", kind: "number" },
|
||
{ name: "budget.agentMaxCostUsdPerDay", label: "每日费用(USD)", kind: "number" },
|
||
{ name: "agent.maxToolCalls", label: "单次工具调用上限", kind: "number", hint: "1–500" },
|
||
{ name: "agent.maxDurationSec", label: "单次时长上限(秒)", kind: "number" },
|
||
{ name: "agent.maxTokensPerRun", label: "单次 token 上限", kind: "number", hint: "留空不限" },
|
||
{ name: "agent.maxCostUsdPerRun", label: "单次费用上限(USD)", kind: "number", hint: "留空不限" },
|
||
],
|
||
fromSettings: (s) => ({
|
||
"budget.agentMaxRunsPerDay": n(s.budget.agentMaxRunsPerDay),
|
||
"budget.agentMaxCostUsdPerDay": n(s.budget.agentMaxCostUsdPerDay),
|
||
"agent.maxToolCalls": n(s.agent.maxToolCalls),
|
||
"agent.maxDurationSec": n(s.agent.maxDurationSec),
|
||
"agent.maxTokensPerRun": n(s.agent.maxTokensPerRun),
|
||
"agent.maxCostUsdPerRun": n(s.agent.maxCostUsdPerRun),
|
||
}),
|
||
toPatch: (v) => ({
|
||
budget: {
|
||
agentMaxRunsPerDay: num(v["budget.agentMaxRunsPerDay"]),
|
||
agentMaxCostUsdPerDay: num(v["budget.agentMaxCostUsdPerDay"]),
|
||
},
|
||
agent: {
|
||
maxToolCalls: num(v["agent.maxToolCalls"]),
|
||
maxDurationSec: num(v["agent.maxDurationSec"]),
|
||
maxTokensPerRun: nullNum(v["agent.maxTokensPerRun"]),
|
||
maxCostUsdPerRun: nullNum(v["agent.maxCostUsdPerRun"]),
|
||
},
|
||
}),
|
||
};
|
||
|
||
const INVESTIGATE_CARD: CardSpec = {
|
||
anchor: "investigate",
|
||
title: "自动调查",
|
||
description: "待处理事项(没识别出作品、下载失败等)创建时,自动发起一次有界调查。",
|
||
fields: [
|
||
{ name: "agent.autoInvestigate", label: "自动调查", kind: "switch", wide: true },
|
||
{
|
||
name: "agent.autoInvestigateMode",
|
||
label: "模式",
|
||
kind: "select",
|
||
options: [
|
||
{ value: "investigate", label: "只读调查,结论交还给你" },
|
||
{ value: "recover", label: "授权内恢复(重试任务、重新校验、确认识别)" },
|
||
],
|
||
hint: "恢复只在已发布策略或持续授权覆盖时执行,换源、删除、清理始终排除;没有授权时按只读调查",
|
||
wide: true,
|
||
visible: (v) => v["agent.autoInvestigate"] === true,
|
||
},
|
||
{
|
||
name: "agent.investigateMaxToolCalls",
|
||
label: "工具调用上限",
|
||
kind: "number",
|
||
hint: "1–100",
|
||
visible: (v) => v["agent.autoInvestigate"] === true,
|
||
},
|
||
{
|
||
name: "agent.investigateMaxAttempts",
|
||
label: "同一根因最多恢复次数",
|
||
kind: "number",
|
||
hint: "1–10,用完后只交还给你",
|
||
visible: (v) => v["agent.autoInvestigate"] === true && v["agent.autoInvestigateMode"] === "recover",
|
||
},
|
||
{
|
||
name: "agent.recoverVerifySec",
|
||
label: "恢复后核实时长(秒)",
|
||
kind: "number",
|
||
hint: "等下载或任务状态变化的最长时间",
|
||
visible: (v) => v["agent.autoInvestigate"] === true && v["agent.autoInvestigateMode"] === "recover",
|
||
},
|
||
],
|
||
fromSettings: (s) => ({
|
||
"agent.autoInvestigate": s.agent.autoInvestigate,
|
||
"agent.autoInvestigateMode": s.agent.autoInvestigateMode,
|
||
"agent.investigateMaxToolCalls": n(s.agent.investigateMaxToolCalls),
|
||
"agent.investigateMaxAttempts": n(s.agent.investigateMaxAttempts),
|
||
"agent.recoverVerifySec": n(s.agent.recoverVerifySec),
|
||
}),
|
||
toPatch: (v) => ({
|
||
agent: {
|
||
autoInvestigate: v["agent.autoInvestigate"] === true,
|
||
autoInvestigateMode: v["agent.autoInvestigateMode"] === "recover" ? "recover" : "investigate",
|
||
investigateMaxToolCalls: num(v["agent.investigateMaxToolCalls"]),
|
||
investigateMaxAttempts: num(v["agent.investigateMaxAttempts"]),
|
||
recoverVerifySec: num(v["agent.recoverVerifySec"]),
|
||
},
|
||
}),
|
||
};
|
||
|
||
const DEV_ONLY_FIELDS = new Set(["agent.sessionDir", "agent.fakeScript"]);
|
||
|
||
const ADVANCED_CARD: CardSpec = {
|
||
anchor: "advanced",
|
||
title: "高级",
|
||
// 会话目录与 fake 脚本是开发调试项,生产构建不显示(DEAI-2)
|
||
fields: (
|
||
[
|
||
{ name: "agent.goalPollSec", label: "目标轮询间隔(秒)", kind: "number", hint: "等下载、入库结束时的检查间隔" },
|
||
{
|
||
name: "agent.goalWaitHours",
|
||
label: "目标最长等待(小时)",
|
||
kind: "number",
|
||
hint: "超时后按「仍在等待」汇报结束",
|
||
},
|
||
{
|
||
name: "agent.optionsTimeoutSec",
|
||
label: "方案选择等待(秒)",
|
||
kind: "number",
|
||
hint: "智能体给出方案后等你选择的最长时间",
|
||
},
|
||
{
|
||
name: "agent.optionsTimeoutAction",
|
||
label: "超时未选",
|
||
kind: "select",
|
||
options: [
|
||
{ value: "recommended", label: "自动选推荐项" },
|
||
{ value: "stop", label: "不选,智能体收尾" },
|
||
],
|
||
},
|
||
{
|
||
name: "agent.approvalTimeoutSec",
|
||
label: "会话内审批有效期(秒)",
|
||
kind: "number",
|
||
hint: "步骤处的审批卡过期未批准,按拒绝处理",
|
||
},
|
||
{
|
||
name: "agent.sessionDir",
|
||
label: "会话目录",
|
||
kind: "text",
|
||
wide: true,
|
||
placeholder: "留空用 DATA_DIR/agent-sessions",
|
||
hint: "绝对路径,api 与 worker 都要可读写;有运行中的会话时不要改",
|
||
},
|
||
{
|
||
name: "agent.fakeScript",
|
||
label: "fake 脚本(JSON)",
|
||
kind: "textarea",
|
||
hint: "只对 fake 模型服务生效,留空用内置演示脚本;格式见 docs/runbook/agent.md",
|
||
},
|
||
] as FieldSpec[]
|
||
).filter((f) => import.meta.env.DEV || !DEV_ONLY_FIELDS.has(f.name)),
|
||
fromSettings: (s) => ({
|
||
"agent.goalPollSec": n(s.agent.goalPollSec),
|
||
"agent.goalWaitHours": n(s.agent.goalWaitHours),
|
||
"agent.optionsTimeoutSec": n(s.agent.optionsTimeoutSec),
|
||
"agent.optionsTimeoutAction": s.agent.optionsTimeoutAction,
|
||
"agent.approvalTimeoutSec": n(s.agent.approvalTimeoutSec),
|
||
"agent.sessionDir": s.agent.sessionDir ?? "",
|
||
"agent.fakeScript": s.agent.fakeScript ?? "",
|
||
}),
|
||
toPatch: (v) => ({
|
||
agent: {
|
||
goalPollSec: num(v["agent.goalPollSec"]),
|
||
goalWaitHours: num(v["agent.goalWaitHours"]),
|
||
optionsTimeoutSec: num(v["agent.optionsTimeoutSec"]),
|
||
optionsTimeoutAction: v["agent.optionsTimeoutAction"] === "stop" ? "stop" : "recommended",
|
||
approvalTimeoutSec: num(v["agent.approvalTimeoutSec"]),
|
||
sessionDir: str(v["agent.sessionDir"]) || null,
|
||
fakeScript: str(v["agent.fakeScript"]) || null,
|
||
},
|
||
}),
|
||
};
|
||
|
||
export function AgentSection() {
|
||
return (
|
||
<div className="grid grid-cols-1 gap-8">
|
||
<PiUpstreamsBlock />
|
||
<SettingsGate>
|
||
{(s) => (
|
||
<>
|
||
<SettingsCard section="agent" spec={RUNTIME_CARD} settings={s} />
|
||
<SettingsCard section="agent" spec={BUDGET_CARD} settings={s} />
|
||
<SettingsCard section="agent" spec={INVESTIGATE_CARD} settings={s} />
|
||
<SettingsCard section="agent" spec={WEBSEARCH_CARD} settings={s} />
|
||
<SettingsCard section="agent" spec={ADVANCED_CARD} settings={s} />
|
||
</>
|
||
)}
|
||
</SettingsGate>
|
||
<AgentToolsBlock />
|
||
</div>
|
||
);
|
||
}
|