Build a Mini Agent
Translation in Progress
This page is being translated. Content below is a placeholder.
Goal
Build a working AI Agent from scratch:
- Interact with Gemini API
- Two tools: read file, run command
- Complete Agent loop
About 100 lines of code.
Complete Code
typescript
// mini-agent.ts
import { GoogleGenerativeAI } from '@google/generative-ai'
import * as fs from 'fs/promises'
import { exec } from 'child_process'
import { promisify } from 'util'
const execAsync = promisify(exec)
// ============ 1. Define Tools ============
const tools = {
read_file: {
declaration: {
name: 'read_file',
description: 'Read file contents at the specified path',
parameters: {
type: 'object',
properties: {
path: { type: 'string', description: 'File path' }
},
required: ['path']
}
},
execute: async (args: { path: string }) => {
try {
const content = await fs.readFile(args.path, 'utf-8')
return { content: content.slice(0, 5000) }
} catch (e: any) {
return { error: `Read failed: ${e.message}` }
}
}
},
run_command: {
declaration: {
name: 'run_command',
description: 'Execute a shell command and return output',
parameters: {
type: 'object',
properties: {
command: { type: 'string', description: 'Command to execute' }
},
required: ['command']
}
},
execute: async (args: { command: string }) => {
try {
const { stdout, stderr } = await execAsync(args.command, {
timeout: 30000
})
return { stdout, stderr }
} catch (e: any) {
return { error: `Command failed: ${e.message}` }
}
}
}
}
// ============ 2. Initialize Gemini ============
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!)
const model = genAI.getGenerativeModel({
model: 'gemini-2.5-flash',
systemInstruction: `You are a coding assistant. You can read files and run commands to help users.
Do one thing at a time, then report the result.`,
tools: [{
functionDeclarations: Object.values(tools).map(t => t.declaration)
}]
})
// ============ 3. Agent Loop ============
const MAX_TURNS = 10
async function runAgent(userMessage: string): Promise<string> {
const chat = model.startChat()
let response = await chat.sendMessage(userMessage)
let turns = 0
while (turns < MAX_TURNS) {
turns++
const functionCalls = response.response.functionCalls()
if (!functionCalls || functionCalls.length === 0) {
return response.response.text()
}
const results: any[] = []
for (const call of functionCalls) {
console.log(`[Tool] ${call.name}(${JSON.stringify(call.args)})`)
const tool = tools[call.name as keyof typeof tools]
if (!tool) {
results.push({
functionResponse: {
name: call.name,
response: { error: `Unknown tool: ${call.name}` }
}
})
continue
}
const result = await tool.execute(call.args as any)
console.log(`[Result] ${JSON.stringify(result).slice(0, 200)}...`)
results.push({
functionResponse: {
name: call.name,
response: result
}
})
}
response = await chat.sendMessage(results)
}
return 'Maximum turns reached'
}
// ============ 4. Run ============
async function main() {
const task = process.argv[2] || 'List files in current directory'
console.log(`\nTask: ${task}\n`)
console.log('---')
const result = await runAgent(task)
console.log('---')
console.log(`\nResponse:\n${result}`)
}
main().catch(console.error)Running
bash
export GEMINI_API_KEY=your-api-key
npx ts-node mini-agent.ts "Read package.json and tell me the project name"Summary
This mini Agent demonstrates:
- Define tools with schema and execute function
- Initialize model with tools
- Agent loop: send → check tools → execute → repeat
- Exit when no more tool calls
Next
Add more features: Extending →