sakura-agent 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +207 -77
  2. package/README.zh-CN.md +208 -78
  3. package/THIRD_PARTY_NOTICES.md +8 -58
  4. package/dist/packages/agent/src/index.d.ts +49 -11
  5. package/dist/packages/agent/src/index.js +50 -55
  6. package/dist/packages/agent/src/restrict-tools.d.ts +6 -0
  7. package/dist/packages/agent/src/restrict-tools.js +11 -0
  8. package/dist/packages/agent/src/system-prompt.d.ts +5 -0
  9. package/dist/packages/agent/src/system-prompt.js +1 -1
  10. package/dist/packages/agent/src/wake.d.ts +41 -0
  11. package/dist/packages/agent/src/wake.js +71 -0
  12. package/dist/packages/env/src/confine.d.ts +13 -0
  13. package/dist/packages/env/src/confine.js +40 -0
  14. package/dist/packages/env/src/connect-ssh.d.ts +45 -0
  15. package/dist/packages/env/src/connect-ssh.js +242 -0
  16. package/dist/packages/env/src/index.d.ts +6 -1
  17. package/dist/packages/env/src/index.js +3 -1
  18. package/dist/packages/env/src/local.d.ts +11 -2
  19. package/dist/packages/env/src/local.js +42 -10
  20. package/dist/packages/env/src/remote-stream.d.ts +48 -0
  21. package/dist/packages/env/src/remote-stream.js +143 -0
  22. package/dist/packages/env/src/remote-types.d.ts +17 -0
  23. package/dist/packages/env/src/remote-types.js +10 -0
  24. package/dist/packages/env/src/remote.d.ts +16 -7
  25. package/dist/packages/env/src/remote.js +73 -10
  26. package/dist/packages/evals/src/bfcl.d.ts +24 -0
  27. package/dist/packages/evals/src/bfcl.js +71 -0
  28. package/dist/packages/evals/src/index.d.ts +3 -0
  29. package/dist/packages/evals/src/index.js +2 -0
  30. package/dist/packages/evals/src/png.d.ts +2 -0
  31. package/dist/packages/evals/src/png.js +30 -0
  32. package/dist/packages/evals/src/pool.d.ts +3 -0
  33. package/dist/packages/evals/src/pool.js +22 -0
  34. package/dist/packages/evals/src/providers.d.ts +13 -0
  35. package/dist/packages/evals/src/providers.js +23 -0
  36. package/dist/packages/kernel/src/compaction.d.ts +24 -3
  37. package/dist/packages/kernel/src/compaction.js +23 -16
  38. package/dist/packages/kernel/src/goal.d.ts +10 -1
  39. package/dist/packages/kernel/src/goal.js +28 -0
  40. package/dist/packages/kernel/src/hooks.d.ts +5 -0
  41. package/dist/packages/kernel/src/hooks.js +21 -1
  42. package/dist/packages/kernel/src/index.d.ts +3 -2
  43. package/dist/packages/kernel/src/index.js +1 -0
  44. package/dist/packages/kernel/src/loop.d.ts +28 -4
  45. package/dist/packages/kernel/src/loop.js +69 -47
  46. package/dist/packages/kernel/src/types.d.ts +25 -4
  47. package/dist/packages/kernel/src/usage.d.ts +3 -0
  48. package/dist/packages/kernel/src/usage.js +16 -0
  49. package/dist/packages/llm/src/chat/errors.d.ts +11 -0
  50. package/dist/packages/llm/src/chat/errors.js +17 -0
  51. package/dist/packages/llm/src/chat/request.js +22 -4
  52. package/dist/packages/llm/src/chat/retry.d.ts +1 -1
  53. package/dist/packages/llm/src/chat/retry.js +1 -1
  54. package/dist/packages/llm/src/chat/stream.js +2 -1
  55. package/dist/packages/llm/src/index.js +7 -2
  56. package/dist/packages/plugins/context/src/index.d.ts +2 -1
  57. package/dist/packages/plugins/context/src/index.js +2 -1
  58. package/dist/packages/plugins/limits/src/index.d.ts +4 -1
  59. package/dist/packages/plugins/redaction/src/index.d.ts +3 -0
  60. package/dist/packages/plugins/redaction/src/index.js +3 -0
  61. package/dist/packages/plugins/redaction/src/rules.gen.js +1 -1
  62. package/dist/packages/plugins/review/src/chain.d.ts +10 -1
  63. package/dist/packages/plugins/review/src/chain.js +7 -4
  64. package/dist/packages/plugins/review/src/hard-rules.d.ts +6 -0
  65. package/dist/packages/plugins/review/src/hard-rules.js +58 -25
  66. package/dist/packages/plugins/review/src/index.d.ts +21 -0
  67. package/dist/packages/plugins/review/src/index.js +42 -7
  68. package/dist/packages/plugins/review/src/reviewer.d.ts +32 -3
  69. package/dist/packages/plugins/review/src/reviewer.js +115 -27
  70. package/dist/packages/plugins/tools/src/builtin/bash.js +24 -10
  71. package/dist/packages/plugins/tools/src/builtin/image.d.ts +11 -0
  72. package/dist/packages/plugins/tools/src/builtin/image.js +84 -0
  73. package/dist/packages/plugins/tools/src/builtin/read.js +26 -12
  74. package/dist/packages/plugins/toolset/src/codemode.d.ts +17 -6
  75. package/dist/packages/plugins/toolset/src/codemode.js +84 -26
  76. package/dist/packages/plugins/toolset/src/index.d.ts +1 -1
  77. package/dist/packages/plugins/toolset/src/index.js +1 -1
  78. package/dist/packages/plugins/trace/src/index.d.ts +27 -0
  79. package/dist/packages/plugins/trace/src/index.js +29 -0
  80. package/dist/packages/plugins/trace/src/modules.d.ts +6 -0
  81. package/dist/packages/plugins/trace/src/modules.js +28 -0
  82. package/dist/packages/session/src/file-log.d.ts +6 -1
  83. package/dist/packages/session/src/file-log.js +45 -25
  84. package/dist/packages/session/src/fork.d.ts +16 -0
  85. package/dist/packages/session/src/fork.js +70 -0
  86. package/dist/packages/session/src/index.d.ts +2 -0
  87. package/dist/packages/session/src/index.js +1 -0
  88. package/dist/packages/session/src/log-core.d.ts +37 -0
  89. package/dist/packages/session/src/log-core.js +47 -0
  90. package/dist/packages/session/src/memory-log.d.ts +3 -12
  91. package/dist/packages/session/src/memory-log.js +3 -23
  92. package/dist/packages/session/src/projection.js +22 -3
  93. package/dist/packages/testing/src/faux.d.ts +36 -0
  94. package/dist/packages/testing/src/faux.js +69 -0
  95. package/dist/packages/testing/src/index.d.ts +4 -0
  96. package/dist/packages/testing/src/index.js +2 -0
  97. package/dist/packages/testing/src/rng.d.ts +7 -0
  98. package/dist/packages/testing/src/rng.js +17 -0
  99. package/dist/sdk/index.d.ts +11 -3
  100. package/dist/sdk/index.js +5 -1
  101. package/dist/sdk/testing.d.ts +2 -0
  102. package/dist/sdk/testing.js +2 -0
  103. package/package.json +7 -2
