> Discover all available pages from the documentation index: https://mastra.zisheng.pro/zh-HK/llms.txt # 建立編程 Agent 本指南會教你建立一個小型編程 Agent 應用程式,類型與 Mastra Code、Claude Code 或 Codex 相同。你會使用 `buildBasePrompt()` 和 `createCodingAgent()` 建立編程 Agent,再以 `AgentController` 包裝它,以支援互動式工作階段及 Tool 核准,最後在使用 pi-tui 建立的終端使用者介面中執行控制器。 以下影片展示你將建立的編程 Agent 實際運作情況。 ## 前置要求 - 已安裝 Node.js `v22.19.0` 或更新版本 - 已取得支援的 [Model Provider](https://mastra.zisheng.pro/zh-HK/models) 所提供的 API 金鑰 - 已有 Mastra 項目。如有需要,請按照[安裝指南](https://mastra.zisheng.pro/zh-HK/guides/getting-started/quickstart)設定。 ## 安裝終端依賴套件 安裝 [pi-tui](https://github.com/earendil-works/pi/tree/main/packages/tui) 和 `tsx`: **npm**: ```bash npm install @earendil-works/pi-tui npm install --save-dev tsx ``` **pnpm**: ```bash pnpm add @earendil-works/pi-tui pnpm add --save-dev tsx ``` **Yarn**: ```bash yarn add @earendil-works/pi-tui yarn add --dev tsx ``` **Bun**: ```bash bun add @earendil-works/pi-tui bun add --dev tsx ``` pi-tui 提供終端渲染器及輸入編輯器。`tsx` 會直接執行 TypeScript 入口點。 ## 建立編程 Agent 建立 `src/mastra/agents/coding-agent.ts`。提示會描述目前項目,並將提示中的通用 Tool 名稱對應至預設 Workspace 提供的 Tool。 ```typescript import { basename } from 'node:path' import { buildBasePrompt, createCodingAgent } from '@mastra/core/coding-agent' export const projectPath = process.cwd() const model = 'openai/gpt-5.6-sol' const instructions = buildBasePrompt({ projectPath, projectName: basename(projectPath), platform: process.platform, date: new Date().toISOString().slice(0, 10), mode: 'build', modelId: model, productName: 'My Coding Agent', coAuthorName: 'My Coding Agent', coAuthorEmail: 'coding-agent@example.com', toolGuidance: `# Workspace tools - Use mastra_workspace_read_file for view. - Use mastra_workspace_list_files for find_files. - Use mastra_workspace_grep for search_content. - Use mastra_workspace_execute_command for execute_command. - Use mastra_workspace_write_file, mastra_workspace_edit_file, and mastra_workspace_file_stat for writing, editing, and inspecting file metadata. - Use only the workspace tools provided to you. Do not attempt unavailable capabilities.`, }) export const codingAgent = createCodingAgent({ id: 'coding-agent', name: 'Coding Agent', model, instructions, basePath: projectPath, }) ``` 將品牌值換成你的 Agent 名稱及共同作者資料。`createCodingAgent()` 會提供本機檔案系統及 Sandbox Workspace,並包含從暫時性 Provider 錯誤中恢復的預設設定。`basePath` 會限制檔案系統 Tool 的作用範圍,並設定命令的初始工作目錄。你傳遞至工廠函數的任何設定都會優先於其預設值。 預設本機 Sandbox 會直接在主機上執行命令,並不提供隔離,因此 `basePath` 並非作業系統層面的安全邊界。此範例會在終端為每次 Tool 呼叫加入核准步驟,但你仍只應針對可信任的本機項目執行它。 ## 註冊編程 Agent 與任何其他 Mastra Agent 一樣,在 `src/mastra/index.ts` 註冊傳回的 Agent。註冊後,底層 Agent 亦可在 Studio 及透過 Mastra 伺服器使用。 ```typescript import { Mastra } from '@mastra/core/mastra' import { codingAgent } from './agents/coding-agent' export const mastra = new Mastra({ agents: { codingAgent }, }) ``` ## 測試編程 Agent 加入終端介面前,先在 Studio 驗證底層 Agent。開發伺服器啟動時,其工作目錄是 `src/mastra/public`,因此請在該處加入一個不含敏感資料的檔案,供 Agent 檢查: ```md # Project notes Name: Acme support portal Status: In development Owner: Platform team ``` 啟動開發伺服器: **npm**: ```bash npm run dev ``` **pnpm**: ```bash pnpm run dev ``` **Yarn**: ```bash yarn dev ``` **Bun**: ```bash bun run dev ``` 開啟 [Studio](https://mastra.zisheng.pro/zh-HK/docs/studio/overview),選取 **Coding Agent**,然後輸入: ```text Inspect project-notes.md and report the project name, status, and owner. Do not modify files. ``` 回應應識別出 Acme 支援入口網站及說明其開發狀態,亦應指出項目由 Platform 團隊負責,並保持檔案不變。模型的措辭可能有所不同。 ## 建立 Agent 控制器 建立 `src/mastra/coding-agent-controller.ts`。控制器會管理互動式工作階段、公開使用者介面事件,並暫停 Workspace Tool 以等待核准。 ```typescript import { AgentController } from '@mastra/core/agent-controller' import { codingAgent, projectPath } from './agents/coding-agent' export async function createCodingAgentSession() { const workspace = await codingAgent.getWorkspace() if (!workspace) { throw new Error('The coding agent requires a workspace.') } const controller = new AgentController({ id: 'coding-agent-controller', agent: codingAgent, workspace, modes: [{ id: 'build', name: 'Build', metadata: { default: true } }], disableBuiltinTools: [ 'ask_user', 'submit_plan', 'task_write', 'task_update', 'task_complete', 'task_check', 'subagent', ], }) await controller.init() const session = await controller.createSession({ id: 'local-session', ownerId: 'local-user', resourceId: projectPath, }) return { controller, session } } ``` 此範例只使用一種模式,並停用控制器的額外內置 Tool,讓入門使用者介面集中處理 Workspace 執行。這個簡化設定專為本教學而設。在正式應用程式中,請啟用產品所需的內置 Tool 並實作其使用者介面流程:`ask_user` 和 `submit_plan` 等互動式 Tool 會暫停,直至介面恢復執行;任務及子代理 Tool 則各有自己的生命週期事件。詳情請參閱 [Tool 核准及暫停](https://mastra.zisheng.pro/zh-HK/docs/harness/agent-controller)。 此範例亦省略儲存空間,因此對話只會維持至目前程序結束。如要恢復工作階段,可在之後加入儲存空間。 ## 建立終端使用者介面 建立 `src/coding-agent-tui.ts`。使用者介面會渲染助理訊息更新並顯示 Tool 活動,也會要求使用者核准或拒絕每次 Workspace Tool 呼叫。 ```typescript import { pathToFileURL } from 'node:url' import { Editor, matchesKey, ProcessTerminal, Text, TUI, type EditorTheme, type Terminal, } from '@earendil-works/pi-tui' import { createCodingAgentSession } from './mastra/coding-agent-controller' const plain = (text: string) => text const editorTheme: EditorTheme = { borderColor: plain, selectList: { selectedPrefix: plain, selectedText: plain, description: plain, scrollInfo: plain, noMatch: plain, }, } function getText(message: { content: Array<{ type: string; text?: string }> }) { return message.content .filter(part => part.type === 'text') .map(part => part.text ?? '') .join('') } export async function startCodingAgentTui(terminal: Terminal = new ProcessTerminal()) { const { controller, session } = await createCodingAgentSession() const tui = new TUI(terminal) const output = new Text('Ask me to inspect or change this project.', 1, 0) const editor = new Editor(tui, editorTheme) let busy = false let pendingApproval: { toolCallId: string; toolName: string } | undefined const showError = (error: unknown) => { output.setText(`Error: ${error instanceof Error ? error.message : String(error)}`) busy = false pendingApproval = undefined tui.requestRender() } const unsubscribe = session.subscribe(event => { if (event.type === 'message_update' && event.message.role === 'assistant') { output.setText(getText(event.message)) } else if (event.type === 'tool_start') { output.setText(`Running ${event.toolName}...`) } else if (event.type === 'tool_approval_required') { pendingApproval = { toolCallId: event.toolCallId, toolName: event.toolName } output.setText(`Allow ${event.toolName}? Enter y or n.`) } else if (event.type === 'agent_end') { busy = false } else if (event.type === 'error') { showError(event.error) return } tui.requestRender() }) editor.onSubmit = value => { if (pendingApproval) { const answer = value.trim().toLowerCase() if (answer !== 'y' && answer !== 'n') { output.setText(`Allow ${pendingApproval.toolName}? Enter y or n.`) tui.requestRender() return } const approval = pendingApproval pendingApproval = undefined session.respondToToolApproval({ toolCallId: approval.toolCallId, decision: answer === 'y' ? 'approve' : 'decline', }) return } if (busy || !value.trim()) return busy = true output.setText('Thinking...') tui.requestRender() void session.sendMessage({ content: value.trim() }).catch(showError) } tui.addChild(new Text('My Coding Agent', 1, 0)) tui.addChild(output) tui.addChild(editor) tui.setFocus(editor) let stopPromise: Promise | undefined let removeInputListener = () => {} const stop = () => { stopPromise ??= (async () => { process.off('SIGINT', handleExit) removeInputListener() session.abort() unsubscribe() tui.stop() await controller.destroy() })() return stopPromise } const handleExit = () => { void stop().catch(error => { console.error(error) process.exitCode = 1 }) } removeInputListener = tui.addInputListener(data => { if (!matchesKey(data, 'ctrl+c')) return handleExit() return { consume: true } }) process.once('SIGINT', handleExit) tui.start() return { stop } } if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { await startCodingAgentTui() } ``` 可選的 `Terminal` 參數支援自動化測試,而正常執行時則使用 `ProcessTerminal`。使用者介面刻意只渲染最新回應。`Session` 仍會保留對話內容,以供後續提示使用。 ## 執行編程 Agent 從項目根目錄啟動終端應用程式,讓 `process.cwd()` 指向你希望 Agent 使用的項目: **npm**: ```bash npx tsx src/coding-agent-tui.ts ``` **pnpm**: ```bash pnpm dlx tsx src/coding-agent-tui.ts ``` **Yarn**: ```bash yarn dlx tsx src/coding-agent-tui.ts ``` **Bun**: ```bash bun x tsx src/coding-agent-tui.ts ``` 輸入以下提示: ```text Inspect package.json and report the package name and available scripts. Do not modify files. ``` 當控制器詢問是否允許 `mastra_workspace_read_file` 時,輸入 `y`。Agent 會讀取 `package.json` 並報告當中內容。模型措辭會有所不同,但回應應包括依賴套件名稱及其指令碼,而且不會更改檔案。 按下 **Ctrl+C** 關閉應用程式並銷毀控制器。 ## 後續步驟 你可以透過以下方式擴充這個基礎: - 加入儲存空間,以保存及恢復控制器工作階段 - 加入更多具有不同指示及 Workspace Tool 允許清單的模式 - 將最新回應元件換成可渲染 Tool 呼叫及結果的對話記錄 - 在接受不可信任的提示或發佈應用程式前加入 Sandbox 隔離 深入了解: - [`createCodingAgent()` 參考資料](https://mastra.zisheng.pro/zh-HK/reference/coding-agent/create-coding-agent) - [`buildBasePrompt()` 參考資料](https://mastra.zisheng.pro/zh-HK/reference/coding-agent/build-base-prompt) - [AgentController 概覽](https://mastra.zisheng.pro/zh-HK/docs/harness/agent-controller) - [`AgentController` 參考資料](https://mastra.zisheng.pro/zh-HK/reference/agent-controller/agent-controller-class) - [Workspace 概覽](https://mastra.zisheng.pro/zh-HK/docs/workspace/overview)