코딩 Agent 구축
이 가이드에서는 Mastra Code, Claude Code 또는 Codex와 동일한 범주에 있는 소규모 코딩 Agent 애플리케이션을 구축합니다. 다음을 사용하여 코딩 Agent를 만듭니다.buildBasePrompt()그리고createCodingAgent(), 그것을 포장AgentController대화형 세션 및 Tool 승인을 위해 pi-tui로 구축된 터미널 UI에서 컨트롤러를 실행합니다.
아래 비디오는 실제로 구축할 코딩 Agent를 보여줍니다.
전제조건전제조건에 대한 직접 링크
- Node.js
v22.19.0이상 설치 - 지원되는 Model Provider의 API 키
- 기존 Mastra 프로젝트. 필요한 경우 설치 가이드를 따르세요.
터미널 종속성 설치터미널 종속성 설치에 대한 직접 링크
pi-tui와 tsx를 설치합니다.
- npm
- pnpm
- Yarn
- Bun
npm install @earendil-works/pi-tui
npm install --save-dev tsx
pnpm add @earendil-works/pi-tui
pnpm add --save-dev tsx
yarn add @earendil-works/pi-tui
yarn add --dev tsx
bun add @earendil-works/pi-tui
bun add --dev tsx
pi-tui는 터미널 렌더러와 입력 편집기를 제공합니다. tsx는 TypeScript 진입점을 직접 실행합니다.
코딩 Agent 만들기코딩 Agent 만들기에 대한 직접 링크
src/mastra/agents/coding-agent.ts를 만듭니다. Prompt는 현재 프로젝트를 설명하고 Prompt의 일반적인 Tool 이름을 기본 Workspace에서 제공하는 Tool에 매핑합니다.
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()는 일시적인 Provider 오류를 복구하기 위한 기본 설정과 함께 로컬 파일 시스템 및 Sandbox Workspace를 제공합니다. basePath는 파일 시스템 Tool의 범위를 제한하고 명령의 초기 작업 디렉터리를 설정합니다. 팩터리에 전달한 구성은 모두 기본값보다 우선합니다.
기본 로컬 Sandbox는 격리 없이 호스트에서 직접 명령을 실행하므로 basePath는 운영 체제 수준의 보안 경계가 아닙니다. 이 예제는 터미널에서 Tool 호출별 승인을 추가하지만, 그래도 신뢰할 수 있는 로컬 프로젝트에서만 실행해야 합니다.
코딩 Agent 등록코딩 Agent 등록에 대한 직접 링크
다른 Mastra Agent와 마찬가지로 반환된 Agent를 src/mastra/index.ts에 등록합니다. 등록하면 기반 Agent를 Studio와 Mastra 서버에서도 사용할 수 있습니다.
import { Mastra } from '@mastra/core/mastra'
import { codingAgent } from './agents/coding-agent'
export const mastra = new Mastra({
agents: { codingAgent },
})
코딩 Agent 테스트코딩 Agent 테스트에 대한 직접 링크
터미널 인터페이스를 추가하기 전에 Studio에서 기본 Agent를 확인하세요. 개발 서버가 시작되면 작업 디렉터리는 src/mastra/public이므로 Agent가 살펴볼 수 있도록 민감하지 않은 파일을 이 디렉터리에 추가하세요.
# Project notes
Name: Acme support portal
Status: In development
Owner: Platform team
개발 서버를 시작합니다.
- npm
- pnpm
- Yarn
- Bun
npm run dev
pnpm run dev
yarn dev
bun run dev
Studio를 열고 Coding Agent를 선택한 후 다음을 입력하세요.
Inspect project-notes.md and report the project name, status, and owner. Do not modify files.
응답에서는 Acme 지원 포털을 식별하고 개발 상태를 설명해야 합니다. 플랫폼 팀이 프로젝트를 소유하고 있음을 보고하고 파일을 변경하지 않은 상태로 두어야 합니다. Model 문구는 다를 수 있습니다.
Agent 컨트롤러 만들기Agent 컨트롤러 만들기에 대한 직접 링크
src/mastra/coding-agent-controller.ts를 만드세요. 컨트롤러는 대화형 세션을 관리하고 UI 이벤트를 노출하며 승인을 위해 Workspace Tool을 일시 중지합니다.
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을 비활성화하여 소개 UI가 Workspace 실행에 집중하도록 합니다. 이 튜토리얼에서는 단순화된 설정을 사용합니다. 프로덕션 애플리케이션에서는 제품에 필요한 내장 Tool을 활성화하고 UI 흐름을 구현하세요. ask_user와 submit_plan은 인터페이스에서 재개할 때까지 일시 중지되며, 작업 및 하위 Agent Tool에는 자체 수명 주기 이벤트가 있습니다. Tool 승인 및 일시 중지를 참조하세요.
이 예에서는 저장 공간도 생략하므로 대화는 현재 프로세스에 대해서만 지속됩니다. 나중에 세션을 재개하고 싶을 때 저장 공간을 추가할 수 있습니다.
터미널 UI 빌드터미널 UI 빌드에 대한 직접 링크
src/coding-agent-tui.ts를 만드세요. UI는 어시스턴트 메시지 업데이트와 Tool 활동을 표시합니다. 또한 각 Workspace Tool 호출을 승인하거나 거부할지 사용자에게 묻습니다.
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<void> | 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을 사용합니다. UI는 의도적으로 최신 응답만 렌더링합니다. Session은 후속 Prompt를 위한 대화 컨텍스트를 계속 유지합니다.
코딩 Agent 실행코딩 Agent 실행에 대한 직접 링크
process.cwd()가 Agent에서 사용할 프로젝트를 가리키도록 프로젝트 루트에서 터미널 애플리케이션을 시작하세요.
- npm
- pnpm
- Yarn
- Bun
npx tsx src/coding-agent-tui.ts
pnpm dlx tsx src/coding-agent-tui.ts
yarn dlx tsx src/coding-agent-tui.ts
bun x tsx src/coding-agent-tui.ts
다음 Prompt를 입력하세요:
Inspect package.json and report the package name and available scripts. Do not modify files.
컨트롤러가 mastra_workspace_read_file의 허용 여부를 물으면 y를 입력하세요. Agent는 package.json을 읽고 확인한 내용을 보고합니다. Model의 표현은 달라질 수 있지만, 파일을 변경하지 않고 패키지 이름과 스크립트를 응답에 포함해야 합니다.
Ctrl+C를 눌러 애플리케이션을 닫고 컨트롤러를 제거하세요.
다음 단계다음 단계에 대한 직접 링크
이 기반을 다음으로 확장할 수 있습니다.
- 컨트롤러 세션을 유지하고 재개하려면 스토리지를 추가하세요.
- 다양한 지침과 작업 공간 Tool 허용 목록을 사용하여 더 많은 모드를 추가하세요.
- 최신 응답 구성 요소를 Tool 호출 및 결과를 렌더링하는 기록으로 교체
- 신뢰할 수 없는 메시지를 수락하거나 애플리케이션을 배포하기 전에 샌드박스 격리를 추가하세요.
자세히 알아보기: