← Back to list

ai-agent-implementation
by omerakben
⭐ 1🍴 0📅 Dec 12, 2025
SKILL.md
name: ai-agent-implementation description: Step-by-step checklist and best practices for implementing new AI agent tools in the omer-akben portfolio. Use when creating new agent tools, API routes, or extending agent capabilities.
AI Agent Implementation Skill
Implementation Checklist
Use this checklist for every new AI agent tool:
Planning Phase
- Define clear tool purpose and triggers
- Design Zod schemas for input/output validation
- Consider rate-limiting requirements
- Plan security measures (validation, sanitization, PII)
- Document environment variables needed
Implementation Phase
- Create API route handler (
src/app/api/tools/[name]/route.ts) - Implement tool schema in
lib/agent-tools/schemas.ts - Add Mastra tool in
lib/mastra/tools.ts(if needed) - Update AI knowledge base (
lib/agent-knowledge-base.ts) - Configure rate-limiting in
lib/rate-limit.ts
Testing Phase
- Write unit tests for API route
- Test Zod schema validation (valid + invalid inputs)
- Manual testing via Playwright for AI behavior
- Verify rate-limiting works correctly
- Test all 6 quality gates pass
Documentation Phase
- Update AGENTS.md with tool details
- Update CLAUDE.md with implementation notes
- Document environment variables in
.env.example - Add lessons learned section
- Update README.md if needed
Deployment Phase
- Configure environment variables in Vercel
- Configure secrets in GitHub Actions
- Create PR with comprehensive description
- Verify CI/CD passes all gates
- Monitor production deployment
Tool Implementation Pattern
1. Create API Route Handler
Location: src/app/api/tools/[tool-name]/route.ts
import { NextRequest } from "next/server";
import { z } from "zod";
import { ratelimit } from "@/lib/rate-limit";
// Define input schema
const inputSchema = z.object({
param1: z.string().min(1).max(100),
param2: z.number().optional(),
});
export async function POST(request: NextRequest) {
try {
// Rate limiting (if needed)
const ip = request.headers.get("x-forwarded-for") ?? "anonymous";
const result = await ratelimit.limit(ip);
if (!result.success) {
return Response.json(
{ error: "Rate limit exceeded" },
{ status: 429 }
);
}
// Parse and validate input
const body = await request.json();
const input = inputSchema.parse(body);
// Implement tool logic
const result = await performToolAction(input);
// Return response
return Response.json(result);
} catch (error) {
console.error("Tool error:", error);
if (error instanceof z.ZodError) {
return Response.json(
{ error: "Invalid input", details: error.errors },
{ status: 400 }
);
}
return Response.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
}
```typescript
### 2. Define Tool Schema
**Location:** `src/lib/agent-tools/schemas.ts`
```typescript
import { z } from "zod";
export const toolNameSchema = z.object({
param1: z.string()
.min(1, "Parameter cannot be empty")
.max(100, "Parameter too long"),
param2: z.number().optional(),
});
export type ToolNameInput = z.infer<typeof toolNameSchema>;
export const toolNameResponseSchema = z.object({
success: z.boolean(),
data: z.unknown(),
message: z.string().optional(),
});
```typescript
### 3. Add to Mastra Tools (if needed)
**Location:** `src/lib/mastra/tools.ts`
```typescript
import { createTool } from "@mastra/core";
import { z } from "zod";
export const toolName = createTool({
id: "tool_name",
description: "Clear description of what this tool does and when to use it",
inputSchema: z.object({
param1: z.string().describe("Description of param1"),
param2: z.number().optional().describe("Optional param2"),
}),
outputSchema: z.object({
success: z.boolean(),
data: z.unknown(),
}),
execute: async ({ context, input }) => {
// Call API route
const response = await fetch("/api/tools/tool-name", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(input),
});
if (!response.ok) {
throw new Error(`Tool failed: ${response.statusText}`);
}
return await response.json();
},
});
```typescript
### 4. Update Knowledge Base
**Location:** `src/lib/agent-knowledge-base.ts`
```typescript
export const AGENT_KNOWLEDGE_BASE = `
...existing knowledge...
## Tool Name
**Purpose:** Clear description of what the tool does
### When to use
- Trigger condition 1
- Trigger condition 2
- Trigger condition 3
### Parameters
- param1 (required): Description
- param2 (optional): Description
### Example usage
"Can you [action]?" → Use tool_name
**Rate limits:** X requests per Y timeframe (if applicable)
`;
```typescript
### 5. Configure Rate Limiting (if needed)
**Location:** `src/lib/rate-limit.ts`
```typescript
export const rateLimits = {
// Existing limits...
toolName: {
limit: 10, // 10 requests
window: 3600, // per hour
},
};
// Create rate limiter
export const toolNameRateLimit = new Ratelimit({
redis,
limiter: Ratelimit.slidingWindow(
rateLimits.toolName.limit,
`${rateLimits.toolName.window}s`
),
prefix: "ratelimit:tool_name",
});
```typescript
## Testing Pattern
### Unit Tests
**Location:** `src/app/api/tools/[tool-name]/__tests__/route.test.ts`
```typescript
import { describe, it, expect, beforeEach, vi } from "vitest";
import { POST } from "../route";
describe("Tool API Route", () => {
beforeEach(() => {
vi.clearAllMocks();
});
describe("Input Validation", () => {
it("should reject invalid input", async () => {
const request = new Request("http://localhost", {
method: "POST",
body: JSON.stringify({ invalid: "data" }),
});
const response = await POST(request);
expect(response.status).toBe(400);
});
it("should accept valid input", async () => {
const request = new Request("http://localhost", {
method: "POST",
body: JSON.stringify({
param1: "valid",
param2: 42,
}),
});
const response = await POST(request);
expect(response.status).toBe(200);
});
});
describe("Rate Limiting", () => {
it("should enforce rate limits", async () => {
// Test rate limit logic
});
});
describe("Tool Logic", () => {
it("should perform expected action", async () => {
// Test tool functionality
});
});
});
```typescript
### E2E Tests
**Location:** `e2e/tools/tool-name.spec.ts`
```typescript
import { test, expect } from "@playwright/test";
test.describe("Tool Name Integration", () => {
test("should trigger tool from chat", async ({ page }) => {
await page.goto("/");
// Open chat
await page.getByRole("button", { name: "Chat" }).click();
// Send message that triggers tool
await page.getByRole("textbox").fill("Trigger phrase");
await page.getByRole("button", { name: "Send" }).click();
// Wait for tool response
await page.waitForSelector('[data-tool="tool_name"]');
// Assert result
await expect(page.getByText("Expected result")).toBeVisible();
});
});
```typescript
## Security Best Practices
### Input Validation
1. **Always use Zod schemas** - Never trust user input
2. **Sanitize strings** - Remove/escape dangerous characters
3. **Validate lengths** - Prevent DoS via large inputs
4. **Check types** - Ensure correct data types
### API Key Protection
1. **Server-side only** - Never expose keys in client
2. **Environment variables** - Use `.env` files
3. **Validate in middleware** - Check keys before processing
4. **Rotate regularly** - Update keys periodically
### Rate Limiting
1. **Apply to all tools** - Prevent abuse
2. **Use IP-based limits** - Track by requester
3. **Sliding window** - More accurate than fixed window
4. **Graceful degradation** - Inform user of limits
### PII Handling
1. **Minimize collection** - Only collect necessary data
2. **Validate before storing** - Ensure data integrity
3. **Encrypt in transit** - Use HTTPS
4. **Log carefully** - Never log sensitive data
## Common Patterns
### Email Sending Tool
```typescript
import { Resend } from "resend";
const resend = new Resend(process.env.RESEND_API_KEY);
await resend.emails.send({
from: process.env.RESEND_FROM_EMAIL!,
to: validatedEmail,
subject: "Subject",
html: templateContent,
});
```typescript
### Database Query Tool
```typescript
import { vectorClient } from "@/lib/vector-client";
const results = await vectorClient.query({
vector: embedding,
topK: 5,
includeMetadata: true,
});
```typescript
### External API Tool
```typescript
const response = await fetch("https://api.example.com/endpoint", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
if (!response.ok) {
throw new Error(`API failed: ${response.statusText}`);
}
const result = await response.json();
```typescript
## Error Handling
### Graceful Degradation
```typescript
try {
const result = await performAction();
return Response.json(result);
} catch (error) {
console.error("Tool error:", error);
// Return helpful error message
return Response.json({
error: "Operation failed",
message: "Please try again or contact support",
}, { status: 500 });
}
```typescript
### Error Categories
1. **Validation errors (400)** - Invalid input
2. **Authentication errors (401)** - Missing/invalid API key
3. **Authorization errors (403)** - Insufficient permissions
4. **Rate limit errors (429)** - Too many requests
5. **Server errors (500)** - Internal failures
## Documentation Requirements
### In-Code Documentation
```typescript
/**
* Tool Name API Route
*
* Purpose: What the tool does
*
* @param param1 - Description of param1
* @param param2 - Description of param2
* @returns Success/error response
*
* @example
* POST /api/tools/tool-name
* {
* "param1": "value",
* "param2": 42
* }
*/
```typescript
### AGENTS.md Documentation
```markdown
## Tool Name
**Purpose:** Clear description
### Triggers
- User asks to [action]
- User mentions [keyword]
### Implementation
- API Route: `/api/tools/tool-name`
- Schema: `toolNameSchema` in `lib/agent-tools/schemas.ts`
- Rate Limit: X requests per Y timeframe
### Example conversation
User: "Can you [action]?"
Ozzy: [Uses tool_name to perform action] "Done! [Result description]"
```typescript
## Deployment Considerations
### Environment Variables
1. Add to `.env.example` with description
2. Configure in Vercel project settings
3. Update deployment checklist in CLAUDE.md
### Monitoring
1. Add PostHog tracking events
2. Configure Sentry error tracking
3. Monitor rate limit hit rates
4. Track tool usage metrics
### Performance
1. Use caching where appropriate
2. Implement timeouts for external APIs
3. Consider async processing for slow operations
4. Monitor API response times
## Common Pitfalls
### ❌ Don't Do This
```typescript
// Exposing API keys
const apiKey = process.env.API_KEY; // Client-side!
// No validation
const data = await request.json(); // Unsafe!
// Hardcoded values
const limit = 100; // Use config file
// No error handling
const result = await action(); // What if it fails?
```typescript
### ✅ Do This Instead
```typescript
// Server-side only
export async function POST(request: NextRequest) {
const apiKey = process.env.API_KEY; // Secure
// Validate input
const data = inputSchema.parse(await request.json());
// Use config
const limit = rateLimits.toolName.limit;
// Handle errors
try {
const result = await action();
return Response.json(result);
} catch (error) {
return handleError(error);
}
}
```typescript
## Success Metrics
### After implementing a new tool
- [ ] Tool successfully triggered by AI agent
- [ ] All edge cases handled gracefully
- [ ] Rate limiting prevents abuse
- [ ] Tests cover success and failure scenarios
- [ ] Documentation complete and accurate
- [ ] No security vulnerabilities
- [ ] Performance meets requirements
- [ ] Monitoring and logging in place
Score
Total Score
55/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
○LICENSE
ライセンスが設定されている
0/10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
✓最近の活動
3ヶ月以内に更新
+5
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
✓タグ
1つ以上のタグが設定されている
+5
Reviews
💬
Reviews coming soon


