Files

179 lines
4.7 KiB
Markdown
Raw Permalink Normal View History

# 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
```bash
npm install && npm run dev # Local dev at http://localhost:8787
npm run deploy # Deploy to production
```
### KV Setup (First-time only)
```bash
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 interviews
- `POST /api/interviews` - Create interview
- `PUT /api/interviews/:id` - Update interview
- `DELETE /api/interviews/:id` - Delete interview
- `POST /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
```typescript
// 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
```typescript
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
```typescript
// 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)
```typescript
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
```typescript
export interface Env {
AI: Ai; // Workers AI
INTERVIEWS: KVNamespace; // KV storage
}
```
## Key Data Structures
```typescript
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
1. **No Node.js APIs** - Edge runtime only
2. **Single file** - Don't split into modules
3. **KV IDs** - Must update `wrangler.toml` after namespace creation
4. **Template literals** - Frontend uses escaped backticks (\`\`) for nested templates
5. **AI model** - Default `llama-3.1-8b-instruct`; use `llama-3.3-70b-instruct-fp8-fast` for quality