<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Telegram — mizore / notes</title>
    <link>https://mizore.blog/en/tags/telegram/</link>
    <link xmlns="http://www.w3.org/2005/Atom" href="https://mizore.blog/en/tags/telegram/feed.xml" rel="self" type="application/rss+xml"></link>
    <description>1 posts</description>
    <language>en</language>
    <lastBuildDate>Mon, 03 Aug 2026 00:00:00 +0000</lastBuildDate>
    <item>
      <title>Putting Memoh Under the Knife: Specializing an Agent for Cheaper Telegram Group Chats</title>
      <link>https://mizore.blog/en/posts/making-memoh-cheaper-on-telegram/</link>
      <description>&lt;p&gt;A while ago, I deployed &lt;a href=&#34;https://github.com/memohai/memoh&#34;&gt;Memoh&lt;/a&gt; as a few Telegram group-chat bots, mainly to burn through an Ollama subscription I couldn&#39;t possibly use up on my own (some idiot subscribed to a full year of Ollama at once).&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://mizore.blog/images/2baf5985a2608e7d7729c6df9ab9a320191edd3be43f59a8f37e8ed387fb0307.webp&#34; alt=&#34;The Memoh bot &amp;quot;Xiaoxue&amp;quot; chatting in a Telegram group and replying with a catgirl sticker&#34; decoding=&#34;async&#34; fetchpriority=&#34;high&#34; width=&#34;1256&#34; height=&#34;874&#34; srcset=&#34;https://mizore.blog/images/ddf84c9704ee90683624988b2e2c49058a8693b40b103bf58f70831278c12e72.webp 720w, https://mizore.blog/images/2baf5985a2608e7d7729c6df9ab9a320191edd3be43f59a8f37e8ed387fb0307.webp 1256w&#34; sizes=&#34;(max-width: 760px) calc(100vw - 64px), 704px&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;After running it for a bit, I noticed that ten minutes of group chat could burn through half of my 5-hour limit, and a single day would eat half of my weekly quota. That got me thinking: in a pure chat scenario, how can I drive down both the number of LLM calls and the token consumption per call? I made a set of targeted changes for group chat, and my total cost dropped to less than a fifth of what it used to be.&lt;/p&gt;&#xA;&lt;p&gt;To be clear, this post isn&#39;t here to nitpick upstream. Memoh is a thoughtfully designed general-purpose agent framework—multi-step tool loops, a rich toolset, and structured message metadata are all reasonable and even necessary for an agent that &amp;quot;gets work done for you.&amp;quot; What I did was &lt;strong&gt;specialize&lt;/strong&gt; it into a chatbot: an agent in a group chat spends most of its life just talking rather than executing tasks, and &amp;quot;talking&amp;quot; inside a general-purpose agent loop has a very unfavorable cost structure.&lt;/p&gt;&#xA;&lt;h2 id=&#34;where-does-the-money-actually-go&#34;&gt;Where Does the Money Actually Go?&lt;/h2&gt;&#xA;&lt;p&gt;First, here is the breakdown of a real request captured before my optimizations:&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Component&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Size&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Share&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Messages (conversation history)&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;~157.7 KB&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;68.0%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Tools (tool schemas)&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;~49.5 KB&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;21.3%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;System (system prompt)&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;~24.7 KB&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;10.7%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;A single request is over 200 KB—roughly 50,000 tokens. The catch is what a general-purpose agent&#39;s tool loop does with that payload: &lt;strong&gt;every extra tool call re-reads all 50,000 tokens from scratch&lt;/strong&gt;. And chat scenarios are packed with tool calls: sending a message is one, replying is one, sending a sticker is another, and after sending, a delivery status comes back for the model to read and confirm. Behind a single outgoing group-chat message, the full context is read 2 to 3 times over.&lt;/p&gt;&#xA;&lt;p&gt;So my changes followed three directions: make fewer calls, read less per call, and hit the prompt cache on almost everything already read. Every change below includes the actual code from my fork (&lt;a href=&#34;https://github.com/mizorewww/Memoh&#34;&gt;mizorewww/Memoh&lt;/a&gt;, compared against upstream baseline &lt;code&gt;d0c5c735^&lt;/code&gt;).&lt;/p&gt;&#xA;&lt;h2 id=&#34;change-1-clock-out-right-after-sending&#34;&gt;Change 1: Clock Out Right After Sending&lt;/h2&gt;&#xA;&lt;p&gt;Upstream&#39;s loop works like this: the model decides to send a message → calls &lt;code&gt;send&lt;/code&gt; → the framework returns the delivery status (message ID, platform, target conversation, etc.) as a tool result → the model is invoked a second time, reads the entire context again, says &amp;quot;okay, sent,&amp;quot; and finishes. For a group-chat bot, that final call is almost pure waste: the message has already been delivered to the chat, and there is nothing meaningful left for the model to do except echo a confirmation. With the Doubao model, an even worse failure mode showed up: seeing the success result, the model kept calling &lt;code&gt;send&lt;/code&gt; over and over in an infinite loop.&lt;/p&gt;&#xA;&lt;p&gt;My fix wraps the provider in a decorator (&lt;code&gt;internal/agent/runtime/native/terminal_send.go&lt;/code&gt;). Once &lt;code&gt;send&lt;/code&gt; successfully delivers to the current conversation, the next time the model would be called, the decorator immediately returns &lt;code&gt;FinishReasonStop&lt;/code&gt; locally without making a network request at all:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;internal/agent/runtime/native/terminal_send.go&lt;/b&gt;&lt;span&gt;End the turn locally after successful delivery&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/Memoh/blob/ad8012c1a0926822307f56454bd26be9ef9dd2dc/internal/agent/runtime/native/terminal_send.go#L76-L103&#34;&gt;L76–103 · ad8012c ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;76&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;terminalSendProvider&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;77&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Provider&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;78&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;terminalSendState&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;79&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;80&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;81&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;terminalSendProvider&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;DoGenerate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;params&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;GenerateParams&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;GenerateResult&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;82&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;isDelivered&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;83&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;GenerateResult&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;84&lt;/span&gt;&#x9;&#x9;&#x9;&lt;span class=&#34;nx&#34;&gt;FinishReason&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;FinishReasonStop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;85&lt;/span&gt;&#x9;&#x9;&#x9;&lt;span class=&#34;nx&#34;&gt;Response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;     &lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ResponseMetadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;terminalSendResponseID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;86&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;87&lt;/span&gt;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;88&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Provider&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;DoGenerate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;89&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;90&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;91&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;terminalSendProvider&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;DoStream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;params&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;GenerateParams&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;StreamResult&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;92&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;isDelivered&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;93&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Provider&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;DoStream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;94&lt;/span&gt;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;95&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;parts&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;chan&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;StreamPart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;96&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;parts&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;FinishStepPart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;97&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;nx&#34;&gt;FinishReason&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;FinishReasonStop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;98&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;nx&#34;&gt;Response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;     &lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ResponseMetadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;terminalSendResponseID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;99&lt;/span&gt;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;100&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;parts&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;FinishPart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;FinishReason&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;FinishReasonStop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;101&lt;/span&gt;&#x9;&lt;span class=&#34;nb&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;parts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;102&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;StreamResult&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Stream&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;parts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;103&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;p&gt;Of course, the protocol requires every &lt;code&gt;tool_call&lt;/code&gt; to be paired with a &lt;code&gt;tool_result&lt;/code&gt;, so we can&#39;t literally drop the result without leaving a dangling tool call in history. Instead, the result is compressed to the bare minimum: a successful send to the current conversation returns just &lt;code&gt;{&amp;quot;ok&amp;quot;: true}&lt;/code&gt;, only attaching target metadata when sending across conversations; failures return a structured retryable error (&lt;code&gt;error_code&lt;/code&gt; + &lt;code&gt;retryable&lt;/code&gt; + &lt;code&gt;guidance&lt;/code&gt;) so the model has a chance to recover instead of crashing the loop with a Go error:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;internal/agent/tool/message.go&lt;/b&gt;&lt;span&gt;Minimal send result&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/Memoh/blob/ad8012c1a0926822307f56454bd26be9ef9dd2dc/internal/agent/tool/message.go#L311-L324&#34;&gt;L311–324 · ad8012c ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;311&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;MessageProvider&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;execSend&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;session&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;SessionContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;toolCallID&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;args&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;any&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;any&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;312&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;session&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SessionType&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sessionmode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Discuss&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;313&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;nx&#34;&gt;sendResult&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;exec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;SendDirectForTool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;toMessagingSession&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;session&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;toolCallID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;314&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;315&lt;/span&gt;&#x9;&#x9;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;messageSendErrorResult&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;316&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;317&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;nx&#34;&gt;resp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;any&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;ok&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;318&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;session&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;IsSameConversation&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sendResult&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Platform&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sendResult&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Target&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;319&lt;/span&gt;&#x9;&#x9;&#x9;&lt;span class=&#34;nx&#34;&gt;resp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;platform&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sendResult&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Platform&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;320&lt;/span&gt;&#x9;&#x9;&#x9;&lt;span class=&#34;nx&#34;&gt;resp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;target&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sendResult&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Target&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;321&lt;/span&gt;&#x9;&#x9;&#x9;&lt;span class=&#34;nx&#34;&gt;resp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;delivered&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;target&amp;#34;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;322&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;323&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;resp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;324&lt;/span&gt;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;p&gt;There is one more layer in history projection. When future turns read the conversation history, successful &lt;code&gt;send&lt;/code&gt; calls are folded into a minimal call/result pair containing only the five audience-visible fields (&lt;code&gt;text&lt;/code&gt;, &lt;code&gt;reply_to&lt;/code&gt;, &lt;code&gt;sticker_id&lt;/code&gt;, &lt;code&gt;attachments&lt;/code&gt;, &lt;code&gt;message&lt;/code&gt;), stripping delivery internals (&lt;code&gt;bot_id&lt;/code&gt;, &lt;code&gt;platform&lt;/code&gt;, &lt;code&gt;message_id&lt;/code&gt;, etc.) from the prompt context. Note that this folding happens only in the projection layer—the persisted canonical history remains untouched for debugging:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;internal/agent/application/service_messages.go&lt;/b&gt;&lt;span&gt;Minimal send call in history projection&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/Memoh/blob/ad8012c1a0926822307f56454bd26be9ef9dd2dc/internal/agent/application/service_messages.go#L232-L246&#34;&gt;L232–246 · ad8012c ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;232&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;minimalDiscussSendCall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;call&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ToolCallPart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ToolCallPart&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;233&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;input&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;normalizeToolInputMap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;call&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Input&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;234&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;minimal&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;any&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;235&lt;/span&gt;&#x9;&lt;span class=&#34;c1&#34;&gt;// Current-conversation routing is implicit. Keep only audience-visible&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;236&lt;/span&gt;&#x9;&lt;span class=&#34;c1&#34;&gt;// payload fields and the reply reference needed to understand the exchange.&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;237&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;range&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;reply_to&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;sticker_id&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;attachments&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;238&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ok&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ok&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;239&lt;/span&gt;&#x9;&#x9;&#x9;&lt;span class=&#34;nx&#34;&gt;minimal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;240&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;241&lt;/span&gt;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;242&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ToolCallPart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;243&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;nx&#34;&gt;ToolCallID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strings&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;TrimSpace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;call&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ToolCallID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;244&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;nx&#34;&gt;ToolName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;   &lt;span class=&#34;s&#34;&gt;&amp;#34;send&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;245&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;nx&#34;&gt;Input&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;      &lt;span class=&#34;nx&#34;&gt;minimal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;246&lt;/span&gt;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;p&gt;The result: on pure messaging turns, LLM calls drop from 2 to 1—&lt;strong&gt;an immediate 50% savings&lt;/strong&gt;. Multi-step workflows that search the web or call other tools still work normally; the bot simply treats &lt;code&gt;send&lt;/code&gt; as the terminal action of the turn.&lt;/p&gt;&#xA;&lt;h2 id=&#34;change-2-send-text-reply-and-sticker-in-a-single-call&#34;&gt;Change 2: Send Text, Reply, and Sticker in a Single Call&lt;/h2&gt;&#xA;&lt;p&gt;In group chats, a single response is often both a reply to someone and accompanied by a sticker. Previously, that required multiple tool calls, re-reading the entire context each time. I merged them into a single &lt;code&gt;send&lt;/code&gt; tool signature:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;send(text[optional], reply_to[optional], sticker_id[optional])&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;Concretely, this involved two changes. First, upstream already had a top-level &lt;code&gt;reply_to&lt;/code&gt; parameter alongside a redundant nested &lt;code&gt;message.reply{message_id}&lt;/code&gt; object; I removed the nested form, kept only the top-level parameter, and restricted it to message IDs visible in the current turn (returning a retryable error if invisible instead of replying to the wrong message).&lt;/p&gt;&#xA;&lt;p&gt;Second, I had previously written an MCP server for sending stickers, only to realize that invoking an external MCP tool added an extra LLM round-trip every time. I folded the sticker catalog directly into the &lt;code&gt;sticker_id&lt;/code&gt; parameter of &lt;code&gt;send&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;internal/agent/runtime/native/telegram_sticker.go&lt;/b&gt;&lt;span&gt;Turn the sticker MCP into an internal backend of send&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/Memoh/blob/ad8012c1a0926822307f56454bd26be9ef9dd2dc/internal/agent/runtime/native/telegram_sticker.go#L14-L31&#34;&gt;L14–31 · ad8012c ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;14&lt;/span&gt;&#x9;&lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/memohai/memoh/internal/delivery&amp;#34;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;16&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;17&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;18&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;telegramStickerSendGuidance&lt;/span&gt;     &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34; For Telegram, normally pair every coherent public message with at least one context-appropriate Sticker by setting `sticker_id` in the same send call; omit it only when the catalog has no suitable Sticker. Choose from the full visual descriptions, not from the original emoji alone, and avoid repetitive duplicates.&amp;#34;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;19&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;telegramStickerCatalogSchemaKey&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;x-memoh-sticker-catalog&amp;#34;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;21&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;telegramStickerSchemaEntry&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;23&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;ID&lt;/span&gt;          &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;`json:&amp;#34;id&amp;#34;`&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;24&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;Description&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;`json:&amp;#34;description&amp;#34;`&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;25&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;Emoji&lt;/span&gt;       &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;`json:&amp;#34;emoji&amp;#34;`&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;26&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;Status&lt;/span&gt;      &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;`json:&amp;#34;status&amp;#34;`&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;27&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;28&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;29&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// mergeTelegramStickerSendTools converts the Sticker MCP into an internal&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;30&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// backend for the first-party send tool. The model sees one send call whose&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;31&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// sticker_id enum contains the complete, stable catalog; it never sees a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;p&gt;Within a single &lt;code&gt;send&lt;/code&gt; call, the bot delivers the text first and then the sticker; if the sticker fails after the text is already sent, it returns partial success and terminates immediately so the model won&#39;t retry and send duplicate text.&lt;/p&gt;&#xA;&lt;p&gt;I also had a vision model pre-generate a concise visual description (under 50 characters) for every sticker, stored alongside the sticker-set metadata in SQLite. Sorted deterministically by ID, these descriptions are embedded into the &lt;code&gt;send&lt;/code&gt; tool schema&#39;s description. Once merged, sending a sticker incurs virtually zero extra LLM cost.&lt;/p&gt;&#xA;&lt;h2 id=&#34;change-3-move-everything-that-changes-to-the-tail-of-the-prefix&#34;&gt;Change 3: Move Everything That Changes to the Tail of the Prefix&lt;/h2&gt;&#xA;&lt;p&gt;This is the key to prompt-cache hit rates. Every provider&#39;s prompt caching mechanism (Anthropic, OpenAI, DeepSeek, Kimi—all of them) works by &lt;strong&gt;prefix matching&lt;/strong&gt;: the prefix of a request must match byte-for-byte, and the first byte that changes invalidates the cache for everything after it.&lt;/p&gt;&#xA;&lt;p&gt;To be fair, upstream&#39;s default behavior isn&#39;t bad across ordinary turns: conversation history is appended at the end, so automatic prefix caches like DeepSeek&#39;s catch most of it. The real leak was a frequently rewritten file buried in the middle of the system prompt: upstream placed &lt;code&gt;MEMORY.md&lt;/code&gt; between &lt;code&gt;AGENTS.md&lt;/code&gt; and &lt;code&gt;PROFILES.md&lt;/code&gt;. Because &lt;code&gt;MEMORY.md&lt;/code&gt; is rewritten constantly by the memory subsystem, every update invalidated the cache for everything following it. My fix was a one-function change:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;internal/agent/runtime/native/fs.go&lt;/b&gt;&lt;span&gt;Move MEMORY.md to the tail of the system prompt&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/Memoh/blob/ad8012c1a0926822307f56454bd26be9ef9dd2dc/internal/agent/runtime/native/fs.go#L66-L71&#34;&gt;L66–71 · ad8012c ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;66&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// systemFileLoadOrder keeps the frequently changing memory summary at the&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;67&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// tail of the system prompt. Stable instruction/profile content therefore&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;68&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// remains in the reusable prefix when MEMORY.md changes between turns.&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;69&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;systemFileLoadOrder&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;70&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;AGENTS.md&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;PROFILES.md&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;MEMORY.md&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;71&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;p&gt;Changing the load order from &lt;code&gt;AGENTS.md → MEMORY.md → PROFILES.md&lt;/code&gt; to &lt;code&gt;AGENTS.md → PROFILES.md → MEMORY.md&lt;/code&gt; keeps the most stable instructions at the front of the prefix and pushes the most volatile file to the very end of the system prompt. Following the same principle, I cleaned up several other sources of &amp;quot;prefix pollution&amp;quot;:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The memory-writing manual (~2.6 KB) is now injected only when a memory provider is actually configured; when set to &lt;code&gt;None&lt;/code&gt;, the entire section is omitted:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;internal/agent/application/service.go&lt;/b&gt;&lt;span&gt;Skip memory instructions when no memory provider is configured&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/Memoh/blob/ad8012c1a0926822307f56454bd26be9ef9dd2dc/internal/agent/application/service.go#L710&#34;&gt;L710 · ad8012c ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;710&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;MemoryInstructions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;strings&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;TrimSpace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;botSettings&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;MemoryProviderID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Platform identity now injects only the active platform&#39;s fields, and strips &lt;code&gt;avatar_url&lt;/code&gt; (which contained the bot token) from the injected prompt.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The difference is measurable: under the old &amp;quot;dynamically mutate system prompt&amp;quot; path, a forced-reply call measured just 5.1% cache read (a single measurement of that specific code path, not the everyday baseline). After the fix, two consecutive requests in a live group chat sent 52,259 and 52,633 input tokens, of which 52,096 and 52,480 were served from cache—a &lt;strong&gt;99.7% cache hit rate&lt;/strong&gt;, leaving only ~160 uncached input tokens billed at full price per turn.&lt;/p&gt;&#xA;&lt;h2 id=&#34;change-4-invisible-request-slimming&#34;&gt;Change 4: Invisible Request Slimming&lt;/h2&gt;&#xA;&lt;p&gt;Smaller requests mean cheaper reads on every turn. This part stacks several small reductions together, all exposed as configurable Telegram channel policies stored in bot metadata:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;internal/agent/channelpolicy/policy.go&lt;/b&gt;&lt;span&gt;Four Telegram channel policy keys&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/Memoh/blob/ad8012c1a0926822307f56454bd26be9ef9dd2dc/internal/agent/channelpolicy/policy.go#L21-L24&#34;&gt;L21–24 · ad8012c ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;21&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;TelegramToolCallsEnabledMetadataKey&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;telegram_tool_calls_enabled&amp;#34;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;TelegramEnabledToolsMetadataKey&lt;/span&gt;     &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;telegram_enabled_tools&amp;#34;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;23&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;TelegramSkillsEnabledMetadataKey&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;telegram_skills_enabled&amp;#34;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;24&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;TelegramMessageMetadataModeKey&lt;/span&gt;      &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;telegram_message_metadata_mode&amp;#34;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;telegram_tool_calls_enabled&lt;/code&gt; is the master switch for tools, &lt;code&gt;telegram_enabled_tools&lt;/code&gt; is an explicit allowlist (an empty array disables all tools), and &lt;code&gt;telegram_skills_enabled&lt;/code&gt; controls skills. A chat bot doesn&#39;t need shell execution or file editing; on my two production bots I enabled only &lt;code&gt;send&lt;/code&gt;, &lt;strong&gt;turning off 37 tools&lt;/strong&gt;. The crucial detail is &lt;em&gt;when&lt;/em&gt; filtering happens: the allowlist runs before schema generation, so disabled tools don&#39;t contribute a single byte to the request:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;internal/agent/runtime/native/agent.go&lt;/b&gt;&lt;span&gt;Filter tools before schema generation&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/Memoh/blob/ad8012c1a0926822307f56454bd26be9ef9dd2dc/internal/agent/runtime/native/agent.go#L990-L997&#34;&gt;L990–997 · ad8012c ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;990&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;991&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;filtered&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([]&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Tool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;providerTools&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;992&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;tool&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;range&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;providerTools&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;993&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;cfg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ChannelPolicy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;AllowsTool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;tool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;cfg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ChannelPolicy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;AllowsBackendTool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;tool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;994&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;nx&#34;&gt;filtered&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;filtered&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;tool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;995&lt;/span&gt;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;996&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;997&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;providerTools&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;filtered&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;p&gt;Before optimization, the Tools section accounted for 21.3% of the request (~49.5 KB, roughly 12,000 tokens); now it is almost completely gone. Policy evaluation is fail-closed: if reading the policy fails, it exposes no tools rather than leaking tools that should be disabled.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;telegram_message_metadata_mode&lt;/code&gt; controls how message metadata headers are projected, defaulting to &lt;code&gt;compact&lt;/code&gt; on Telegram. Upstream prepends a full metadata header to every message sent to the model: &lt;code&gt;&amp;lt;message id=&amp;quot;...&amp;quot; sender=&amp;quot;...&amp;quot; t=&amp;quot;...&amp;quot; channel=&amp;quot;telegram&amp;quot; conversation=&amp;quot;...&amp;quot; type=&amp;quot;...&amp;quot; target=&amp;quot;...&amp;quot;&amp;gt;&lt;/code&gt;. The canonical format in SQLite stays unchanged, but the transient projection sent to the LLM strips the per-message repeated timestamp, platform, and conversation name while keeping speaker attribution for group chats:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;internal/agent/turn/user_header.go&lt;/b&gt;&lt;span&gt;Compact message header projection&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/Memoh/blob/ad8012c1a0926822307f56454bd26be9ef9dd2dc/internal/agent/turn/user_header.go#L165-L183&#34;&gt;L165–183 · ad8012c ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;165&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;ProjectUserMessageHeader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;mode&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;166&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strings&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ToLower&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;strings&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;TrimSpace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;mode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;compact&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;strings&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;HasPrefix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;strings&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;TrimSpace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;lt;message&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;167&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;content&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;168&lt;/span&gt;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;169&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;start&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strings&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;lt;message&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;170&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;start&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;171&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;content&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;172&lt;/span&gt;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;173&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;endRel&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strings&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:],&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;174&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;endRel&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;175&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;content&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;176&lt;/span&gt;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;177&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;start&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;endRel&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;178&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;compactOpening&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ok&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;projectMessageOpeningTag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;start&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;179&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ok&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;180&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;content&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;181&lt;/span&gt;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;182&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[:&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;compactOpening&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:]&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;183&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;p&gt;That saves 85–120 characters per message, reduces occurrences of &lt;code&gt;channel=&amp;quot;telegram&amp;quot;&lt;/code&gt; in a request from 148 down to 2, and shrinks a full-history payload from 221.0 KB to 208.7 KB.&lt;/p&gt;&#xA;&lt;h2 id=&#34;change-5-giving-text-only-models-eyes&#34;&gt;Change 5: Giving Text-Only Models &amp;quot;Eyes&amp;quot;&lt;/h2&gt;&#xA;&lt;p&gt;Some of the primary models I run don&#39;t support vision (such as DeepSeek V4 Flash), yet people post images in group chats all day long. I added an auxiliary vision model mechanism: when the primary model declares no vision support and the current turn includes image attachments, a cheap small vision model describes the images first:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;internal/agent/application/auxiliary_vision.go&lt;/b&gt;&lt;span&gt;Trigger only when the primary model lacks vision&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/Memoh/blob/ad8012c1a0926822307f56454bd26be9ef9dd2dc/internal/agent/application/auxiliary_vision.go#L183-L196&#34;&gt;L183–196 · ad8012c ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;183&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;describeImagesWithAuxiliaryVision&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;184&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;185&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ChatRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;186&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;primarySupportsVision&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;187&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;attachments&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;gatewayAttachment&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;188&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;189&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;primarySupportsVision&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;190&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;191&lt;/span&gt;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;192&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;images&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;extractNativeImageParts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;attachmentsToAny&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;attachments&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;193&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;describeImagePartsWithAuxiliaryVision&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;primarySupportsVision&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;images&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;194&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;195&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;196&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;describeImagePartsWithAuxiliaryVision&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;p&gt;The generated description is appended as an &lt;code&gt;&amp;lt;auxiliary_vision_description&amp;gt;&lt;/code&gt; block at the &lt;strong&gt;tail of the last user message&lt;/strong&gt;, once again leaving the cached prefix untouched:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;internal/agent/application/auxiliary_vision.go&lt;/b&gt;&lt;span&gt;Append vision descriptions to the tail of the last user message&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/Memoh/blob/ad8012c1a0926822307f56454bd26be9ef9dd2dc/internal/agent/application/auxiliary_vision.go#L454-L467&#34;&gt;L454–467 · ad8012c ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;454&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;appendAuxiliaryVisionToLastUserMessage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;messages&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;visionContext&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Message&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;455&lt;/span&gt;&#x9;&lt;span class=&#34;nx&#34;&gt;visionContext&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strings&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;TrimSpace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;visionContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;456&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;visionContext&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;457&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;messages&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;458&lt;/span&gt;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;459&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;messages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;--&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;460&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;messages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Role&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;MessageRoleUser&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;461&lt;/span&gt;&#x9;&#x9;&#x9;&lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;462&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;463&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;nx&#34;&gt;messages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Content&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;messages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;TextPart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;\n\n&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;visionContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;464&lt;/span&gt;&#x9;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;messages&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;465&lt;/span&gt;&#x9;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;466&lt;/span&gt;&#x9;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;messages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;UserMessage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;visionContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;467&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;h2 id=&#34;bonus-telegram-specific-polish&#34;&gt;Bonus Telegram-Specific Polish&lt;/h2&gt;&#xA;&lt;p&gt;A few additional improvements aimed at making the bot feel more natural in Telegram group chats also helped keep costs predictable:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Continuously refreshing the &lt;code&gt;typing&lt;/code&gt; indicator throughout any turn where the bot is selected to reply, so group members see &amp;quot;is typing…&amp;quot; instead of 30 seconds of dead silence followed by a wall of text;&lt;/li&gt;&#xA;&lt;li&gt;Switching context compaction to a rolling-summary mode whose prompt explicitly forbids repeating raw tool-argument JSON; the context budget takes the smaller of the model&#39;s context window and the bot&#39;s compaction threshold, and truncation boundaries never split a &lt;code&gt;user&lt;/code&gt;/&lt;code&gt;tool&lt;/code&gt; pair mid-exchange.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;how-much-did-it-actually-save&#34;&gt;How Much Did It Actually Save?&lt;/h2&gt;&#xA;&lt;p&gt;Modeling the savings is straightforward. The input cost of a single LLM call is:&lt;/p&gt;&#xA;&lt;div class=&#34;math&#34; tabindex=&#34;0&#34;&gt;&lt;math display=&#34;block&#34; style=&#34;font-feature-settings: &#39;dtls&#39; off;&#34; xmlns=&#34;http://www.w3.org/1998/Math/MathML&#34;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mpadded lspace=&#34;0&#34;&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;c&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;a&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;l&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;l&lt;/mi&gt;&lt;/mpadded&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mrow&gt;&lt;mo fence=&#34;true&#34; form=&#34;prefix&#34; stretchy=&#34;true&#34;&gt;[&lt;/mo&gt;&lt;mo form=&#34;prefix&#34; stretchy=&#34;false&#34;&gt;(&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mo form=&#34;postfix&#34; stretchy=&#34;false&#34;&gt;)&lt;/mo&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mpadded lspace=&#34;0&#34;&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;i&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;n&lt;/mi&gt;&lt;/mpadded&gt;&lt;/msub&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mpadded lspace=&#34;0&#34;&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;c&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;a&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;c&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;h&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;e&lt;/mi&gt;&lt;/mpadded&gt;&lt;/msub&gt;&lt;mo fence=&#34;true&#34; form=&#34;postfix&#34; stretchy=&#34;true&#34;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mpadded lspace=&#34;0&#34;&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;i&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;n&lt;/mi&gt;&lt;/mpadded&gt;&lt;/msub&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mrow&gt;&lt;mo fence=&#34;true&#34; form=&#34;prefix&#34; stretchy=&#34;true&#34;&gt;[&lt;/mo&gt;&lt;mo form=&#34;prefix&#34; stretchy=&#34;false&#34;&gt;(&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mo form=&#34;postfix&#34; stretchy=&#34;false&#34;&gt;)&lt;/mo&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mo fence=&#34;true&#34; form=&#34;postfix&#34; stretchy=&#34;true&#34;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;/mrow&gt;&lt;annotation encoding=&#34;application/x-tex&#34;&gt;C_{\mathrm{call}} = T \times \left[(1-h) \times P_{\mathrm{in}} + h \times P_{\mathrm{cache}}\right] = T \times P_{\mathrm{in}} \times \left[(1-h) + h \times r\right]&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/div&gt;&#xA;&lt;p&gt;where &lt;code&gt;T&lt;/code&gt; is the number of input tokens, &lt;code&gt;h&lt;/code&gt; is the cache hit rate, and &lt;code&gt;r = P_cache / P_in&lt;/code&gt; is the ratio of cached-input price to uncached-input price. Multiplying by the number of calls &lt;code&gt;N&lt;/code&gt; per turn separates the before/after ratio into three independent factors:&lt;/p&gt;&#xA;&lt;div class=&#34;math&#34; tabindex=&#34;0&#34;&gt;&lt;math display=&#34;block&#34; style=&#34;font-feature-settings: &#39;dtls&#39; off;&#34; xmlns=&#34;http://www.w3.org/1998/Math/MathML&#34;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mpadded lspace=&#34;0&#34;&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;b&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;e&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;f&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;o&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;r&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;e&lt;/mi&gt;&lt;/mpadded&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mpadded lspace=&#34;0&#34;&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;a&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;f&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;t&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;e&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;r&lt;/mi&gt;&lt;/mpadded&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mpadded lspace=&#34;0&#34;&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;o&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;l&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;d&lt;/mi&gt;&lt;/mpadded&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mpadded lspace=&#34;0&#34;&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;n&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;e&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;w&lt;/mi&gt;&lt;/mpadded&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mpadded lspace=&#34;0&#34;&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;o&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;l&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;d&lt;/mi&gt;&lt;/mpadded&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mpadded lspace=&#34;0&#34;&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;n&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;e&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;w&lt;/mi&gt;&lt;/mpadded&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mo form=&#34;prefix&#34; stretchy=&#34;false&#34;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mpadded lspace=&#34;0&#34;&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;o&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;l&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;d&lt;/mi&gt;&lt;/mpadded&gt;&lt;/msub&gt;&lt;mo form=&#34;postfix&#34; stretchy=&#34;false&#34;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mo form=&#34;prefix&#34; stretchy=&#34;false&#34;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mpadded lspace=&#34;0&#34;&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;n&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;e&lt;/mi&gt;&lt;mi mathvariant=&#34;normal&#34;&gt;w&lt;/mi&gt;&lt;/mpadded&gt;&lt;/msub&gt;&lt;mo form=&#34;postfix&#34; stretchy=&#34;false&#34;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;/mrow&gt;&lt;annotation encoding=&#34;application/x-tex&#34;&gt;\frac{C_{\mathrm{before}}}{C_{\mathrm{after}}} = \frac{N_{\mathrm{old}}}{N_{\mathrm{new}}} \times \frac{T_{\mathrm{old}}}{T_{\mathrm{new}}} \times \frac{f(h_{\mathrm{old}})}{f(h_{\mathrm{new}})}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/div&gt;&#xA;&lt;p&gt;where &lt;span class=&#34;math-inline&#34;&gt;&lt;math display=&#34;inline&#34; style=&#34;font-feature-settings: &#39;dtls&#39; off;&#34; xmlns=&#34;http://www.w3.org/1998/Math/MathML&#34;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mo form=&#34;prefix&#34; stretchy=&#34;false&#34;&gt;(&lt;/mo&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mo form=&#34;postfix&#34; stretchy=&#34;false&#34;&gt;)&lt;/mo&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo form=&#34;prefix&#34; stretchy=&#34;false&#34;&gt;(&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mo form=&#34;postfix&#34; stretchy=&#34;false&#34;&gt;)&lt;/mo&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&#34;application/x-tex&#34;&gt;f(h) = (1-h) + h \times r&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;. Each of the three factors is grounded in real measurements:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;N_old / N_new = 2–3&lt;/strong&gt;: pure text turns drop from 2 calls to 1, and reply + sticker turns drop from 3 calls to 1. This is structural—no estimation involved;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;T_old / T_new ≈ 70K / 52K ≈ 1.35&lt;/strong&gt;: stripping the unused tool schemas (49.5 KB), dynamic sticker catalog (18.3 KB), and repeated message headers removes ~20K tokens per request;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;h_new = 99.7%&lt;/strong&gt; is measured in production; I set &lt;code&gt;h_old = 95%&lt;/code&gt; to be generous to upstream&#39;s automatic prefix caching, which works well on ordinary turns and only loses its prefix when &lt;code&gt;MEMORY.md&lt;/code&gt; is rewritten.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Using official provider pricing as of 2026-08-03—DeepSeek V4 Flash at $0.0028/$0.14 = &lt;strong&gt;1/50&lt;/strong&gt;, Claude Sonnet 4.6 at 1/10, Kimi K2.6 at ~1/6, and Doubao seed-1.6 at 1/5—and plugging in conservative numbers (&lt;code&gt;N&lt;/code&gt; ratio = 2, &lt;code&gt;h_old&lt;/code&gt; = 95%):&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Model&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;r&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;f(95%) / f(99.7%)&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Total Factor 2 × 1.35 × f-ratio&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Savings&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;DeepSeek V4 Flash&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1/50&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;3.0&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;≈ 8.1×&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;≈ 88%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Claude Sonnet 4.6&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1/10&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1.4&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;≈ 3.8×&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;≈ 74%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Kimi K2.6&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;≈1/6&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1.2&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;≈ 3.3×&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;≈ 70%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;The pattern is obvious: the steeper the cache discount, the more leverage you get from pushing the hit rate to 99.7%—DeepSeek&#39;s 50× cache discount pushes total savings close to 90%. Meanwhile, the call-count factor &lt;code&gt;N&lt;/code&gt; doesn&#39;t depend on caching at all; it&#39;s free money. This matches what I see on my actual billing dashboard: costs dropped to well under 1/5 of what they were, and the conservative formula gives ~1/8 on DeepSeek even before counting the eliminated output tokens.&lt;/p&gt;&#xA;&lt;h2 id=&#34;closing-thoughts&#34;&gt;Closing Thoughts&lt;/h2&gt;&#xA;&lt;p&gt;All I really did was ask one question at every step of the pipeline: &lt;strong&gt;when you put a general-purpose agent framework into a high-frequency group chat, is this read or this LLM call actually necessary?&lt;/strong&gt; Don&#39;t make an extra call just to confirm a sent message, combine text + reply + sticker into a single call, push volatile files to the tail of the prompt prefix, don&#39;t send a single byte of unused tool schemas, and let a cheap small vision model look at images first.&lt;/p&gt;&#xA;&lt;p&gt;Once again, credit goes to upstream for building a solid foundation: the tool loop, history projection, and channel abstractions are cleanly separated. The reason I could pull off this degree of specialization in a little over a week is precisely because those boundaries were well drawn—wrapping the provider for terminal &lt;code&gt;send&lt;/code&gt; without touching the core loop, and filtering tools before schema generation, both plugged cleanly into seams the architecture already had. If your use case is &amp;quot;an agent that does multi-step work,&amp;quot; upstream&#39;s defaults are probably right for you; if, like me, you just want a talkative resident in your Telegram group that won&#39;t burn through your wallet, I hope these notes help.&lt;/p&gt;&#xA;</description>
      <category>Tech</category>
      <pubDate>Mon, 03 Aug 2026 00:00:00 +0000</pubDate>
      <guid>https://mizore.blog/en/posts/making-memoh-cheaper-on-telegram/</guid>
    </item>
  </channel>
</rss>