> ## Documentation Index
> Fetch the complete documentation index at: https://docs.openkova.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent 引擎

> 本地 sidecar 运行时、内置工具、会话模式与权限档位、上下文压缩、长期记忆与子代理。

扣瓦的 agent 不在渲染进程里。它跑在一个独立的本地 sidecar 进程中
（`apps/sidecar/pi-agent`，Bun + TypeScript），
通过 stdin/stdout 的 NDJSON 协议与前端通信。
这样做的直接好处是：长任务不会拖垮界面，界面崩溃不会打断正在跑的活儿。

## 一次回合的生命周期

理解 agent 的行为，从这一个循环开始比读任何单个模块都清楚：

<Steps>
  <Step title="组装上下文">
    取当前会话历史，注入长期记忆与已装载技能，附上 @ 提及指向的文件内容
    与附件。是否需要压缩，取决于当前上下文占用了多少。
  </Step>

  <Step title="调用模型">
    把组装好的上下文交给当前选中的模型，拿到增量文本或一组工具调用。
    换模型只影响这一步。
  </Step>

  <Step title="逐个判定工具调用">
    每个调用先过**会话模式**（这一档允许写吗），再过**权限档位**
    （这一档要不要问）。两者都放行才继续。
  </Step>

  <Step title="需要审批就挂起">
    挂起不是丢弃：sidecar 保留回合状态，推一条审批事件给前端，
    你的选择回来之后从同一步继续。被拒绝的调用会作为 blocked 结果回给模型，
    让它换一条路，而不是卡死。
  </Step>

  <Step title="执行并回灌结果">
    工具在 sidecar 内执行，结果作为 tool 消息回灌进上下文，循环回到第二步。
    直到模型不再要求工具，这一回合才结束。
  </Step>

  <Step title="落库">
    转录、工具调用与检查点写入会话存储；长会话触发上下文压缩，
    把早期回合折成摘要。
  </Step>
</Steps>

<Note>
  这个循环里**只有第二步是模型的**，其余全是本地确定性的逻辑。
  这就是为什么换模型不会改变权限行为——审批、压缩、子代理调度都在模型之外。
</Note>

这个循环模型内部跑了多少轮、每轮想干什么、为什么停，默认看不见。
想看清它，见[循环视图](/features/agent-loop)。

## 内置工具

sidecar 注册的工具大致分为这几类：

| 类别 | 工具 | 说明 |
| - | - | - |
| 文件与代码 | `read` `write` `edit` `glob` `grep` | 读写与结构化搜索 |
| 命令执行 | `bash` | 受权限档位与审批规则双重约束 |
| 联网 | `WebFetch` `WebSearch` | 抓取与检索 |
| 浏览器 | 浏览器工具集 | 由 `browser-config.ts` 配置 |
| 网络请求 | HTTP 工具集 | 由 `http-tools.ts` 提供 |
| 图像 | `screenshot` `generate_image` `echo_image` | 截图、生成与回显，含镜像与配置缓存 |
| 交互 | `Question` | agent 反问用户，驱动问答流程 |
| 面板 | `open_plugin_panel` `open_file` | 打开工作台面板或文件 |

`Question` 工具值得单说：它是 agent 主动向用户提问的通道，
在需要澄清需求或确认关键决策时挂起回合，而不是猜一个然后继续。

## 会话模式：能不能改

<CardGroup cols={4}>
  <Card title="agent">完整工具集。默认模式，可以读写文件、跑命令。</Card>
  <Card title="plan">结构性只读。只能读和规划，通过 `plan_exit` 拿到批准后回到 agent 实施。</Card>
  <Card title="ask">纯只读子集，没有 `bash`。适合"就问问，别动手"。</Card>
  <Card title="goal">完整工具集 + 跨轮自治。面向"把这个目标做完"的长任务。</Card>
</CardGroup>

`plan` 模式的设计意图是让规划与实施在**权限上**分开：
读代码阶段拿到的是只读权限，写代码阶段才拿回写权限。

## 权限档位：问不问

<CardGroup cols={4}>
  <Card title="ask">write / edit / bash / 配置类工具，每次都确认。</Card>
  <Card title="workspace-write">工作区内 + 可写根清单内的目录免确认；bash 仍确认，但支持"允许并记住这类命令"。</Card>
  <Card title="auto-edit">写与编辑全部免确认，含工作区外；bash 仍确认。</Card>
  <Card title="auto">全免确认。</Card>
</CardGroup>

这四档就是全部（档位是枚举，不是可调参数；`Shift+Tab` 在它们之间循环）。

### 审批卡的三个按钮

| 按钮 | 语义 |
| - | - |
| 拒绝 | 拦下这次调用，模型收到 blocked 结果 |
| 仅这一次 | 放行这一次，**盘上不留任何东西**，下次仍然问 |
| 允许并记住 | 放行，并写进 `.kova/permissions.local.json`，之后同类不再问 |

