Keni — Production AI Agent with Native Anthropic Tool-Use

Conversational AI agent built with the Anthropic SDK's native agentic loop — no orchestration frameworks. Runs live on this portfolio with multi-tier identity, persistent memory, Google Calendar/Gmail tools, Telegram integration, and a resilient multi-provider LLM fallback chain.

Python FastAPI Anthropic SDK Claude Sonnet Supabase Google Calendar API Gmail API Telegram Bot API Whisper STT Docker Cloud Run
Keni — Production AI Agent with Native Anthropic Tool-Use

What it is

Keni is a production conversational agent embedded in this portfolio. It answers questions about my work, schedules meetings, drafts emails, and adapts its behavior based on who is asking. It is deployed on Google Cloud Run and handles requests from both a web chat widget and a Telegram bot.

The core design decision: no orchestration framework. The agentic loop is implemented directly against the Anthropic SDK, making the tool-use contract explicit and the system fully auditable.


Agentic Architecture — Native Tool-Use Loop

Instead of delegating control to LangGraph or LangChain, the agent owns its own loop:

1. Build context: system prompt (tier-scoped) + conversation history + tool schemas
        ↓
2. Call Claude → response is one of:
   ├─ [{type: "text"}]                                        → final answer, loop ends
   └─ [{type: "tool_use", name: "...", input: {...}}]         → tool invocation requested
        ↓
3. Execute the tool locally (calendar, email, memory, search)
        ↓
4. Append to history:
   - assistant turn: the tool_use content blocks
   - user turn:      [{type: "tool_result", tool_use_id: "...", content: "..."}]
        ↓
5. Back to step 1 with the updated history
        ↓
6. Safety cap at 10 iterations → forces a graceful exit

This pattern keeps the orchestration logic in plain Python — no hidden graph state, no magic middleware.


Tools available to the agent

Tool What it does
check_availability Queries Google Calendar for free slots
create_event Books a meeting and sends invite
get_events Lists upcoming events in a range
send_email Drafts and sends email via Gmail API
search_web Retrieves context for open-ended questions
get_memory Reads user-specific facts from Supabase
save_memory Persists new facts across sessions

Each tool is a typed Python function with a JSON schema definition injected into every API call. Claude decides autonomously which tools to call, in what order, and when to stop.


Multi-tier Identity

The agent's behavior changes based on who is on the other side of the conversation:

Tier How it authenticates What changes
PUBLIC none Portfolio Q&A, basic scheduling
CLIENT OTP via email Extended professional context
FAMILY OTP via email Personal tools + family-specific knowledge
OWNER Passphrase Full tool access, no guardrails

The system prompt is built dynamically from the tier. No branching logic inside the agent — the prompt itself scopes what Keni knows and what it can do.


Persistent Memory

Keni maintains a per-user memory backed by Supabase:

  • Profiles: inferred facts about the user (role, preferences, goals)
  • Long-term facts: explicitly saved across sessions
  • Recent messages: rolling window for continuity

On each turn, relevant memories are retrieved and injected into the prompt context. New facts are saved automatically when the agent decides to call save_memory.


Multi-provider Fallback Chain

LLM_PROVIDER_CHAIN = anthropic, openai, groq

If Anthropic is unavailable, the agent retries transparently with OpenAI (gpt-4o-mini) and then Groq (llama-3.3-70b-versatile). The same tool schema format is used across providers — swapping the LLM requires zero changes to the agent logic.

Audio (Telegram voice notes) is transcribed via Whisper on Groq or OpenAI before the text enters the conversation loop.


Platforms

  • Web: chat widget embedded in this site, session identity via signed HMAC cookie
  • Telegram: webhook endpoint receiving text and voice messages from a real bot

Both platforms share the same agent core. Routing and session resolution are the only platform-specific layers.


Architecture

domain/         ← entities and port protocols (no external imports)
application/    ← KeniAgent: loop, prompt builder, tool dispatch
adapters/       ← calendar, email, memory, transcription, LLM providers
interfaces/     ← FastAPI routes (web + Telegram), Jinja2 templates

Hexagonal layout keeps the agent core independent of infrastructure. Swapping the calendar provider or the LLM requires touching only the adapter layer.


Stack

  • LLM: Anthropic Claude Sonnet (primary) · OpenAI · Groq (fallback)
  • Audio STT: Whisper via Groq or OpenAI
  • Backend: Python 3.12, FastAPI, Pydantic v2
  • Identity / DB: Supabase (PostgreSQL + RLS + OTP)
  • Integrations: Google Calendar API, Gmail API, Telegram Bot API
  • Infra: Docker multi-stage, Google Cloud Run