package/README.zh-CN.md CHANGED
@@ -2,132 +2,262 @@
2
2
 
3
3
  [English](README.md) · [简体中文](README.zh-CN.md)
4
4
 
5
- **Sakura 是一个可嵌入应用的 TypeScript SDK,用于构建支持会话恢复和可配置工具执行的编程 Agent。**
5
+ **Sakura 把 Codex 式的编程 Agent 做成了库。** 完整的循环(工具、会话、压缩、目标、审核、子 Agent)都在你自己的代码里:定义一个特定用途的 Agent,或者起一群 Agent,只要几行代码,不用折腾配置文件和插件开关。它是 TypeScript 写的,以 `sakura-agent` 这个 npm 包发布,包含 SDK 和一个小的 `sakura` 命令行工具;基于同一个 SDK 做出来的终端是 [`sakuracode`](code/README.md)。
6
6
 
7
- Sakura 源于一个实际需求:让 Agent 在自己的应用里运行,从代码控制模型、会话和工具。`sakura` CLI 使用同一套 SDK,可在终端或脚本里调用。
7
+ ```ts
8
+ import { createAgent } from "sakura-agent";
8
9
 
9
- ## 运行示例
10
+ const agent = await createAgent({ model }); // 就这一行
11
+ const run = agent.run("给 parse() 补上测试,并让测试通过。");
12
+ ```
10
13
 
11
- 使用 Node.js 26 和 npm。
14
+ 这一行得到的已经是一个完整的 Codex 式 Agent:`read`、`write`、`edit`、`bash` 四个工具,项目说明(`AGENTS.md`),上下文快满时自动压缩,截断或为空的回复自动补救,可设置的预算;指定 `sessionFile` 就能续接、分叉和回退,设置 `goal` 就能让它朝一个目标一直做下去。
12
15
 
13
- 已发布的版本可用 `npm install sakura-agent` 安装。下面的命令从源码运行示例。
16
+ ## 为什么用 Sakura
14
17
 
15
- ```sh
16
- git clone https://github.com/Vist233/Sakura.git
17
- cd Sakura
18
- npm ci
19
- npm run example
20
- npm run example:tools
18
+ **你拥有 Codex 式 Agent 的完整内部,而不是一个只能用的成品。** 其余都是它的推论。
19
+
20
+ ### 1. 一行起步,默认就是完整的
21
+
22
+ 不需要先选一堆插件。默认的一套已经是命令行 Agent 该有的;需要更多(审核、脱敏、子 Agent、MCP)时,每一项都是再加一行。
23
+
24
+ ### 2. 特化一个 Agent,是改参数,不是翻开关
25
+
26
+ 一个用途就是几个参数:它在哪个目录、拿到哪些工具、被告知什么、要完成什么。
27
+
28
+ ```ts
29
+ // 只读的审阅 Agent
30
+ await createAgent({ model, tools: ["read"], rules: ["只审阅,不修改任何文件。"] });
31
+
32
+ // 有目标和验证命令的 Agent:验证不通过就不允许停
33
+ await createAgent({ model, goal: { objective: "让所有测试通过", verify: "npm test" } });
34
+
35
+ // 工具跑在另一台机器上,并对在那里运行的命令开启自动审核
36
+ const environment = await createSshEnvironment({ host: "agent@box", cwd: "/srv/job" });
37
+ await createAgent({ model, environment, plugins: [...corePlugins(), reviewPlugin({ llm: reviewerModel })] });
38
+
39
+ // 能派子 Agent 的 Agent(子 Agent 继承审核和脱敏)
40
+ await createAgent({ model, subAgents: {} });
21
41
  ```
22
42
 
23
- 示例默认使用脚本模型。设置 `DEEPSEEK_API_KEY` 后可用 DeepSeek 运行。[工具示例](examples/tools.ts) 会注册一个函数,并显示 Agent 对它的调用。
43
+ ### 3. 起一群 Agent 很便宜
44
+
45
+ 一个 Agent 就是一个对象:自己的工作目录、自己的 `Environment`、自己的会话文件,不读进程的当前目录。所以一群 Agent 就是一个数组加 `Promise.all`:
46
+
47
+ ```ts
48
+ const results = await Promise.all(
49
+ jobs.map(async (job) => {
50
+ const agent = await createAgent({ model, cwd: job.dir, confine: true, tools: job.tools, rules: job.rules, sessionFile: job.session });
51
+ const run = agent.run(job.task);
52
+ for await (const _event of run.events) {} // 在这里把事件写进你自己的日志
53
+ return (await run.result).reason;
54
+ }),
55
+ );
56
+ ```
24
57
 
25
- ## 创建 Agent 并添加工具
58
+ 完整的、可以直接运行的例子在 [`examples/fleet.ts`](examples/fleet.ts)(没有 API 密钥时用脚本化的模型,离线就能跑:`npm run example:fleet`):三个 Agent,分别负责文档、测试、审阅,各在自己的目录里同时运行,只读的审阅 Agent 不可能写出文件。
26
59
 
27
- 安装包后从 `sakura-agent` 导入。本仓库中的相同接口位于 `sdk/index.ts`。下面的示例使用环境变量 `DEEPSEEK_API_KEY`。
60
+ ### 4. 它能到哪里、谁来审、花多少,都是代码里的选项
61
+
62
+ - **能到哪里:** `confine: true` 让文件工具出不了这个目录,不管路径怎么写(绝对路径、`..`、链接);`createSshEnvironment` 用一次 SSH 登录在另一台机器上运行工具;任何能执行 shell 命令的函数都可以做环境。
63
+ - **谁来审:** `review` 插件先用硬规则、再用审核模型判断有风险的工具调用,熔断器会让一直被拒绝的运行停下来,每一次决定都记录在会话日志里。Agent 可以无人值守。没有 shell 的 Agent(只有文件工具和一个回答真或假的检查器)有了限定的目录就够了,不用再运行第二个模型。
64
+ - **花多少:** `limits` 管轮数、token、费用和运行时间。
65
+
66
+ ## 和别的工具比
67
+
68
+ Codex CLI、pi 这样的工具是成品,直接拿来用;Sakura 给你的是成品里面的那些零件,你可以拆开、重新组合、放进自己的产品或者一群 Agent 里。下面依据它们公开的文档(2026 年 11 月)。
69
+
70
+ | | Codex CLI | pi | Sakura |
71
+ |---|---|---|---|
72
+ | 是什么 | 终端 Agent 产品;`exec --json` 用于自动化;可以作为 MCP 服务运行 | “极简、可扩展的 Agent 工具集”;交互、打印 / JSON、RPC 三种模式,有 TypeScript SDK | 以库为主:整个 Agent 在你的代码里;带一个最小命令行和一个单独的终端 |
73
+ | 怎么保证动作安全 | 沙箱模式(只读、工作区可写、完全访问)加批准策略 | 其 README 没有说明 | 带硬规则和熔断器的审核,不需要人;文件工具有 `confine`;自己不带沙箱 |
74
+ | 子 Agent、计划模式 | 没有核对 | 有意不做 | 内置子 Agent(按需开启) |
75
+ | 工具在哪里运行 | 本机,在沙箱里 | 其 README 没有说明 | 本机、SSH,或任何函数,每个 Agent 各自选择 |
76
+ | 模型 | 默认是 OpenAI 的模型 | 用 `/login` 连接内置的服务商 | 任何 Chat Completions 接口(用 DeepSeek、Kimi、OpenCode Go 试过) |
77
+
78
+ 来源:[Codex CLI 文档](https://developers.openai.com/codex)、[pi README](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent)。细节请以它们当前的文档为准,两者都变得很快。
79
+
80
+ ## 适合谁
81
+
82
+ - 你想用代码定义 Agent,并从那里控制它的模型、会话、工具和能触到的范围。
83
+ - 你要起很多个 Agent,每个有特定用途:批处理、远程机器,或者放在你自己的产品里,无人看着也能运行。
84
+ - 你想要把审核和密钥脱敏做成独立、可测试的部件,而不是一个大程序里的开关,以及一个坐下来一次就能读完的循环。
85
+
86
+ 它不是给你自己笔记本用的全能助手(那种需求直接用 [`sakuracode`](code/README.md):`npm install -g sakuracode`),也不带沙箱:默认的本机环境使用调用进程的权限。`confine` 是文件工具的边界,不是 shell 的边界:shell 命令仍然能触到任何地方,所以给 Agent 一个 shell 时要同时开启审核,或者把不可信的任务放在你自己的隔离环境里运行。
87
+
88
+ ## Agent 能触到哪里
28
89
 
29
90
  ```ts