"允许并记住"生成的是**前缀规则**，不是精确匹配：

| 记下的命令 | 实际生效的规则 |
| - | - |
| `pnpm add -D react` | `pnpm add *` |
| `git log --oneline` | `git log *` |
| `cat package.json` | `cat *` |
| `lsof -ti:1420`（第二个词就是值，截掉） | `lsof *` |

（不带 `*` 的逐字相等规则仍然有效——那是手工写进清单的形态，UI 只产出前缀规则。）

解释器类与破坏性命令（`node` / `bash` / `npx` / `pnpm dlx` / `sudo` / `rm` / `cp` /
`find`）**不记**——它们的规则第一词之后就是"要执行的代码"或"任意路径"，一次点击
等于永久免问。这类命令的卡上没有第三个按钮，只说明"这一次放行"。

<Warning>
  这些规则必须配三道守卫：**逐段校验**（`git log && rm -rf ~` 的第二段要自己命中
  规则）、**反藏写**（重定向、命令替换、反引号、`$'…'` 一律不命中；重定向的识别按
  shell 的词法走，`echo a${IFS}>f` 也是写）、**转义与引号按 shell 解析**（解析不可信
  就不放行也不记规则）。另加一层**可写根清单**限制"能落到哪些目录"——项目文件只能
  提议、不能自行授权。也就是说，"记住这类命令"永远不会让 agent 获得你手动批准之外
  的新目录写权限。

  同时要坦白一点：`workspace-write` 这档**管不住 bash**。
  命令可以通过 shell 写到工作区之外的任何位置。这一点在
  `docs/permission-modes.md` 里有专门章节说明，不是设计疏漏而是取舍。
</Warning>

### 可写根清单（工作区外也要免确认的目录）

工作区内免确认、工作区外要确认——但真实工作常跨项目（前后端两个目录、monorepo 外的
共享库），每次都弹确认就成了纯噪声。清单解决这个：列进去的目录按"工作区内"对待。
三层文件取并集：

| 层 | 文件 | 效力 |
| - | - | - |
| 用户级 | `~/.kova/permissions.json` | 生效——你机器上的文件 |
| 项目共享 | `<工作区>/.kova/permissions.json` | **只提议，不生效**——跟着仓库走，clone 别人的项目不该让那个仓库给 agent 授权 |
| 项目本地 | `<工作区>/.kova/permissions.local.json` | 生效——本机文件，写入时自动加进 `.git/info/exclude` |

审批卡上点「允许并记住」，写进去的是**本机那份**（local）。也就是说：唯一能授权的
文件都在你自己机器上，结构上不存在可以被仓库伪造的信任状态——项目层声明的根只会
出现在审批卡上那句「这个项目请求放行 X」里。

### 两个维度是分开的

模式决定"能不能改"，档位决定"要不要问"。它们是独立的下拉，组合起来才是最终行为。
把这两件事混为一谈是关于扣瓦最常见的误解。

## 上下文压缩

长会话总会撞上窗口上限。sidecar 的 compaction 会把较早的对话
压缩成摘要，保留关键决策、已产出的文件与未完成的目标，
让任务能继续跑下去而不丢上下文。

## 长期记忆

除了会话内的压缩，扣瓦还有一层跨会话的长期记忆：
在设置 → 记忆里可以查看与编辑历史条目。

记忆分两层存放：全局层在 `~/.kova/memory`（跨会话、跨工作区共享），
工作区层在 `<工作区>/.kova/memory`。会话本身（转录与轨迹）不在这里，
而在应用数据目录下的 `sessions/` 里。

## 子代理

子代理让 agent 把大任务拆开并行处理，而不是在一个上下文里串行做完。

<Steps>
  <Step title="Task">派发一个子代理，带独立的上下文与工具集。</Step>
  <Step title="TaskWait">等待某个子代理完成并取回结果。</Step>
  <Step title="TaskList">列出当前存活的子代理及其状态。</Step>
  <Step title="TaskStop">中止一个正在跑的子代理。</Step>
</Steps>

子代理定义的本机层在 `~/.kova/subagents`，工作区层在 `<工作区>/.kova/subagents`
（可随仓库提交、与团队共享），都可在设置 → 子代理里管理。
发现机制分三层：内置定义、用户自定义、以及插件提供的定义。
子代理活动会被持久化，长任务中途重启也能接上
（见 `docs/subagent-activity-persistence-design.md`）。

## 定时任务与无人值守

自动化（automations）用 [croner](https://github.com/Hexagon/croner) 调度。
定时任务跑在专门的自动化权限档下——没人盯着的时候，
危险档位显然不能默认放开。任务完成还可以通过 Webhook 推送到任意服务。

<Card title="下一步" icon="arrow-right" href="/features/plugins">
  工具之外，还有能直接打开来用的工作台。
</Card>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.