sakura-agent 0.0.0-stage → 0.1.0

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 (126) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +132 -2
  3. package/README.zh-CN.md +133 -0
  4. package/THIRD_PARTY_NOTICES.md +63 -0
  5. package/dist/packages/agent/src/compose.d.ts +25 -0
  6. package/dist/packages/agent/src/compose.js +91 -0
  7. package/dist/packages/agent/src/index.d.ts +92 -0
  8. package/dist/packages/agent/src/index.js +166 -0
  9. package/dist/packages/agent/src/system-prompt.d.ts +10 -0
  10. package/dist/packages/agent/src/system-prompt.js +49 -0
  11. package/dist/packages/env/src/index.d.ts +3 -0
  12. package/dist/packages/env/src/index.js +2 -0
  13. package/dist/packages/env/src/local.d.ts +3 -0
  14. package/dist/packages/env/src/local.js +174 -0
  15. package/dist/packages/env/src/remote.d.ts +15 -0
  16. package/dist/packages/env/src/remote.js +120 -0
  17. package/dist/packages/kernel/src/channel.d.ts +7 -0
  18. package/dist/packages/kernel/src/channel.js +34 -0
  19. package/dist/packages/kernel/src/compaction.d.ts +25 -0
  20. package/dist/packages/kernel/src/compaction.js +79 -0
  21. package/dist/packages/kernel/src/constants.d.ts +2 -0
  22. package/dist/packages/kernel/src/constants.js +5 -0
  23. package/dist/packages/kernel/src/goal.d.ts +26 -0
  24. package/dist/packages/kernel/src/goal.js +37 -0
  25. package/dist/packages/kernel/src/hooks.d.ts +29 -0
  26. package/dist/packages/kernel/src/hooks.js +133 -0
  27. package/dist/packages/kernel/src/index.d.ts +6 -0
  28. package/dist/packages/kernel/src/index.js +3 -0
  29. package/dist/packages/kernel/src/loop.d.ts +51 -0
  30. package/dist/packages/kernel/src/loop.js +534 -0
  31. package/dist/packages/kernel/src/prompts.d.ts +18 -0
  32. package/dist/packages/kernel/src/prompts.js +99 -0
  33. package/dist/packages/kernel/src/system.d.ts +25 -0
  34. package/dist/packages/kernel/src/system.js +49 -0
  35. package/dist/packages/kernel/src/types.d.ts +377 -0
  36. package/dist/packages/kernel/src/types.js +23 -0
  37. package/dist/packages/llm/src/chat/compat.d.ts +19 -0
  38. package/dist/packages/llm/src/chat/compat.js +16 -0
  39. package/dist/packages/llm/src/chat/errors.d.ts +8 -0
  40. package/dist/packages/llm/src/chat/errors.js +44 -0
  41. package/dist/packages/llm/src/chat/request.d.ts +12 -0
  42. package/dist/packages/llm/src/chat/request.js +91 -0
  43. package/dist/packages/llm/src/chat/retry.d.ts +26 -0
  44. package/dist/packages/llm/src/chat/retry.js +57 -0
  45. package/dist/packages/llm/src/chat/stream.d.ts +17 -0
  46. package/dist/packages/llm/src/chat/stream.js +121 -0
  47. package/dist/packages/llm/src/index.d.ts +45 -0
  48. package/dist/packages/llm/src/index.js +115 -0
  49. package/dist/packages/plugins/agents/src/index.d.ts +33 -0
  50. package/dist/packages/plugins/agents/src/index.js +206 -0
  51. package/dist/packages/plugins/agents/src/view.d.ts +24 -0
  52. package/dist/packages/plugins/agents/src/view.js +60 -0
  53. package/dist/packages/plugins/context/src/index.d.ts +26 -0
  54. package/dist/packages/plugins/context/src/index.js +66 -0
  55. package/dist/packages/plugins/limits/src/cost.d.ts +9 -0
  56. package/dist/packages/plugins/limits/src/cost.js +3 -0
  57. package/dist/packages/plugins/limits/src/index.d.ts +28 -0
  58. package/dist/packages/plugins/limits/src/index.js +31 -0
  59. package/dist/packages/plugins/redaction/src/engine.d.ts +24 -0
  60. package/dist/packages/plugins/redaction/src/engine.js +110 -0
  61. package/dist/packages/plugins/redaction/src/index.d.ts +25 -0
  62. package/dist/packages/plugins/redaction/src/index.js +66 -0
  63. package/dist/packages/plugins/redaction/src/restore.d.ts +6 -0
  64. package/dist/packages/plugins/redaction/src/restore.js +44 -0
  65. package/dist/packages/plugins/redaction/src/rules.gen.d.ts +14 -0
  66. package/dist/packages/plugins/redaction/src/rules.gen.js +2059 -0
  67. package/dist/packages/plugins/resilience/src/index.d.ts +31 -0
  68. package/dist/packages/plugins/resilience/src/index.js +86 -0
  69. package/dist/packages/plugins/review/src/chain.d.ts +31 -0
  70. package/dist/packages/plugins/review/src/chain.js +24 -0
  71. package/dist/packages/plugins/review/src/hard-rules.d.ts +7 -0
  72. package/dist/packages/plugins/review/src/hard-rules.js +123 -0
  73. package/dist/packages/plugins/review/src/index.d.ts +45 -0
  74. package/dist/packages/plugins/review/src/index.js +58 -0
  75. package/dist/packages/plugins/review/src/policy.d.ts +15 -0
  76. package/dist/packages/plugins/review/src/policy.js +65 -0
  77. package/dist/packages/plugins/review/src/reviewer.d.ts +39 -0
  78. package/dist/packages/plugins/review/src/reviewer.js +119 -0
  79. package/dist/packages/plugins/review/src/shell.d.ts +10 -0
  80. package/dist/packages/plugins/review/src/shell.js +124 -0
  81. package/dist/packages/plugins/tools/src/artifacts.d.ts +27 -0
  82. package/dist/packages/plugins/tools/src/artifacts.js +61 -0
  83. package/dist/packages/plugins/tools/src/builtin/args.d.ts +11 -0
  84. package/dist/packages/plugins/tools/src/builtin/args.js +46 -0
  85. package/dist/packages/plugins/tools/src/builtin/bash.d.ts +11 -0
  86. package/dist/packages/plugins/tools/src/builtin/bash.js +96 -0
  87. package/dist/packages/plugins/tools/src/builtin/edit.d.ts +2 -0
  88. package/dist/packages/plugins/tools/src/builtin/edit.js +71 -0
  89. package/dist/packages/plugins/tools/src/builtin/read.d.ts +2 -0
  90. package/dist/packages/plugins/tools/src/builtin/read.js +75 -0
  91. package/dist/packages/plugins/tools/src/builtin/write.d.ts +2 -0
  92. package/dist/packages/plugins/tools/src/builtin/write.js +35 -0
  93. package/dist/packages/plugins/tools/src/edit-match.d.ts +21 -0
  94. package/dist/packages/plugins/tools/src/edit-match.js +159 -0
  95. package/dist/packages/plugins/tools/src/fold.d.ts +16 -0
  96. package/dist/packages/plugins/tools/src/fold.js +65 -0
  97. package/dist/packages/plugins/tools/src/index.d.ts +10 -0
  98. package/dist/packages/plugins/tools/src/index.js +10 -0
  99. package/dist/packages/plugins/toolset/src/bm25.d.ts +8 -0
  100. package/dist/packages/plugins/toolset/src/bm25.js +35 -0
  101. package/dist/packages/plugins/toolset/src/codemode.d.ts +36 -0
  102. package/dist/packages/plugins/toolset/src/codemode.js +168 -0
  103. package/dist/packages/plugins/toolset/src/index.d.ts +6 -0
  104. package/dist/packages/plugins/toolset/src/index.js +3 -0
  105. package/dist/packages/plugins/toolset/src/mcp.d.ts +27 -0
  106. package/dist/packages/plugins/toolset/src/mcp.js +173 -0
  107. package/dist/packages/plugins/toolset/src/search.d.ts +12 -0
  108. package/dist/packages/plugins/toolset/src/search.js +57 -0
  109. package/dist/packages/session/src/file-log.d.ts +20 -0
  110. package/dist/packages/session/src/file-log.js +124 -0
  111. package/dist/packages/session/src/index.d.ts +4 -0
  112. package/dist/packages/session/src/index.js +2 -0
  113. package/dist/packages/session/src/memory-log.d.ts +16 -0
  114. package/dist/packages/session/src/memory-log.js +27 -0
  115. package/dist/packages/session/src/projection.d.ts +2 -0
  116. package/dist/packages/session/src/projection.js +88 -0
  117. package/dist/packages/session/src/tree.d.ts +13 -0
  118. package/dist/packages/session/src/tree.js +35 -0
  119. package/dist/sdk/cli.d.ts +2 -0
  120. package/dist/sdk/cli.js +118 -0
  121. package/dist/sdk/index.d.ts +10 -0
  122. package/dist/sdk/index.js +6 -0
  123. package/licenses/codex-Apache-2.0.txt +201 -0
  124. package/licenses/gitleaks-MIT.txt +21 -0
  125. package/licenses/pi-mono-MIT.txt +21 -0
  126. package/package.json +74 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025–2026 Vist233
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,133 @@
1
- # Temporary Holding Version
1
+ # Sakura
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [English](README.md) · [简体中文](README.zh-CN.md)
4
+
5
+ **Sakura is an embeddable TypeScript SDK for building coding agents with resumable sessions and configurable tool execution.**
6
+
7
+ Sakura grew out of a need to run an agent as part of an application and control its models, sessions, and tools from code. The `sakura` CLI uses the same SDK for terminal and script workflows.
8
+
9
+ ## Run the examples
10
+
11
+ Use Node.js 26 and npm.
12
+
13
+ Install a published version with `npm install sakura-agent`. The commands below run the examples from source.
14
+
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
21
+ ```
22
+
23
+ The examples use a scripted model by default. Set `DEEPSEEK_API_KEY` to run them with DeepSeek. The [tool example](examples/tools.ts) registers a function and shows the agent calling it.
24
+
25
+ ## Create an agent and add tools
26
+
27
+ Import from `sakura-agent` in an installed package. In this repository, the same API is available from `sdk/index.ts`. The following example expects `DEEPSEEK_API_KEY` in the environment.
28
+
29
+ ```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
+ });
48
+ },
49
+ };
50
+
51
+ 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
+ cwd: process.cwd(),
60
+ 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,
68
+ });
69
+
70
+ try {
71
+ const run = agent.run("Call project_status and tell me the result.");
72
+ for await (const event of run.events) {
73
+ if (event.type === "tool_start") console.log(event.call.name);
74
+ if (event.type === "message_end" && event.message.role === "assistant") {
75
+ for (const part of event.message.content) if (part.type === "text") console.log(part.text);
76
+ }
77
+ }
78
+ console.log(await run.result);
79
+ } finally {
80
+ await agent.close();
81
+ }
82
+ ```
83
+
84
+ | Configuration | What it controls |
85
+ | --- | --- |
86
+ | `model` | Provider URL, API key, model name, and context window. You can also pass an `LlmClient`. |
87
+ | `tools` | Selects built-in tools from `read`, `write`, `edit`, and `bash`. Pass `[]` to disable them. |
88
+ | `plugins` | Registers custom tools or adds behavior. This list replaces the defaults, so include the desired `corePlugins()`. Validate tool arguments in `execute()`. |
89
+ | `mcp` | Starts stdio MCP servers and exposes their tools to the agent. |
90
+ | `cwd`, `environment` | Choose the tool working directory or supply a custom execution environment. |
91
+ | `sessionFile` | Saves the session as JSONL. To resume, create an agent with the same file and call `agent.run()` without a prompt. |
92
+ | `maxTokens`, `limitsPlugin()` | Set a per-request output limit and session or run budgets. |
93
+
94
+ For an existing stdio MCP server, add this property to the same configuration. Use your own server command and arguments. Check `agent.mcp` for startup status.
95
+
96
+ ```ts
97
+ mcp: {
98
+ servers: {
99
+ project: { command: "node", args: ["./your-mcp-server.mjs"] },
100
+ },
101
+ expose: "direct",
102
+ }
103
+ ```
104
+
105
+ ## Use the CLI
106
+
107
+ From source, run `npm run build` and use `node dist/sdk/cli.js` in place of `sakura`. An installed package provides the `sakura` executable. Set `DEEPSEEK_API_KEY` or `SAKURA_API_KEY` first.
108
+
109
+ ```sh
110
+ sakura run "Read README.md and summarize it" --tools read --session .sakura/demo.jsonl
111
+ sakura resume --tools read --session .sakura/demo.jsonl
112
+ sakura --help
113
+ ```
114
+
115
+ Add `--json` for JSON lines or use `--cwd`, `--base-url`, `--model`, and `--context-window` to configure the run. The CLI starts with no built-in tools unless you select them.
116
+
117
+ ## Choose where tools run
118
+
119
+ The SDK manages the agent loop, model requests, and session state. The execution environment handles files and shell commands. Use `createLocalEnvironment()` for local execution or `createRemoteEnvironment({ cwd, run })` with a runner you provide. For example, a local application can manage sessions while a Linux worker runs builds with its own dependencies.
120
+
121
+ The default local environment uses the calling process's permissions. `cwd` selects a working directory. Use an isolated runner for untrusted workloads. Session files and JSON event logs can contain sensitive content. Review and redaction are opt-in, and a separate reviewer client needs its own redaction wrapper.
122
+
123
+ ## Validation
124
+
125
+ The public CI runs offline checks on Linux and macOS. In a separate local evaluation with DeepSeek Flash, Sakura passed 10 Lean proof checks and 20 append-log checks. Across both tasks it passed 96 background checks. The evaluation used an external isolation layer and resumed from checkpoints after transport failures.
126
+
127
+ ```sh
128
+ npm run check
129
+ ```
130
+
131
+ ## License
132
+
133
+ [MIT](LICENSE) · [Third-party notices](THIRD_PARTY_NOTICES.md) · [Previous Python source](https://github.com/Vist233/Sakura/tree/3e9b52cca7ff9e69fc6fc5d4b865b5e44ac338dd)
@@ -0,0 +1,133 @@
1
+ # Sakura
2
+
3
+ [English](README.md) · [简体中文](README.zh-CN.md)
4
+
5
+ **Sakura 是一个可嵌入应用的 TypeScript SDK,用于构建支持会话恢复和可配置工具执行的编程 Agent。**
6
+
7
+ Sakura 源于一个实际需求:让 Agent 在自己的应用里运行,从代码控制模型、会话和工具。`sakura` CLI 使用同一套 SDK,可在终端或脚本里调用。
8
+
9
+ ## 运行示例
10
+
11
+ 使用 Node.js 26 和 npm。
12
+
13
+ 已发布的版本可用 `npm install sakura-agent` 安装。下面的命令从源码运行示例。
14
+
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
21
+ ```
22
+
23
+ 示例默认使用脚本模型。设置 `DEEPSEEK_API_KEY` 后可用 DeepSeek 运行。[工具示例](examples/tools.ts) 会注册一个函数,并显示 Agent 对它的调用。
24
+
25
+ ## 创建 Agent 并添加工具
26
+
27
+ 安装包后从 `sakura-agent` 导入。本仓库中的相同接口位于 `sdk/index.ts`。下面的示例使用环境变量 `DEEPSEEK_API_KEY`。
28
+
29
+ ```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
+ });
48
+ },
49
+ };
50
+
51
+ 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
+ cwd: process.cwd(),
60
+ 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,
68
+ });
69
+
70
+ try {
71
+ const run = agent.run("Call project_status and tell me the result.");
72
+ for await (const event of run.events) {
73
+ if (event.type === "tool_start") console.log(event.call.name);
74
+ if (event.type === "message_end" && event.message.role === "assistant") {
75
+ for (const part of event.message.content) if (part.type === "text") console.log(part.text);
76
+ }
77
+ }
78
+ console.log(await run.result);
79
+ } finally {
80
+ await agent.close();
81
+ }
82
+ ```
83
+
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()` | 设置单次请求的输出上限,以及会话或运行预算。 |
93
+
94
+ 接入已有 stdio MCP 服务时,把下面的属性加入同一份配置。换成实际的启动命令和参数,再通过 `agent.mcp` 检查启动状态。
95
+
96
+ ```ts
97
+ mcp: {
98
+ servers: {
99
+ project: { command: "node", args: ["./your-mcp-server.mjs"] },
100
+ },
101
+ expose: "direct",
102
+ }
103
+ ```
104
+
105
+ ## 使用 CLI
106
+
107
+ 从源码运行时,先执行 `npm run build`,再用 `node dist/sdk/cli.js` 代替 `sakura`。安装包提供 `sakura` 命令。先设置 `DEEPSEEK_API_KEY` 或 `SAKURA_API_KEY`。
108
+
109
+ ```sh
110
+ sakura run "Read README.md and summarize it" --tools read --session .sakura/demo.jsonl
111
+ sakura resume --tools read --session .sakura/demo.jsonl
112
+ sakura --help
113
+ ```
114
+
115
+ 加 `--json` 可按行输出 JSON。用 `--cwd`、`--base-url`、`--model`、`--context-window` 配置运行。CLI 默认不开放内置工具,使用时按需选择。
116
+
117
+ ## 选择工具执行位置
118
+
119
+ SDK 管理 Agent 循环、模型请求和会话状态。执行环境负责文件与 shell。用 `createLocalEnvironment()` 在本地执行,或给 `createRemoteEnvironment({ cwd, run })` 传入自己的执行器。例如,本地应用可以管理会话,把构建交给装好依赖的 Linux 工作环境。
120
+
121
+ 默认本地环境沿用进程权限。`cwd` 用于选择工作目录。不受信任的任务应使用隔离执行器。会话文件和 JSON 事件日志可能包含敏感内容。审核与脱敏按需启用,独立的审核客户端需要单独包装脱敏。
122
+
123
+ ## 验证
124
+
125
+ 公开 CI 在 Linux 和 macOS 跑离线检查。在一轮独立的本地 DeepSeek Flash 评测中,Sakura 通过了 10 项 Lean 证明检查和 20 项追加日志检查,两项任务合计通过 96 次后台校验。评测使用外部隔离,传输故障后从检查点续跑。
126
+
127
+ ```sh
128
+ npm run check
129
+ ```
130
+
131
+ ## 许可
132
+
133
+ [MIT](LICENSE) · [第三方许可](THIRD_PARTY_NOTICES.md) · [旧 Python 源码](https://github.com/Vist233/Sakura/tree/3e9b52cca7ff9e69fc6fc5d4b865b5e44ac338dd)
@@ -0,0 +1,63 @@
1
+ # Third-party notices
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.
6
+
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).
11
+
12
+ ## Copied or ported
13
+
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
+ ```
@@ -0,0 +1,25 @@
1
+ import type { Plugin } from "../../kernel/src/index.js";
2
+ /** A plugin that may say what it needs and what it offers. The kernel ignores the two extra fields. */
3
+ export interface Composable extends Plugin {
4
+ /** Names (of plugins or of capabilities that plugins provide) that must be installed before this one. */
5
+ requires?: string[];
6
+ /** Capability names this plugin offers besides its own name, so others can depend on "what" rather than "who". */
7
+ provides?: string[];
8
+ /** Set by bundle(): lets compose() see through the bundle to the plugins inside it. */
9
+ children?: Plugin[];
10
+ }
11
+ /**
12
+ * One plugin made of several: installing it installs them all, in the order given. All three entry points are passed on
13
+ * (setup, prepare, afterCompaction); passing on only setup would silently drop the other two. Bundles may contain bundles.
14
+ * Give a bundle to createAgent (or to compose) and a plugin that is in two bundles is installed once.
15
+ */
16
+ export declare function bundle(name: string, children: Plugin[]): Composable;
17
+ export declare class CompositionError extends Error {
18
+ constructor(message: string);
19
+ }
20
+ /**
21
+ * Turns a list of plugins that may contain and depend on each other into the flat, ordered list the kernel wants: bundles opened up,
22
+ * each plugin once, every plugin after the ones it requires. Throws before anything runs when a requirement is missing, the requirements
23
+ * form a cycle, or two different plugins share a name. Plugins keep the order they were listed in unless a requirement says otherwise.
24
+ */
25
+ export declare function compose(listed: Plugin[]): Plugin[];
@@ -0,0 +1,91 @@
1
+ const unique = (items) => [...new Set(items)];
2
+ /**
3
+ * One plugin made of several: installing it installs them all, in the order given. All three entry points are passed on
4
+ * (setup, prepare, afterCompaction); passing on only setup would silently drop the other two. Bundles may contain bundles.
5
+ * Give a bundle to createAgent (or to compose) and a plugin that is in two bundles is installed once.
6
+ */
7
+ export function bundle(name, children) {
8
+ const compensates = children.flatMap((child) => (child.compensates ? [child.compensates] : []));
9
+ const withPrepare = children.filter((child) => child.prepare);
10
+ const withAfter = children.filter((child) => child.afterCompaction);
11
+ return {
12
+ name,
13
+ children,
14
+ ...(compensates.length > 0 ? { compensates: compensates.join("; ") } : {}),
15
+ requires: unique(children.flatMap((child) => child.requires ?? [])),
16
+ provides: unique(children.flatMap((child) => [child.name, ...(child.provides ?? [])])),
17
+ setup(api) {
18
+ for (const child of children)
19
+ child.setup(api);
20
+ },
21
+ ...(withPrepare.length > 0
22
+ ? {
23
+ async prepare(context) {
24
+ for (const child of withPrepare)
25
+ await child.prepare?.(context);
26
+ },
27
+ }
28
+ : {}),
29
+ ...(withAfter.length > 0
30
+ ? {
31
+ async afterCompaction(context) {
32
+ for (const child of withAfter)
33
+ await child.afterCompaction?.(context);
34
+ },
35
+ }
36
+ : {}),
37
+ };
38
+ }
39
+ export class CompositionError extends Error {
40
+ constructor(message) {
41
+ super(message);
42
+ this.name = "CompositionError";
43
+ }
44
+ }
45
+ /**
46
+ * Turns a list of plugins that may contain and depend on each other into the flat, ordered list the kernel wants: bundles opened up,
47
+ * each plugin once, every plugin after the ones it requires. Throws before anything runs when a requirement is missing, the requirements
48
+ * form a cycle, or two different plugins share a name. Plugins keep the order they were listed in unless a requirement says otherwise.
49
+ */
50
+ export function compose(listed) {
51
+ const providers = new Map(); // capability -> names of the plugins that offer it
52
+ const byName = new Map();
53
+ const open = (plugin, groups) => {
54
+ if (plugin.children) {
55
+ for (const child of plugin.children)
56
+ open(child, [...groups, plugin.name]);
57
+ return;
58
+ }
59
+ const known = byName.get(plugin.name);
60
+ if (known && known !== plugin)
61
+ throw new CompositionError(`two different plugins are named '${plugin.name}'`);
62
+ byName.set(plugin.name, plugin);
63
+ for (const capability of [plugin.name, ...(plugin.provides ?? []), ...groups])
64
+ providers.set(capability, (providers.get(capability) ?? new Set()).add(plugin.name));
65
+ };
66
+ for (const plugin of listed)
67
+ open(plugin, []);
68
+ const ordered = [];
69
+ const state = new Map();
70
+ const visit = (name, path) => {
71
+ if (state.get(name) === "done")
72
+ return;
73
+ if (state.get(name) === "visiting")
74
+ throw new CompositionError(`dependency cycle: ${[...path, name].join(" -> ")}`);
75
+ state.set(name, "visiting");
76
+ const plugin = byName.get(name);
77
+ for (const need of plugin.requires ?? []) {
78
+ const offered = providers.get(need);
79
+ if (!offered)
80
+ throw new CompositionError(`plugin '${name}' requires '${need}', which nothing provides`);
81
+ for (const provider of offered)
82
+ if (provider !== name)
83
+ visit(provider, [...path, name]);
84
+ }
85
+ state.set(name, "done");
86
+ ordered.push(plugin);
87
+ };
88
+ for (const name of byName.keys())
89
+ visit(name, []);
90
+ return ordered;
91
+ }
@@ -0,0 +1,92 @@
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";
3
+ import type { AgentDefinition } from "../../plugins/agents/src/index.js";
4
+ import type { McpServerConfig, McpServerStatus } from "../../plugins/toolset/src/index.js";
5
+ import type { RewindableLog } from "../../session/src/index.js";
6
+ export interface ModelConfig {
7
+ /** Base URL without /chat/completions, for example https://api.deepseek.com */
8
+ baseUrl: string;
9
+ apiKey: string;
10
+ model: string;
11
+ contextWindow: number;
12
+ compat?: Partial<ChatCompat>;
13
+ headers?: Record<string, string>;
14
+ }
15
+ export interface AgentConfig {
16
+ /** A provider to talk to, or a ready-made client (for tests). */
17
+ model: ModelConfig | LlmClient;
18
+ cwd?: string;
19
+ tools?: Array<"read" | "write" | "edit" | "bash">;
20
+ /** After this many milliseconds a running shell command is moved to the background (default 120000). */
21
+ bashSoftTimeoutMs?: number;
22
+ /** 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
+ 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(). */
25
+ plugins?: Plugin[];
26
+ /** Replaces the generated system prompt. */
27
+ system?: string;
28
+ /** Write the conversation to this JSONL file; without it the conversation lives in memory only. */
29
+ sessionFile?: string;
30
+ thinking?: ThinkingLevel;
31
+ maxTokens?: number;
32
+ goal?: {
33
+ objective: string;
34
+ verify?: string;
35
+ };
36
+ compaction?: false | Partial<CompactionConfig>;
37
+ prompts?: Partial<Prompts>;
38
+ environment?: Environment;
39
+ now?: () => number;
40
+ /**
41
+ * 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
+ * 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
+ * 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.
44
+ */
45
+ wake?: {
46
+ onRun(handle: RunHandle): void;
47
+ cacheCheckMs?: number;
48
+ };
49
+ /**
50
+ * 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.
53
+ */
54
+ mcp?: {
55
+ servers: Record<string, McpServerConfig>;
56
+ expose?: "direct" | "search" | "codemode";
57
+ timeoutMs?: number;
58
+ };
59
+ /** Turns on sub-agents (delegate, agent_view, agent_stop). Off unless this is given. */
60
+ subAgents?: {
61
+ agents?: AgentDefinition[];
62
+ maxRegistered?: number;
63
+ maxRunning?: number;
64
+ /**
65
+ * Plugins (by name) that sub-agents do not get. Every other plugin of the agent is shared with its sub-agents, so review and redaction
66
+ * cannot be bypassed by delegating. Default: agents (no nesting), limits (a sub-agent has its own turn limit), context and tools (a sub-agent starts fresh).
67
+ */
68
+ notInherited?: string[];
69
+ /** Models by name, for sub-agent definitions that name one (`AgentDefinition.model`). A definition whose model is not in the table uses the parent's model. */
70
+ models?: Record<string, ModelConfig | LlmClient>;
71
+ };
72
+ }
73
+ export interface Agent {
74
+ /** Starts, resumes or follows up. See Kernel.run. */
75
+ run(input?: UserInput): RunHandle;
76
+ queue(text: string): void;
77
+ steer(text: string): void;
78
+ cancel(): void;
79
+ log: RewindableLog;
80
+ /** 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
+ rewindTo(entryId: string | null): void;
82
+ /** How each MCP server did when the agent was created (for the person running it; the model is not told). Empty without `mcp`. */
83
+ mcp: Record<string, McpServerStatus>;
84
+ /** Releases the session file lock. */
85
+ close(): Promise<void>;
86
+ }
87
+ /** The plugins every agent gets unless the caller passes its own list: project instructions (AGENTS.md), long tool output saved to files, resilience (replies that were cut off or came back empty are asked again), and limits (unlimited until configured). */
88
+ export declare function corePlugins(): Plugin[];
89
+ export declare function createAgent(config: AgentConfig): Promise<Agent>;
90
+ export { buildSystemPrompt } from "./system-prompt.js";
91
+ export { bundle, compose, CompositionError } from "./compose.js";
92
+ export type { Composable } from "./compose.js";