feat(agent): 添加 write 工具,支持创建和覆盖写入文件

pi-agent 会话新增 write 工具,路径限制在 books/ 下,
自动创建父目录,safeBooksPath 防路径穿越。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
fanghanjun
2026-04-15 23:11:11 -07:00
parent 038fd8d098
commit 72fa992df8
4 changed files with 41 additions and 1 deletions
+2
View File
@@ -8,6 +8,7 @@ import {
createSubAgentTool,
createReadTool,
createEditTool,
createWriteFileTool,
createGrepTool,
createLsTool,
} from "./agent-tools.js";
@@ -233,6 +234,7 @@ export async function runAgentSession(
createSubAgentTool(pipeline, bookId),
createReadTool(projectRoot),
createEditTool(projectRoot),
createWriteFileTool(projectRoot),
createGrepTool(projectRoot),
createLsTool(projectRoot),
],
@@ -78,6 +78,7 @@ export function buildAgentSystemPrompt(bookId: string | null, language: string):
- agent="exporter" 导出书籍(参数:format: txt/md/epub, approvedOnly: true/false
- **read** — 读取书籍的设定文件或章节内容
- **edit** — 编辑设定文件(如修改角色名、调整世界观)
- **write** — 创建新文件或覆盖写入已有文件
- **grep** — 搜索内容(如"哪一章提到了某个角色")
- **ls** — 列出文件或章节
@@ -119,6 +120,7 @@ export function buildAgentSystemPrompt(bookId: string | null, language: string):
- agent="exporter" export book (params: format: txt/md/epub, approvedOnly: true/false)
- **read** — Read truth files or chapter content
- **edit** — Edit truth files (rename characters, adjust world settings)
- **write** — Create a new file or overwrite an existing file
- **grep** — Search content across chapters
- **ls** — List files or chapters
+36
View File
@@ -247,6 +247,42 @@ export function createEditTool(projectRoot: string): AgentTool<typeof EditParams
};
}
// ---------------------------------------------------------------------------
// 3b. Write File Tool
// ---------------------------------------------------------------------------
const WriteFileParams = Type.Object({
path: Type.String({ description: "File path relative to books/" }),
content: Type.String({ description: "Full file content to write" }),
});
export function createWriteFileTool(projectRoot: string): AgentTool<typeof WriteFileParams> {
const booksRoot = join(projectRoot, "books");
return {
name: "write",
description:
"Create a new file or overwrite an existing file. " +
"Path is relative to books/. Parent directories are created automatically.",
label: "Write File",
parameters: WriteFileParams,
async execute(
_toolCallId: string,
params: Static<typeof WriteFileParams>,
): Promise<AgentToolResult<undefined>> {
try {
const filePath = safeBooksPath(booksRoot, params.path);
const { mkdir } = await import("node:fs/promises");
await mkdir(resolve(filePath, ".."), { recursive: true });
await writeFile(filePath, params.content, "utf-8");
return textResult(`File "${params.path}" written successfully.`);
} catch (err: any) {
return textResult(`Failed to write "${params.path}": ${err?.message ?? String(err)}`);
}
},
};
}
// ---------------------------------------------------------------------------
// 4. Grep Tool
// ---------------------------------------------------------------------------
+1 -1
View File
@@ -1,3 +1,3 @@
export { buildAgentSystemPrompt } from "./agent-system-prompt.js";
export { createSubAgentTool, createReadTool, createEditTool, createGrepTool, createLsTool } from "./agent-tools.js";
export { createSubAgentTool, createReadTool, createEditTool, createWriteFileTool, createGrepTool, createLsTool } from "./agent-tools.js";
export { runAgentSession, evictAgentCache, type AgentSessionConfig, type AgentSessionResult } from "./agent-session.js";