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: () => (
), }; 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 (
{(s) => ( <> )} {(s) => }
); }