Try asking:
Problem
Portfolio sites make people infer too much. I wanted a faster interface for discovery, but it had to stay native to the site and keep prompt logic on the server.
Context / users
λlambda is not a generic embed. It is a shared AI layer that lets visitors ask direct questions about the portfolio through multiple interfaces without duplicating backend logic.
My role
I designed the interaction model, built the shared chat architecture, wrote the server-only prompt system, implemented the protected API route, and added the request guardrails.
Solution
I built one `/api/chat` backend and let each surface talk to it differently. The widget and page chat share a common path. The terminal uses the same backend through a command bridge.
- Shared chat backend across widget, dedicated page chat, and terminal command surfaces
- Server-only prompt composition with channel-aware behavior for terminal vs website chat
- Groq-first provider strategy with OpenAI fallback when needed
- Image attachment support in website chat for multimodal prompts
- Terminal `chat` command that routes into the same AI backend instead of a separate implementation
- Natural transcript behavior with sticky-bottom scrolling and “jump to latest” affordances
- Clipboard image paste support and attachment previews in the website chat UI
- Response safety measures including sanitization, suspicious-message filtering, prompt-leak redaction, and allowlisted links in rendered assistant markdown
Architecture
The key boundary is server over client. Prompts stay server-side. The route participates in the same `withProtectedRoute` pipeline as other protected APIs: origin/host allowlist (fail closed in production if unset), Zod schema validation, rate limiting, bot heuristics, timeout handling, and provider fallback before any model call. The widget and terminal both send payloads built through `lib/chat/requestBuilder.js` so the contract stays explicit.
Engineering Details
- • Unified `/api/chat` route centralizes request validation, provider selection, and response handling so AI logic is not duplicated across surfaces
- • Same-origin enforcement reduces the chance of cross-site abuse against the chat endpoint
- • Rate limiting and bot protection use IP/user-agent keying plus honeypot/timestamp checks to reduce spam and scripted misuse
- • Conversation history is normalized before model submission: roles are constrained, content is trimmed, suspicious assistant messages are filtered, and history depth is capped
- • Multimodal requests are handled explicitly by converting supported image attachments into provider-friendly message content
- • The widget/page chat uses shared hooks for state, submission flow, and auto-scroll behavior, while terminal keeps a separate bridge appropriate for command-driven UX
- • Responses are marked `no-store`, upstream failures are handled with controlled fallbacks, and provider timeouts return bounded error behavior instead of hanging the UI
- • The broader app also applies CSP and security headers at the middleware layer to reinforce client-side trust boundaries
Outcome
- Built a reusable AI layer inside the portfolio instead of three disconnected chat implementations
- Made the same portfolio assistant available through a widget, a full chat surface, and a terminal command without exposing prompt logic to the client
- Added image-aware chat support to the website interface, expanding the project beyond plain-text Q&A
- Created a stronger technical showcase for prompt architecture, route protection, UX engineering, and AI integration work
- Likely reduces discovery friction for visitors who prefer asking direct questions instead of browsing multiple pages first
Tradeoffs / Limits
- • This is a prompt-driven assistant, not a tool-using autonomous agent with memory, retrieval, or workflow execution
- • Answers are not yet source-grounded with citations back to projects, resume entries, or Codex content
- • Terminal and website chat share the backend route, but only the widget and dedicated page chat share the same front-end hook path
- • Production chat relies on the same KV and origin requirements as the rest of the hardened API surface
- • Automated tests cover the request pipeline and shared helpers more than full end-to-end chat UX
Why It Matters
It turns the portfolio into a conversational interface without hiding the implementation reality.
Like what you see?
Feel free to reach out if you have questions about this project or want to chat about working together.