<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>GCS on Wojciech Marusiak IT Blog</title>
        <link>https://www.wojcieh.net/tags/gcs/</link>
        <description>Recent content in GCS on Wojciech Marusiak IT Blog</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en-us</language>
        <lastBuildDate>Wed, 16 Sep 2026 10:00:00 +0200</lastBuildDate><atom:link href="https://www.wojcieh.net/tags/gcs/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Deploying a Stateful Autonomous Agent on Cloud Run: Hermes Agent with Telegram &amp; Dual-Engine Fallback</title>
        <link>https://www.wojcieh.net/stateful-ai-agent-cloud-run-hermes-telegram/</link>
        <pubDate>Wed, 16 Sep 2026 10:00:00 +0200</pubDate>
        
        <guid>https://www.wojcieh.net/stateful-ai-agent-cloud-run-hermes-telegram/</guid>
        <category>Cloud Run</category>
        <category>AI Agent</category>
        <category>Hermes</category>
        <category>Telegram</category>
        <category>Vertex AI</category>
        <category>GCS</category>
        <category>Secret Manager</category>
        <category>AI &amp; LLM Ops</category>
        <category>Google Cloud</category>
        <description>&lt;p&gt;&lt;img src=&#34;https://www.wojcieh.net/images/uploads/2026/09/stateful-ai-agent-cloud-run-hermes.webp&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Deploying a Stateful Autonomous Agent on Cloud Run with Hermes Agent&#34;
	
	
&gt;&lt;/p&gt;
&lt;p&gt;Serverless platforms like Google Cloud Run are fundamentally designed to be stateless: containers can spin up, restart, or scale down to zero at any moment. But how do you run a long-running, stateful autonomous AI Agent that maintains persistent conversation history, chat database files, and a live Telegram bot connection?&lt;/p&gt;
&lt;p&gt;In this article, I share the architecture behind deploying &lt;strong&gt;Hermes Agent&lt;/strong&gt; on Cloud Run with persistent state backed by Google Cloud Storage and a dual-engine LLM backend.&lt;/p&gt;
&lt;h2 id=&#34;high-level-architecture&#34;&gt;High-Level Architecture
&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;15
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;16
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;17
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;18
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;19
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;20
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;21
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;22
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;23
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;24
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               ┌────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               │           TELEGRAM USERS               │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               │         @WojciechHermesBot             │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               └──────────────────┬─────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                                  │ (Long-polling / Webhooks)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                                  ▼
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               ┌────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               │       CLOUD RUN: hermes-agent          │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               │     (europe-west4, Always-On)          │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               │                                        │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               │   ┌────────────────────────────────┐   │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               │   │   gcs_sync.py (State Manager)  │   │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               │   │   • Pulls state.db on startup  │   │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               │   │   • Syncs state.db periodically│   │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               │   └────────────────┬───────────────┘   │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               └────────────────────┼───────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                                    │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      ┌─────────────────────────────┴─────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      ▼                                                           ▼
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       ┌──────────────────────────────┐                            ┌──────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       │   PRIMARY LLM BACKEND        │                            │   FALLBACK / NIGHT BACKEND   │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       │   vLLM (RTX PRO 6000 96GB)   │                            │   Vertex AI (Gemini 3.7 Flash│
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       │   • 08:00 - 23:00 Active     │                            │   • 23:00 - 08:00 Active     │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       └──────────────────────────────┘                            └──────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;1-stateful-persistence-on-serverless-gcs-state-bridge&#34;&gt;1. Stateful Persistence on Serverless (GCS State Bridge)
&lt;/h2&gt;&lt;p&gt;Hermes Agent maintains SQLite databases (&lt;code&gt;state.db&lt;/code&gt;) for conversation memory, user sessions, and tool states. To survive container revisions and deployments without losing a single chat:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Startup Hook:&lt;/strong&gt; When the container initializes, a lightweight Python wrapper runs GCS API sync to restore &lt;code&gt;/app/data/state.db&lt;/code&gt; from &lt;code&gt;gs://wojciech-genai-hermes-state/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Periodic Daemon &amp;amp; SIGTERM Catch:&lt;/strong&gt; A background thread flushes SQLite WAL checkpoints and uploads snapshots to GCS every 5 minutes and on graceful container shutdown.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;2-secure-secret-management-gcp-secret-manager&#34;&gt;2. Secure Secret Management (GCP Secret Manager)
&lt;/h2&gt;&lt;p&gt;Hardcoding tokens or passwords in container environment variables is an anti-pattern. We integrate &lt;strong&gt;GCP Secret Manager&lt;/strong&gt; with native Cloud Run references:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gcloud run services update hermes-agent &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --set-secrets&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;HERMES_DASHBOARD_PASSWORD=hermes-dashboard-password:latest,\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;                 HERMES_DASHBOARD_SECRET=hermes-dashboard-secret:latest,\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;                 TELEGRAM_BOT_TOKEN=hermes-telegram-bot-token:latest&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --service-account&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;cloud-run-executor@wojciech-genai.iam.gserviceaccount.com
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;3-dual-engine-llm-fallback-vllm--vertex-ai&#34;&gt;3. Dual-Engine LLM Fallback (vLLM + Vertex AI)
&lt;/h2&gt;&lt;p&gt;To maximize reasoning power while keeping GPU FinOps tightly controlled:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Daytime (vLLM GPU):&lt;/strong&gt; Between 08:00 and 23:00, when our dedicated NVIDIA RTX PRO 6000 (96 GB VRAM) instance is active, Hermes routes primary inference and tool-calling requests to our private BF16 model with custom Jinja tool-calling templates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nighttime &amp;amp; Failover (Vertex AI):&lt;/strong&gt; At 23:00, Cloud Scheduler scales the GPU service down to &lt;code&gt;min-instances=0&lt;/code&gt; (cutting monthly GPU spend from &lt;strong&gt;$944/month&lt;/strong&gt; down to &lt;strong&gt;~$550/month&lt;/strong&gt;). Whenever the GPU instance is scaled to zero or undergoing maintenance, Hermes transparently falls back to &lt;code&gt;google/gemini-3.7-flash&lt;/code&gt; on Vertex AI with zero downtime.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the next post, we will look at how we route and sanitize tool-calling payloads using a custom Python middleware proxy!&lt;/p&gt;</description>
        </item>
        
    </channel>
</rss>