30
- import { compatPresets, corePlugins, createAgent, limitsPlugin } from "sakura-agent";
31
- import type { Plugin } from "sakura-agent";
32
-
33
- const apiKey = process.env.DEEPSEEK_API_KEY;
34
- if (!apiKey) throw new Error("Set DEEPSEEK_API_KEY.");
35
-
36
- const projectTools: Plugin = {
37
- name: "project-tools",
38
- setup(api) {
39
- api.registerTool({
40
- name: "project_status",
41
- description: "Return the status of the sample project.",
42
- parameters: { type: "object", properties: {}, additionalProperties: false },
43
- effect: "read",
44
- async execute() {
45
- return { content: [{ type: "text", text: "Build passed." }] };
46
- },
47
- });
91
+ import { createAgent, createSshEnvironment, corePlugins, reviewPlugin } from "sakura-agent";
92
+ import type { Tool } from "sakura-agent";
93
+
94
+ // 工具就是普通对象
95
+ const checkProof: Tool = {
96
+ name: "check_proof",
97
+ description: "检查 proof.txt,回答 true 或 false。",
98
+ parameters: { type: "object", properties: {}, additionalProperties: false },
99
+ effect: "read",
100
+ async execute(_args, { env }) {
101
+ const proof = new TextDecoder().decode(await env.readFile("proof.txt"));
102
+ return { content: [{ type: "text", text: String(proof.includes("QED")) }] };
48
103
  },
49
104
  };
50
105
 
106
+ // 1. 没有 shell,限定在自己的目录里:不需要审核
107
+ const prover = await createAgent({ model, cwd: "/work/job-17", confine: true, tools: ["read", "write", "edit", checkProof] });
108
+
109
+ // 2. 同一个循环,工具跑在另一台机器上,并对在那里运行的命令开启审核
110
+ const environment = await createSshEnvironment({ host: "agent@box", cwd: "/srv/job-17" });
111
+ const remote = await createAgent({ model, environment, plugins: [...corePlugins(), reviewPlugin({ llm: reviewerModel })] });
112
+ ```
113
+
114
+ ## 我们测过什么
115
+
116
+ 下面是真实运行里测到的数字,每一项都写明了条件。它们描述的是那几次运行,不是保证,供应商的行为也可能变化。
117
+
118
+ | 项目 | 结果 | 条件 |
119
+ |---|---|---|
120
+ | 提示缓存 | 请求的中位数有 **98.8%** 的输入来自供应商缓存;按 token 总量计是 95.7%(不计每次压缩后的第一个请求时是 97.7%) | 一次真实的编码会话,模型 `deepseek-v4.1-flash`,经 OpenCode Go:20.8 小时,1,817 次模型请求。压缩请求和审核请求不在统计内。缓存由供应商负责 |
121
+ | 长时间无人值守 | 连续 **20.8 小时**,1,817 次模型请求,1,766 次工具调用,没有供应商错误,没有崩溃;进程内存稳定在约 160 MB | 同一次会话,统计的是最初这 20.8 小时 |
122
+ | 自动审核 | 之后 15 小时里审核了 **445** 次调用:审核模型**技术失败 0 次**,拒绝 2 次(一次是被取消的运行,一次是 `rm -rf` 工作目录) | 同一次会话,在限制了审核模型对话长度、并且审核失败会重试一次之后。在此之前有 9 次审核因技术原因失败,原因是审核模型自己的对话变得太长 |
123
+ | 基准测试 | Terminal-Bench 2.1 还没有完整分数,所以不公布分数 | 有一次不完整的运行,它不是分数 |
124
+
125
+ 需要知道的一个局限:在同一次会话的后段,供应商在流中途发来的一个错误让运行停了一次。这类错误现在会按同样的 HTTP 状态一样分类并重试。
126
+
127
+ ## 一眼看懂
128
+
129
+ - **是什么:** 供 TypeScript 代码调用的库,外加一个最小的命令行(`sakura run`、`sakura resume`),仓库里还有一个终端。
130
+ - **运行环境:** Node.js 26 及以上。开发时直接运行 TypeScript 源码;npm 包里是编译好的 JavaScript。
131
+ - **模型:** 任何 OpenAI 风格的 Chat Completions 接口(用 DeepSeek、Kimi、OpenCode Go 试过)。只有一种线协议,按模型配置兼容开关。
132
+ - **内核:** 无状态循环、8 个钩子、3 个接口(`LlmClient`、`Log`、`Environment`)、对话压缩和目标。
133
+ - **持久化:** 只追加的树形 JSONL 会话文件;崩溃的运行可以在同一个文件上继续。
134
+ - **默认启用的插件:** `tools`、`context`、`resilience`、`limits`。**按需开启:** `review`、`redaction`、子 Agent、MCP 客户端、工具搜索、代码模式。
135
+ - **安全类插件出错即拒绝:** 审核或脱敏没能完成工作时,动作或请求不会放行。
136
+ - **测试:** 公开仓库里有 5000 多个测试,有对每个接口的所有实现跑同一套用例的契约测试,还有对真实模型和真实 SSH 服务器的实测。
137
+ - **许可:** MIT。
138
+
139
+ ## 怎么搭的
140
+
141
+ ```
142
+ kernel 循环、8 个钩子、3 个接口(LlmClient、Log、Environment)、压缩、目标
143
+ session 会话日志:内存版,或 JSONL 文件(树形、单写者、会修复被截断的最后一行)
144
+ llm 一种协议(Chat Completions):重试、断流重发、卡住检测
145
+ env 工具在哪里运行:本机,或你提供的远程执行器
146
+ agent createAgent():把以上装配起来,带一套默认插件
147
+ plugins/* tools、context、resilience、limits、review、redaction、agents、toolset
148
+ ```
149
+
150
+ - **内核不保存状态。** 它读日志、问模型、跑工具、写日志。崩溃后在同一份日志上重新运行就能恢复;标成 `replay: "never"` 的工具不会被重复执行,而是得到一条"被中断"的结果。
151
+ - **插件只有 8 个钩子可用:** `context`、`request`、`tool.before`、`tool.run`、`tool.after`、`turn.end`、`error`、`event`。插件的形状是 `{ name, compensates?, setup(api), prepare?, afterCompaction? }`;`compensates` 写明它在弥补当今模型的哪个弱点,这样弱点消失后可以删掉它。
152
+ - **包的依赖只有一个方向**(内核 ← 基础设施 ← 插件 ← agent),插件之间不互相引用。有脚本检查(`npm run check:boundaries`),同时还限制每个包的导出名字数量、禁止循环引用。
153
+
154
+ | 插件 | 做什么 | 默认启用 |
155
+ |---|---|---|
156
+ | `tools` | `read`、`write`、`edit`、`bash`(后台命令、`sleep N` 等待、长输出存成文件) | 是 |
157
+ | `context` | 读取 `AGENTS.md` 作为置顶说明,压缩后重读 | 是 |
158
+ | `resilience` | 模型回复在写出任何内容之前就被截断(思考型模型把输出上限全用来思考)、回复为空、或(可选)文字写到一半被截断时,让模型再答一次;每一项都可以单独关掉 | 是 |
159
+ | `limits` | 轮数、token、费用、运行时间预算(运行时间在每个回合结束时检查,不是回合进行中);额度不足时暂停 | 是(默认不限) |
160
+ | `review` | 对有风险的工具调用做自动审核:硬规则、额外授权方、审核模型;出错一律拒绝 | 否 |
161
+ | `redaction` | 请求发出前把密钥换成稳定的占位符,回复里再还原 | 否 |
162
+ | `agents` | `delegate`、`agent_view`、`agent_stop` 三个子 Agent 工具(子 Agent 继承审核和脱敏);用 `subAgents` 选项开启 | 否 |
163
+ | `toolset` | BM25 工具搜索、MCP 客户端(stdio)、代码模式(让模型写脚本一次调用多个工具,脚本在隔离的 JavaScript 运行环境里执行);用 `mcp` 选项开启 | 否 |
164
+
165
+ ## 安装和运行
166
+
167
+ ```sh
168
+ npm install sakura-agent
169
+ ```
170
+
171
+ ```ts
172
+ import { compatPresets, createAgent } from "sakura-agent";
173
+
51
174
  const agent = await createAgent({
52
- model: {
53
- baseUrl: "https://api.deepseek.com",
54
- apiKey,
55
- model: "deepseek-flash",
56
- contextWindow: 128_000,
57
- compat: compatPresets.deepseek,
58
- },
59
175
  cwd: process.cwd(),
176
+ model: { baseUrl: "https://api.deepseek.com", apiKey: process.env.DEEPSEEK_API_KEY!, model: "deepseek-flash", contextWindow: 128_000, compat: compatPresets.deepseek },
60
177
  tools: ["read"],
61
- plugins: [
62
- ...corePlugins().filter((plugin) => plugin.name !== "limits"),
63
- limitsPlugin({ maxTurns: 8 }),
64
- projectTools,
65
- ],
66
- sessionFile: ".sakura/session.jsonl",
67
- maxTokens: 1_024,
178
+ sessionFile: ".sakura/session.jsonl", // 不写则会话只放在内存里
68
179
  });
69
-
70
180
  try {
71
- const run = agent.run("Call project_status and tell me the result.");
181
+ const run = agent.run("总结一下 README.md。");
72
182
  for await (const event of run.events) {
73
- if (event.type === "tool_start") console.log(event.call.name);
183
+ if (event.type === "tool_start") console.log("tool:", event.call.name);
74
184
  if (event.type === "message_end" && event.message.role === "assistant") {
75
185
  for (const part of event.message.content) if (part.type === "text") console.log(part.text);
76
186
  }
77
187
  }
78
- console.log(await run.result);
188
+ console.log((await run.result).reason); // "done" | "cancelled" | "paused" | "error"
79
189
  } finally {
80
- await agent.close();
190
+ await agent.close(); // 一定要调用:它会停掉还在后台运行的命令,并释放会话文件锁
81
191
  }
82
192
  ```
83
193
 
84
- | 配置 | 作用 |
85
- | --- | --- |
86
- | `model` | 设置服务地址、密钥、模型名和上下文窗口,也可传入 `LlmClient`。 |
87
- | `tools` | 从 `read`、`write`、`edit`、`bash` 中选择内置工具。传入 `[]` 可关闭。 |
88
- | `plugins` | 注册自定义工具或添加行为。这份列表会替换默认配置,需要的默认插件可从 `corePlugins()` 加回。在 `execute()` 中校验工具参数。 |
89
- | `mcp` | 启动 stdio MCP 服务,并向 Agent 暴露工具。 |
90
- | `cwd`、`environment` | 选择工具的工作目录,或提供自定义执行环境。 |
91
- | `sessionFile` | 把会话保存为 JSONL。恢复时用同一个文件创建 Agent,再调用无参数的 `agent.run()`。 |
92
- | `maxTokens`、`limitsPlugin()` | 设置单次请求的输出上限,以及会话或运行预算。 |
194
+ 要继续一个会话,用同一个 `sessionFile` 创建 Agent,再不带提示词调用 `agent.run()`。
93
195
 
94
- 接入已有 stdio MCP 服务时,把下面的属性加入同一份配置。换成实际的启动命令和参数,再通过 `agent.mcp` 检查启动状态。
196
+ 打开安全类插件和子 Agent:
95
197
 
96
198
  ```ts
97
- mcp: {
98
- servers: {
99
- project: { command: "node", args: ["./your-mcp-server.mjs"] },
100
- },
101
- expose: "direct",
102
- }
199
+ import { corePlugins, createAgent, redactionPlugin, reviewPlugin } from "sakura-agent";
200
+
201
+ const redaction = redactionPlugin({ key: "stable-key" });
202
+ // `model` 和 `reviewerModel` 是模型配置或客户端,写法同上一个例子
203
+ const agent = await createAgent({
204
+ model,
205
+ plugins: [...corePlugins(), redaction, reviewPlugin({ llm: redaction.wrap(reviewerModel) })], // 审核模型也不能看到密钥
206
+ subAgents: {}, // 子 Agent 拿到同样的插件
207
+ mcp: { servers: { files: { command: "npx", args: ["some-mcp-server"] } }, expose: "codemode" }, // 脚本里的调用同样会被审核
208
+ });
103
209
  ```
104
210
 
105
- ## 使用 CLI
211
+ 插件可以包含插件:`bundle("safety", [redaction, review])` 是由两个插件组成的一个插件。`createAgent` 会把每个插件只装一次,按 `requires` 排好顺序,缺依赖、成环或重名时在创建阶段就报错。
106
212
 
107
- 从源码运行时,先执行 `npm run build`,再用 `node dist/sdk/cli.js` 代替 `sakura`。安装包提供 `sakura` 命令。先设置 `DEEPSEEK_API_KEY` 或 `SAKURA_API_KEY`。
213
+ ## 命令行
108
214
 
109
215
  ```sh
110
- sakura run "Read README.md and summarize it" --tools read --session .sakura/demo.jsonl
216
+ sakura run "读 README.md 并总结" --tools read --session .sakura/demo.jsonl
111
217
  sakura resume --tools read --session .sakura/demo.jsonl
112
218
  sakura --help
113
219
  ```
114
220
 
115
- 加 `--json` 可按行输出 JSON。用 `--cwd`、`--base-url`、`--model`、`--context-window` 配置运行。CLI 默认不开放内置工具,使用时按需选择。
221
+ 先设置 `DEEPSEEK_API_KEY` 或 `SAKURA_API_KEY`。不传 `--tools` 时命令行不带任何内置工具。加 `--json` 输出 JSON 行,用 `--cwd`、`--base-url`、`--model`、`--context-window` 配置运行。
222
+
223
+ ## 常见问题
224
+
225
+ **崩溃后怎么恢复?** 会话文件只追加,一条消息完整结束才写一行。在同一个文件上重新运行即可:只读调用如果当时没完成,就直接再跑一次;可能跑了一半的命令得到一条"被中断,请先检查现状"的结果而不是再跑一遍;被截断的最后一行在打开文件时会修复。
116
226
 
117
- ## 选择工具执行位置
227
+ **能自己手动压缩对话吗?** 能。上下文进入模型窗口剩余 17%(且不少于 16384 个 token)时会自动压缩;`agent.run(undefined, { compact: true })` 则立刻压缩,不管多大:把较早的部分写成摘要,较新的部分原样保留,并用 `compaction` 事件告诉你(没有值得总结的内容时没有这个事件)。`agent.run("下一个问题", { compact: true })` 先压缩再回答,新问题不会被写进摘要。
118
228
 
119
- SDK 管理 Agent 循环、模型请求和会话状态。执行环境负责文件与 shell。用 `createLocalEnvironment()` 在本地执行,或给 `createRemoteEnvironment({ cwd, run })` 传入自己的执行器。例如,本地应用可以管理会话,把构建交给装好依赖的 Linux 工作环境。
229
+ **能回到对话的某个早先位置吗?** 能,有两种办法。`agent.rewindTo(条目 id)` 在同一个会话文件里回退:接下来说的话开出新分支,旧分支仍在文件里。`agent.fork(路径, 条目 id)` 把到那个点为止的对话复制成一个新的会话文件,用 `createAgent({ sessionFile: 路径 })` 打开;原会话不变,两边都可以继续。分叉不会把一个回合切成两半:最后一条消息里的工具调用的结果会一起带上。
120
230
 
121
- 默认本地环境沿用进程权限。`cwd` 用于选择工作目录。不受信任的任务应使用隔离执行器。会话文件和 JSON 事件日志可能包含敏感内容。审核与脱敏按需启用,独立的审核客户端需要单独包装脱敏。
231
+ **模型能让命令在后台运行吗?** 能。`bash` 有 `background: true` 参数,任何命令跑过 120 秒也会自动转后台。模型会被告知进程号和输出文件,命令结束时也会被告知。模型可以要求命令结束时叫醒自己(`bash` 调用里写 `wake: true`,不需要就写 `wake: false`);应用用 `createAgent` 的 `wake` 选项设置默认值。一定要调用 `agent.close()`:留着没结束的命令会让 Node 进程一直不退出,`close()`、Ctrl-C 和 `process.exit` 都会停掉它。
122
232
 
123
- ## 验证
233
+ **怎么不让模型看到密钥?** `redaction` 插件在每个请求里把密钥(基于 gitleaks 的规则表加几条通用规则)换成稳定的占位符,在工具运行前把回复里的占位符还原,扫描失败时拒绝发出请求。`redaction.wrap(llm)` 让审核模型得到同样的保护。它保护的是发给模型服务商的内容,不是保存在本机的内容:会话文件、事件和追踪里保留真实值(工具要用它们,恢复会话也是从那个文件读),导出或分享前请先用 `redaction.scrub(text)` 打码。它不能阻止你放行的命令去读它自己进程的环境变量。
124
234
 
125
- 公开 CI 在 Linux 和 macOS 跑离线检查。在一轮独立的本地 DeepSeek Flash 评测中,Sakura 通过了 10 项 Lean 证明检查和 20 项追加日志检查,两项任务合计通过 96 次后台校验。评测使用外部隔离,传输故障后从检查点续跑。
235
+ **自动审核检查什么?** 先是硬规则(留在工作目录内的只读命令放行,删除根目录这类灾难性命令拒绝;指向工作目录之外的只读命令交给审核模型),再是可选的额外授权方,最后是审核模型,按风险和用户授权打分。拒绝会作为工具错误回给 Agent,让它换条路;审核本身出任何故障都按拒绝处理。审核是一道安全网,不是沙箱:它只读命令的文字,跟不到符号链接,也不限制文件访问范围。
236
+
237
+ **思考型模型把输出上限全用来思考怎么办?** 回复会以 `finish_reason: length` 被截断,而且没有文字。默认启用的 `resilience` 插件会发现这种情况,让模型继续,并把下一次请求的 `max_tokens` 加大(翻倍,封顶 32768);重试两次之后让运行结束。空回复会再问一次。`resiliencePlugin({ cutEmpty: false })` 可以关掉其中一项。
238
+
239
+ **支持 MCP 吗?** 作为客户端,走 stdio。工具可以直接声明、通过 BM25 搜索找到,或在代码模式的脚本里调用。
240
+
241
+ **什么是代码模式?脚本已经在隔离的运行环境里了,为什么脚本里的调用还要审核?** 代码模式是让模型写一小段 JavaScript,在一段程序里调用多个工具,而不是每次请求只调一个。这段程序在隔离的 JavaScript 运行环境里执行(QuickJS 编译成 WebAssembly),它只管住**程序本身**碰不到机器,不是命令的沙箱。它调用的工具(一条 shell 命令、一次写文件、一个 MCP 工具)是在这个运行环境之外以完整权限运行的,所以脚本里的一次调用和直接发起同一次调用风险一样。脚本里的调用不经过循环的钩子,所以要明确地去请求审核:装了 `review` 插件,脚本里的每一次调用都会逐个被审核(脚本整体不再重复审核),被拒绝就在脚本里变成一个错误;没装,所有调用直接执行,和没有审核时的直接调用一样。
242
+
243
+ **工具在哪里运行?** 在 `Environment` 里。`createLocalEnvironment()` 使用调用进程的权限;`createRemoteEnvironment({ cwd, run })` 把命令交给你提供的执行器(比如一个容器)。它只是适配器,不是沙箱。`createSshEnvironment({ host, cwd })` 是用于能通过 ssh 到达的机器的适配器:登录一次,所有命令都走这一条连接,并在系统提示里告诉模型它的工具在别处执行、连接可能出问题(出问题时工具结果会如实说明,并给出命令输出所在的位置,绝不会把连接断了说成命令结束了)。认证和主机密钥完全由你的 ssh 配置决定;远端机器需要 `bash`、`base64` 和 `setsid`,所以应当是 Linux 而不是 macOS。在本机,超时、取消和退出会停掉命令以及它启动的所有进程,但停不掉自己开了新会话的进程(比如用 `setsid`);要停掉所有进程,请把命令放进容器。长命令输出和远程脚本保存在工作目录下的 `.sakura/` 里。
244
+
245
+ **哪些模型能用?** 任何支持 Chat Completions(含流式和工具调用)的模型。兼容开关覆盖各家的差异(字段名、推理内容、图片处理)。
246
+
247
+ ## 开发
126
248
 
127
249
  ```sh
128
- npm run check
250
+ npm ci
251
+ npm run check # 边界、类型、lint、格式,然后跑全部测试
252
+ npm run test:unit # 一次一个包(packages/*/test)
253
+ npm run test:contract # 同一套测试跑遍一个接口的所有实现
254
+ npm run test:tools # 仓库规则:依赖方向、导出数量上限、无循环引用
255
+ npm run example # 用脚本化模型跑的快速开始示例
256
+ npm run build # 把 SDK 和命令行编译到 dist/
129
257
  ```
130
258
 
259
+ 所有测试都不调用真实模型。
260
+
131
261
  ## 许可
132
262
 
133
- [MIT](LICENSE) · [第三方许可](THIRD_PARTY_NOTICES.md) · [旧 Python 源码](https://github.com/Vist233/Sakura/tree/3e9b52cca7ff9e69fc6fc5d4b865b5e44ac338dd)
263
+ MIT,见 [LICENSE](LICENSE)。取自其他项目的代码和文字(Pi、OpenAI Codex、gitleaks)登记在 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md),许可证原文在 `licenses/`。早先的 Python 源码保留在仓库历史里。
@@ -1,63 +1,13 @@
1
1
  # Third-party notices
2
2
 
3
- This file registers every piece of third-party code that is copied, ported, or
4
- vendored into this repository. Entries under "Copied or ported" are the authoritative list; the
5
- "Planned sources" table lists upstream projects we may still borrow from.
3
+ Sakura borrows from a few other projects. Where code or text was copied or adapted, the source file says so in its header, and the licence text is kept in `licenses/`.
6
4
 
7
- Rule: borrowing a design idea does not need an entry. Copying or porting code
8
- (including translating it to another language) does. Each ported file must carry
9
- a header comment naming its source, and a check script must fail the build when a
10
- ported file has no header (planned for milestone M0).
5
+ | Project | Licence | What Sakura took |
6
+ |---|---|---|
7
+ | [Pi](https://github.com/badlogic/pi-mono) (Mario Zechner) | MIT | The edit-matching code in `packages/plugins/tools/src/edit-match.ts`, and the wording of the `read`, `write`, `edit` and `bash` tool descriptions, adapted. The structure and some rules of the system prompt follow Pi's. |
8
+ | [gitleaks](https://github.com/gitleaks/gitleaks) (Zachary Rice) | MIT | The secret-detection rules in `packages/plugins/redaction/src/rules.gen.ts`, converted to TypeScript. |
9
+ | [OpenAI Codex](https://github.com/openai/codex) | Apache-2.0 | Ideas only: some task-execution principles in the system prompt, reworded. No code or text is copied. |
11
10
 
12
- ## Copied or ported
11
+ Dependency: [`quickjs-emscripten`](https://github.com/justjake/quickjs-emscripten) (MIT) runs the code-mode scripts. It is installed from npm, not copied.
13
12
 
14
- ### packages/plugins/tools/src/edit-match.ts
15
- - Source: Pi (`pi-mono`), path `packages/coding-agent/src/core/tools/edit-diff.ts`, source snapshot dated 2026-10-04 (npm 1.5.0 was current at the time)
16
- - Licence: MIT
17
- - Copyright: Copyright (c) 2025 Mario Zechner
18
- - Changes: removed the diff-rendering helpers and the file-system and `diff` package imports; restructured into one `applyEdits` function; kept the fuzzy matching, line-ending handling, overlap detection, line-preserving replacement and the error messages
19
- - Licence text: `licenses/pi-mono-MIT.txt`
20
-
21
- ### packages/plugins/tools/src/builtin/{read,write,edit,bash}.ts (tool descriptions)
22
- - Source: Pi (`pi-mono`), `packages/coding-agent/src/core/tools/{read,write,edit,bash}.ts` (description texts); the implementations are written fresh
23
- - Licence: MIT
24
- - Copyright: Copyright (c) 2025 Mario Zechner
25
- - Changes: shortened and reworded for our tool contracts (timeouts, non-interactive commands)
26
- - Licence text: `licenses/pi-mono-MIT.txt`
27
-
28
- ### packages/agent/src/system-prompt.ts (rule texts)
29
- - Source: Pi (`pi-mono`) `packages/coding-agent/src/core/system-prompt.ts` and tool prompt snippets (structure and some rules); OpenAI Codex `codex-rs/protocol/src/prompts/base_instructions/default.md` (task-execution, validation and final-message principles)
30
- - Licence: Pi MIT; Codex Apache-2.0
31
- - Copyright: Copyright (c) 2025 Mario Zechner (Pi); OpenAI (Codex)
32
- - Changes: principles condensed and reworded into 11 general rules plus per-tool rules; no text copied verbatim from Codex; Pi's section layout (preamble, tools, rules, environment) followed
33
- - Licence text: `licenses/pi-mono-MIT.txt`, `licenses/codex-Apache-2.0.txt`
34
-
35
- ### packages/plugins/redaction/src/rules.gen.ts (generated)
36
- - Source: gitleaks (`gitleaks/gitleaks`), `config/gitleaks.toml`, source snapshot dated 2026-11-06. The public workspace includes the generated rule table.
37
- - Licence: MIT
38
- - Copyright: Copyright (c) 2019 Zachary Rice
39
- - Changes: converted by `scripts/gen-secret-rules.py` into TypeScript data (regular expressions translated to JavaScript, 22 of 221 rules skipped because they do not translate; allowlists not used)
40
- - Licence text: `licenses/gitleaks-MIT.txt`
41
-
42
- ## Planned sources (not yet copied)
43
-
44
- | Source | Licence | Upstream | Intended use | Status |
45
- |---|---|---|---|---|
46
- | Pi (`pi-mono`) | MIT, copyright Mario Zechner | `earendil-works/pi` | Edit-tool matching and the read/write/edit/bash tool descriptions are now ported (see below); system-prompt structure may follow; mcp client and codemode ideas | partly copied (see below) |
47
- | Magpie | MIT | `yetone/magpie` | Design reference for redaction (stable placeholders, streaming restore, fail closed). Not a code port any more (decision: only the essence) | not copied |
48
- | gitleaks | MIT (Zachary Rice) | `gitleaks/gitleaks` | Rule table converted for the redaction plugin (see above) | copied (see above) |
49
- | Codex | Apache-2.0 | `openai/codex` | Design reference (guardian reviewer, goal, compaction); base-instructions principles adapted into our system prompt (`protocol/src/prompts/base_instructions/default.md`), with changes noted. Other prompt texts are written fresh; if any text or code is copied, add an entry and keep the Apache-2.0 notice | not copied |
50
- | A2A | Apache-2.0 | `a2aproject/A2A` | Possible future protocol reference | not copied |
51
- | `quickjs-emscripten` | MIT (Fabrice Bellard's QuickJS, Jake Teton-Landis's bindings; checked on npm, all 7 installed packages report MIT) | npm | Runtime dependency of `packages/plugins/toolset` (codemode sandbox). Not copied, only installed. `quickjs-wasi` was the other candidate (also MIT), not used | dependency |
52
- | Mastra | not verified (GitHub reports NOASSERTION) | `mastra-ai/mastra` | Design reference only. **Do not copy code until the licence is read.** | not copied |
53
-
54
- ## Entry format (use when code is actually copied or ported)
55
-
56
- ```
57
- ### <file or component in this repo>
58
- - Source: <repository URL>, path <path>, commit <hash>
59
- - Licence: <SPDX id>
60
- - Copyright: <holder, year>
61
- - Changes: <what was changed or translated>
62
- - Licence text: <path to the full licence text kept in this repository>
63
- ```
13
+ Licence texts: `licenses/pi-mono-MIT.txt`, `licenses/gitleaks-MIT.txt`, `licenses/codex-Apache-2.0.txt`.
@@ -1,8 +1,10 @@
1
1
  import type { ChatCompat } from "../../llm/src/index.js";
2
- import type { CompactionConfig, Environment, LlmClient, Plugin, Prompts, RunHandle, ThinkingLevel, UserInput } from "../../kernel/src/index.js";
2
+ import type { CompactionConfig, ContextStatus, Environment, GoalRecord, LlmClient, Plugin, Prompts, RunHandle, RunOptions, ThinkingLevel, Tool, UsageTotals, UserInput } from "../../kernel/src/index.js";
3
3
  import type { AgentDefinition } from "../../plugins/agents/src/index.js";
4
4
  import type { McpServerConfig, McpServerStatus } from "../../plugins/toolset/src/index.js";
5
5
  import type { RewindableLog } from "../../session/src/index.js";
6
+ import type { WakeSetting } from "./wake.js";
7
+ type BuiltinToolName = "read" | "write" | "edit" | "bash";
6
8
  export interface ModelConfig {
7
9
  /** Base URL without /chat/completions, for example https://api.deepseek.com */
8
10
  baseUrl: string;
@@ -16,15 +18,25 @@ export interface AgentConfig {
16
18
  /** A provider to talk to, or a ready-made client (for tests). */
17
19
  model: ModelConfig | LlmClient;
18
20
  cwd?: string;
19
- tools?: Array<"read" | "write" | "edit" | "bash">;
21
+ /**
22
+ * Keep the file tools inside `cwd`: a read, write, edit or list of anything outside it is refused with an error the model sees, however the path is written
23
+ * (absolute, `..`, a link). For an agent with no shell tool this is the whole boundary, and no review is needed. A shell command can still reach anything,
24
+ * so with `bash` use it together with the review plugin. Only for the default local environment: build `createLocalEnvironment(cwd, { confine: true })` yourself
25
+ * for anything else (giving both is an error).
26
+ */
27
+ confine?: boolean;
28
+ /** The tools the model gets: names of the built-in ones (default all four) and tools you wrote. A kind of sub-agent that lists tool names gets only those, whoever registered them. */
29
+ tools?: Array<BuiltinToolName | Tool>;
20
30
  /** After this many milliseconds a running shell command is moved to the background (default 120000). */
21
31
  bashSoftTimeoutMs?: number;
22
32
  /** How long a command the model starts with `background: true` is watched before it is left to run (default 1000), so that one that fails at once is reported as failed. */
23
33
  bashBackgroundGraceMs?: number;
24
- /** Defaults to corePlugins(). Safety plugins (review, redaction, sandbox, sub-agents) are never in the default set. May contain bundles and plugins that say what they require; see compose(). */
34
+ /** Defaults to corePlugins(). Safety plugins (review, redaction, sub-agents) are never in the default set. May contain bundles and plugins that say what they require; see compose(). */
25
35
  plugins?: Plugin[];
26
36
  /** Replaces the generated system prompt. */
27
37
  system?: string;
38
+ /** Rules added to the generated system prompt, after the built-in ones. Sub-agents get them too. Not used when `system` replaces the prompt. */
39
+ rules?: string[];
28
40
  /** Write the conversation to this JSONL file; without it the conversation lives in memory only. */
29
41
  sessionFile?: string;
30
42
  thinking?: ThinkingLevel;
@@ -41,15 +53,14 @@ export interface AgentConfig {
41
53
  * Wakes the agent by itself. When background work ends (a command moved to the background, a background sub-agent) and no run is going,
42
54
  * a run is started so the agent hears about it; `onRun` receives each such run (to show its events). While work is still pending and the agent
43
55
  * is quiet, it is woken once after `cacheCheckMs` (default 4 minutes, a little under the prompt cache lifetime) to check, and then left alone until something ends.
56
+ * The agent can also ask for it: `bash` takes `wake: true` or `wake: false` for one command, which wins over this setting for that command. With no `wake` here,
57
+ * a command that asked to wake the agent still does, and its run is not shown to anyone (the log has all of it). The check before the cache expires needs this setting.
44
58
  */
45
- wake?: {
46
- onRun(handle: RunHandle): void;
47
- cacheCheckMs?: number;
48
- };
59
+ wake?: WakeSetting;
49
60
  /**
50
61
  * MCP servers, started once when the agent is created (a server that fails is left out and shows in `agent.mcp`). Their tools are named mcp__<server>__<tool>.
51
- * `expose`: "direct" declares every tool to the model; "search" lists only tool_search and tool_call; "codemode" lists only run_code, where read-only
52
- * tools can be called from a script. The default is "direct" up to 10 tools and "search" above.
62
+ * `expose`: "direct" declares every tool to the model; "search" lists only tool_search and tool_call; "codemode" lists only run_code, a script that can call the
63
+ * tools (each call goes through the review plugin when one is installed). The default is "direct" up to 10 tools and "search" above.
53
64
  */
54
65
  mcp?: {
55
66
  servers: Record<string, McpServerConfig>;
@@ -71,14 +82,41 @@ export interface AgentConfig {
71
82
  };
72
83
  }
73
84
  export interface Agent {
74
- /** Starts, resumes or follows up. See Kernel.run. */
75
- run(input?: UserInput): RunHandle;
85
+ /**
86
+ * Starts, resumes or follows up. See Kernel.run. `{ compact: true }` compacts the conversation first, whatever its size: `agent.run(undefined, { compact: true })`
87
+ * is "compact now", and the `compaction` event of the run says it was done.
88
+ */
89
+ run(input?: UserInput, options?: RunOptions): RunHandle;
76
90
  queue(text: string): void;
77
91
  steer(text: string): void;
78
92
  cancel(): void;
79
93
  log: RewindableLog;
80
94
  /** Goes back to an earlier point of the conversation (an entry id from `log.branch()`, or null for the very start); what is said next starts a new branch. */
81
95
  rewindTo(entryId: string | null): void;
96
+ /**
97
+ * Writes the conversation up to an earlier point (an entry id from `log.branch()`; left out, up to now) as a new session file, which is a session of
98
+ * its own: open it with `createAgent({ ...config, sessionFile: path })`. This session is not changed, and both can go on. A turn is not cut in two:
99
+ * the results of the tool calls of the last message copied come with it. Fails if the file exists.
100
+ */
101
+ fork(path: string, upTo?: string): Promise<void>;
102
+ /** What is waiting to be told to the agent and which background work it is waiting for. A host can use it to decide whether to start a run. */
103
+ pending(): {
104
+ signals: string[];
105
+ watching: string[];
106
+ };
107
+ /** The goal of the conversation, as the session file says it is (active, blocked or complete); undefined when there is none. */
108
+ goal(): Promise<GoalRecord | undefined>;
109
+ /** Sets the goal, replacing an earlier one; the next run is checked against it before it may stop. Part of the session, so it survives reopening and fork. Fails while a run is active. */
110
+ setGoal(goal: {
111
+ objective: string;
112
+ verify?: string;
113
+ }): Promise<void>;
114
+ /** Ends the goal (it counts as complete). Fails while a run is active. */
115
+ clearGoal(): Promise<void>;
116
+ /** How full the conversation is now: tokens used, the model's window, what is free, and where compaction starts (undefined when it is off). */
117
+ context(): Promise<ContextStatus>;
118
+ /** What the conversation has spent so far (tokens and replies), counted from the log, so it includes earlier runs of the same session file. */
119
+ usage(): Promise<UsageTotals>;
82
120
  /** How each MCP server did when the agent was created (for the person running it; the model is not told). Empty without `mcp`. */
83
121
  mcp: Record<string, McpServerStatus>;
84
122
  /** Releases the session file lock. */