4.7 KiB
4.7 KiB
AGENTS.md - Interview Bot
AI-powered interviewer bot with video call interface and calendar scheduling on Cloudflare Workers.
Quick Reference
| Command | Description |
|---|---|
npm run dev |
Start local dev server (port 8787) |
npm run deploy |
Deploy to Cloudflare Workers |
npm run tail |
Stream production logs |
Project Structure
src/index.ts # Entire app: API routes, AI chat, HTML/CSS/JS frontend
wrangler.toml # Cloudflare Workers config (KV bindings, AI binding)
package.json # Dependencies and npm scripts
Single-file architecture: All backend routes + frontend UI lives in src/index.ts.
Build & Development
npm install && npm run dev # Local dev at http://localhost:8787
npm run deploy # Deploy to production
KV Setup (First-time only)
npx wrangler kv namespace create INTERVIEWS
npx wrangler kv namespace create INTERVIEWS --preview
# Update wrangler.toml with returned IDs
Testing
No test framework. Manual testing only:
GET /api/interviews- List interviewsPOST /api/interviews- Create interviewPUT /api/interviews/:id- Update interviewDELETE /api/interviews/:id- Delete interviewPOST /api/chat- Stream AI chat
Code Style
TypeScript Patterns
- Runtime: Cloudflare Workers (no Node.js APIs)
- No tsconfig.json: Wrangler handles TypeScript compilation
- Explicit types: Always type function params and return values
- Interfaces: Define at file top, before constants
// Interfaces at top
interface Interview {
id: string;
candidateName: string;
status: 'scheduled' | 'in-progress' | 'completed' | 'cancelled';
}
// Explicit return types
async function getInterviews(env: Env, corsHeaders: Record<string, string>): Promise<Response> {
// ...
}
// Type assertions for JSON
const body = await request.json() as Partial<Interview>;
Naming Conventions
| Element | Convention | Example |
|---|---|---|
| Interfaces | PascalCase | Interview, ChatMessage, Env |
| Functions | camelCase | handleChat, getInterviews |
| Constants | SCREAMING_SNAKE | SYSTEM_PROMPT |
| Variables | camelCase | corsHeaders, currentView |
Error Handling
try {
// operation
} catch (error) {
console.error('Error:', error);
return new Response(JSON.stringify({ error: 'Internal Server Error' }), {
status: 500,
headers: { 'Content-Type': 'application/json', ...corsHeaders },
});
}
API Response Pattern
// Always include CORS headers
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
};
// JSON response
return new Response(JSON.stringify(data), {
status: 200,
headers: { 'Content-Type': 'application/json', ...corsHeaders },
});
// SSE streaming response
return new Response(stream as ReadableStream, {
headers: { 'Content-Type': 'text/event-stream', ...corsHeaders },
});
Routing (No framework)
if (path === '/api/interviews' && request.method === 'GET') {
return await getInterviews(env, corsHeaders);
}
if (path.startsWith('/api/interviews/') && request.method === 'DELETE') {
const id = path.split('/')[3];
return await deleteInterview(id, env, corsHeaders);
}
Frontend (Inline in getHTML())
- CSS: Custom properties in
:root, inline<style>block - JS: Inline
<script>at end of body, vanilla DOM manipulation - State: Module-level variables (
let interviews = [])
Environment Bindings
export interface Env {
AI: Ai; // Workers AI
INTERVIEWS: KVNamespace; // KV storage
}
Key Data Structures
interface Interview {
id: string;
candidateName: string;
email: string;
scheduledAt: string; // ISO 8601
duration: number; // minutes
status: 'scheduled' | 'in-progress' | 'completed' | 'cancelled';
notes: string[];
transcript: string[];
}
interface ChatMessage {
role: 'system' | 'user' | 'assistant';
content: string;
}
Common Tasks
Add API endpoint: Add handler function + path match in fetch handler + include corsHeaders
Modify AI behavior: Edit SYSTEM_PROMPT constant or adjust max_tokens in handleChat()
Update UI: Modify HTML/CSS/JS in getHTML() function
Gotchas
- No Node.js APIs - Edge runtime only
- Single file - Don't split into modules
- KV IDs - Must update
wrangler.tomlafter namespace creation - Template literals - Frontend uses escaped backticks (``) for nested templates
- AI model - Default
llama-3.1-8b-instruct; usellama-3.3-70b-instruct-fp8-fastfor quality