Google Calendar Agent

A Telegram bot that manages my personal Google Calendar through natural language, built on top of DeepSeek's function calling. This writeup focuses on the operational loop wrapped around the LLM: prompt versioning, tracing, evaluation, guardrails and CI/CD.

LLMOps in practice:

Prompt Registry & Eval

The system prompt is a versioned MLflow Prompt, not hardcoded. Edits publish to a challenger alias and must clear a tool-selection accuracy harness before a separate, deliberate step promotes them to champion.

Tracing & Guardrails

Every turn is logged to MLflow: params, tokens, latency, and the full tool-call trace as a JSON artifact. The LLM never writes to the calendar directly, only propose an action, gated by an idempotency check, explicit human confirmation, and a dry_run safety net.

CI/CD

GitHub Actions runs the test suite on every push and, only if it passes, deploys the Flask webhook container to Cloud Run. A single instance, single authorized Telegram user, no agent framework. GitHub: Calendar_Tools .

Architecture Overview:

A message from the authorized Telegram user hits a Flask webhook on Cloud Run, which runs the tool-calling loop against DeepSeek and, for writes, waits on human confirmation before touching Google Calendar. The MLflow server (shared with my other ML projects) sits alongside as the LLMOps layer: it's where the system prompt is versioned, where every turn is traced, and where the eval harness reports back before a prompt edit is trusted in production.

%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#2d3748','primaryTextColor':'#fff','primaryBorderColor':'#2d3748','lineColor':'#2d3748','secondaryColor':'#2d3748','tertiaryColor':'#2d3748'}}}%% graph LR subgraph user["👤 User"] A[Telegram] end subgraph runtime["🚀 Production — Cloud Run"] B[Flask Webhook] C[CalendarAgent Loop] D[DeepSeek
Function Calling] E[Google Calendar API] end subgraph llmops["🔬 LLMOps — MLflow"] F[Prompt Registry
challenger → champion] G[Tracing
tokens · latency · trace.json] H[Eval Harness
tool-selection accuracy] end subgraph cicd["⚙️ CI/CD — GitHub Actions"] I[pytest] J[Deploy to Cloud Run] end A -->|message| B --> C C <-->|function calling| D C -->|human-confirmed writes| E F -.->|loads system prompt| C C -.->|logs every turn| G H -.->|gates promotion| F I --> J -.->|deploy| B style user fill:#fed7aa,stroke:#ed8936,stroke-width:3px style runtime fill:#bfdbfe,stroke:#4299e1,stroke-width:3px style llmops fill:#fecaca,stroke:#ef4444,stroke-width:3px style cicd fill:#d9f99d,stroke:#65a30d,stroke-width:3px classDef userStyle fill:#ed8936,stroke:#c05621,stroke-width:2px,color:#fff classDef runtimeStyle fill:#4299e1,stroke:#2b6cb0,stroke-width:2px,color:#fff classDef llmopsStyle fill:#ef4444,stroke:#dc2626,stroke-width:2px,color:#fff classDef cicdStyle fill:#65a30d,stroke:#4d7c0f,stroke-width:2px,color:#fff class A userStyle class B,C,D,E runtimeStyle class F,G,H llmopsStyle class I,J cicdStyle