Project 1: Build Your Own Chat Interface
Objective
Build a functional web application that replicates core ChatGPT-like functionality from scratch — no LLM frameworks, no abstractions. Raw HTTP calls only. You talk to the APIs, you handle the streams, you own every byte. But youll will use agentic coding to do it. Minimal amount of hand written code (less than 1% of all the code).
Framework and language choice is free.
Requirements
1. Core Chat Engine
- Multi-turn conversation with streaming responses (SSE parsing done by hand)
- Dual provider support — OpenAI (
/v1/chat/completionsandv1/responses) and Anthropic (/v1/messages) running in parallel, switchable per conversation - Proper message history management with role mapping between formats (
system/user/assistant↔ Anthropic'ssystemparameter +user/assistantturns) - Handle API differences yourself: token counting heuristics, stop reasons, content block types
2. Tool Use (Function Calling)
Implement the tool-use loop end-to-end for both providers:
- Date and Time — provide current date/time in ISO format
- Web Search — call a search API (SearXNG, Tavily, or similar), return results to the model, let it synthesize
- Web Fetch — retrieve and extract readable content from a URL (use headless dockerized browser)
- Todo List — CRUD operations with persistent storage (file, SQLite, or equivalent) - per user
- Calendar — CRUD operations with persistent storage (file, SQLite, or equivalent) - per user
The model decides when to call tools. You parse tool calls from the response, execute them, feed results back, loop until the model produces a final text response. No hardcoded orchestration — the LLM drives.
Tool Configuration Per Project
- Each project defines which tools are enabled. If a tool is disabled for a project, it must not appear in the tool definitions sent to the API.
- Tools are enabled/disabled via the project settings UI.
- The available tool set is global (all implemented tools), but the active subset is per-project.
3. Projects & System Prompts
- Projects — named configurations, each containing:
- Custom system prompt
- Default provider and model
- Enabled/disabled tools
- File upload for project
- Create, edit, delete projects; switch between them
- System prompt editor with immediate effect on new messages
- At least one "default" project with an empty system prompt and all tools enabled
4. File Upload
Support uploading files into a conversation. Only the following file types are required:
- Text files (
.txt,.md,.csv,.json,.xml, common code file extensions) — extract content, inject into the user message as context or append to system prompt - PDF (
.pdf) — extract text content (a library for PDF text extraction is allowed) and inject as context (or use llm file attachment capability) - Images (
.png,.jpg,.jpeg,.webp) — send via the appropriate vision API format:- OpenAI:
image_urlcontent part - Anthropic:
imagesource block with base64 encoding - Only available if the currently selected model supports vision. If it does not, reject the upload with a clear message to the user.
- OpenAI:
UI requirements for file upload:
- Drag & drop and file picker support
- Display uploaded files in the conversation (thumbnails for images, filename + size for text/PDF)
- Clear error messaging for unsupported file types or model capability mismatches
5. Backend Configuration UI
A mandatory settings page for managing API backends. No hand-editing .env files to switch providers.
- Add, edit, remove API backends, each defined by:
- Name (user-assigned label)
- Provider type (OpenAI-compatible or Anthropic)
- Base URL
- API key
- Available models
- This architecture means pointing at OpenAI, Anthropic, local Ollama, LiteLLM, Azure OpenAI, or anything else speaking either API format
- Test connection button per backend — send a minimal request, display success or error
- Model list — manually configured or auto-fetched from the
/modelsendpoint where the provider supports it - Default backend and model selection at global and per-project level
- API keys must not be stored in plaintext in the browser. At minimum, store server-side. Ideally, encrypt at rest.
6. User Interface
- Conversation list (create, rename, delete)
- Markdown rendering in responses
- Streaming text display (token-by-token, not waiting for completion)
- Provider/model selector (per-conversation override)
- Visual indication when tools are being invoked (which tool, pending/complete status)
- Project switcher with clear indication of active project
7. Non-Functional Requirements
- Error handling that does not crash the application — bad API keys, rate limits, network failures, malformed responses, tool execution failures
- README with setup and run instructions
- Meaningful Git commit history reflecting incremental development
Explicitly Forbidden
- LLM frameworks and SDKs: LangChain, LlamaIndex, Semantic Kernel, Vercel AI SDK, Spring AI, Microsoft.Extensions.AI, or any equivalent that abstracts away API communication, streaming, or tool orchestration
- Pre-built chat UI components that handle streaming or tool-use logic for you
Standard HTTP clients, JSON parsing libraries, PDF text extraction libraries, and UI component libraries (for general layout, not LLM-specific) are allowed.
Deliverables
- Working source code in a Git repository with meaningful commit history
- Live demo during defense
- Technical document (~2 pages) covering:
- Architecture decisions and technology choices
- How you handle format differences between OpenAI and Anthropic APIs (message structure, streaming, tool calls)
- Your tool execution loop design
- How project-level configuration (system prompt, tools, model) flows into API requests
Defense
You will be asked to:
- Explain any line of code in the project
- Modify a behavior live (e.g., "add retry with exponential backoff to your API call right now")
- Describe what happens byte-by-byte when a streamed tool-call response arrives from each provider
- Explain the structural differences between OpenAI and Anthropic tool-use protocols
- Add a new backend live (e.g., a locally running Ollama instance) and hold a conversation through it
- Upload an image mid-conversation and explain exactly what your code sends to each provider's API
- Demonstrate switching projects and show how the system prompt and tool configuration changes in the actual API payload
- Disable a tool in project settings and prove it disappears from the API request
- Display all prompts used in coding
If you cannot explain it, you did not own it (let llm explain every line in code if needed).
Git
All projects go here: gitlab.proxy.itcollege.ee
For api access to LLM backend, use this: https://api.proxy.itcollege.ee