Files
UHD_Media_Tool/apps/web/app/components/settings/agent.tsx
T
rootandClaude Opus 5.5 c57411f9a5 docs(copy): 设置页账户与智能体分区文案按 human-copy 重写
- 改密码后的会话说法统一为「其他会话已退出」
- 模型服务向导里的 provider 统一写「提供方」
- 能力类别「提案」改「方案」;自动调查说明去掉「有界调查」

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
2026-10-07 01:48:45 +08:00

265 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { AgentSpendSummary } from "~/components/status/attention-cards.tsx";
import { kToTokens, tokensToK } from "~/lib/tokens.ts";
import { AgentToolsBlock } from "./agent-tools.tsx";
import { WEBSEARCH_CARD } from "./agent-websearch.tsx";
import { PiUpstreamsBlock } from "./pi-upstreams.tsx";
import type { FieldSpec } from "./resource-section.tsx";
import { num, str } from "./resource-section.tsx";
import { type CardSpec, n, SettingsCard, SettingsGate } from "./settings-card.tsx";
// 智能体分区:模型服务(pi_upstream)→ 用量与限制(不设预算,只有单次防跑飞上限 + 花费统计)→ 自动处理(识别失败自动派智能体、
// 自动调查)→ 上下文与子会话 → 网页搜索 → MCP 服务端与能力清单(agent-tools.tsx)→ 高级
export const RUNTIME_CARD: CardSpec = {
anchor: "runtime",
title: "上下文与子会话",
fields: [
{
name: "pi.contextBudget",
label: "上下文预算",
kind: "tokens",
tokens: { min: 4000, max: 2_000_000, required: true },
hint: "4K–2000K,超过模型窗口时按窗口算",
},
{
name: "pi.subagentsEnabled",
label: "允许子会话",
kind: "switch",
hint: "智能体可以把独立的小目标交给子会话并行做",
},
{
name: "pi.subagents.maxConcurrent",
label: "同时运行的子会话",
kind: "number",
hint: "一个会话最多同时跑几个子会话;1–8",
visible: (v) => v["pi.subagentsEnabled"] === true,
},
{
name: "pi.subagents.maxDepth",
label: "派生层数",
kind: "number",
hint: "1 表示子会话不能再派生;1–3",
visible: (v) => v["pi.subagentsEnabled"] === true,
},
{ 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": tokensToK(s.pi.contextBudget),
"pi.subagentsEnabled": s.pi.subagents?.enabled ?? s.pi.subagentsEnabled,
"pi.subagents.maxConcurrent": n(s.pi.subagents?.maxConcurrent),
"pi.subagents.maxDepth": n(s.pi.subagents?.maxDepth),
"pi.compaction.enabled": s.pi.compaction.enabled,
"pi.compaction.thresholdRatio": n(s.pi.compaction.thresholdRatio),
}),
toPatch: (v) => ({
pi: {
contextBudget: kToTokens(str(v["pi.contextBudget"])),
subagentsEnabled: v["pi.subagentsEnabled"] === true,
subagents: {
enabled: v["pi.subagentsEnabled"] === true,
maxConcurrent: num(v["pi.subagents.maxConcurrent"]),
maxDepth: num(v["pi.subagents.maxDepth"]),
},
compaction: {
enabled: v["pi.compaction.enabled"] === true,
thresholdRatio: num(v["pi.compaction.thresholdRatio"]),
},
},
}),
};
// 2026-10-06:不设每日次数 / 每日花费 / 单次花费 / 单次 token 上限(旧值兼容读取、不生效),
// 只保留单次工具调用次数与时长两个防跑飞限制;花费在这里与运行状态里可见
export const BUDGET_CARD: CardSpec = {
anchor: "budget",
title: "用量与限制",
description: "不限次数和花费。单次运行只限制工具调用次数和时长,防止跑飞。",
fields: [
{ name: "agent.maxToolCalls", label: "单次工具调用上限", kind: "number", hint: "1–500" },
{ name: "agent.maxDurationSec", label: "单次时长上限(秒)", kind: "number" },
],
fromSettings: (s) => ({
"agent.maxToolCalls": n(s.agent.maxToolCalls),
"agent.maxDurationSec": n(s.agent.maxDurationSec),
}),
toPatch: (v) => ({
agent: {
maxToolCalls: num(v["agent.maxToolCalls"]),
maxDurationSec: num(v["agent.maxDurationSec"]),
},
}),
extra: () => (
<div className="border-t border-border/60 pt-4">
<AgentSpendSummary />
</div>
),
};
export const INVESTIGATE_CARD: CardSpec = {
anchor: "investigate",
title: "自动处理",
description: "整理时识别不到作品就叫智能体识别;下载失败、集数对不上时自动发起一次调查,受下面的上限约束。",
fields: [
{
name: "agent.autoIdentifyOrganize",
label: "整理识别不到作品时叫智能体识别",
kind: "switch",
wide: true,
hint: "认出来自动重新整理;认不出的留在整理记录「需要处理」里",
},
{ 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.autoIdentifyOrganize": s.agent.autoIdentifyOrganize,
"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: {
autoIdentifyOrganize: v["agent.autoIdentifyOrganize"] === true,
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"]);
export 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={BUDGET_CARD} settings={s} />
<SettingsCard section="agent" spec={INVESTIGATE_CARD} settings={s} />
<SettingsCard section="agent" spec={RUNTIME_CARD} settings={s} />
<SettingsCard section="agent" spec={WEBSEARCH_CARD} settings={s} />
</>
)}
</SettingsGate>
<AgentToolsBlock />
<SettingsGate>{(s) => <SettingsCard section="agent" spec={ADVANCED_CARD} settings={s} />}</SettingsGate>
</div>
);
}