<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Programming on blog.iankulin.com</title><link>https://blog.iankulin.com/tags/programming/</link><description>Recent content in Programming on blog.iankulin.com</description><generator>Hugo</generator><language>en-AU</language><lastBuildDate>Sat, 05 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.iankulin.com/tags/programming/index.xml" rel="self" type="application/rss+xml"/><item><title>Using LLMs programmatically</title><link>https://blog.iankulin.com/using-llms-programmatically/</link><pubDate>Sat, 05 Sep 2026 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/using-llms-programmatically/</guid><description>&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/using-llms-programmatically_stone_tool_use_by_a_capuchin_monkey_hu_ed6fa2df94ddc756.webp" width="600" height="400" alt="Stone tool use by a capuchin monkey - wikimedia" loading="eager" fetchpriority="high" decoding="async"&gt;&lt;/p&gt;&#10;&lt;p&gt;About a year ago (when everyone else was) I built an &lt;a href="https://github.com/IanKulin/aichat"&gt;AI chat app&lt;/a&gt;. At the time I was excited about the &lt;a href="https://vercel.com/docs/ai-sdk"&gt;Vercel AI SDK&lt;/a&gt; for some reason. The industry is so standardised on the &lt;a href="https://developers.openai.com/api/reference/overview"&gt;OpenAI REST API&lt;/a&gt; that I wouldn&amp;rsquo;t bother using a wrapper like the Vercel one now unless I was using Next or one of the other big frameworks.&lt;/p&gt;&#10;&lt;p&gt;If you haven&amp;rsquo;t used the API in an app before to make use of LLM functionality from your software, it&amp;rsquo;s pretty simple. This post sets out a minimal demo of doing exactly that.&lt;/p&gt;&#10;&lt;h2 id="api-key"&gt;API Key&lt;/h2&gt;&#10;&lt;p&gt;To use a commercial LLM over the web, you&amp;rsquo;re going to need to create an account with them, add some credit then create an API key to use those credits. The exact process varies - Gemini seems to want a subscription at the moment, but &lt;a href="https://claude.ai/settings/billing"&gt;Anthropic&lt;/a&gt;, &lt;a href="https://platform.deepseek.com"&gt;Deepseek&lt;/a&gt;, &lt;a href="https://platform.openai.com"&gt;Open AI&lt;/a&gt;, and all the others work this way.&lt;/p&gt;&#10;&lt;p&gt;I generally use &lt;a href="https://openrouter.ai/"&gt;OpenRouter&lt;/a&gt; - they provide simple access to a heap of different models, and it saves me from leaving $4.32 credit in ten different places around the web. I don&amp;rsquo;t love that &lt;a href="https://openrouter.ai/blog/announcements/openrouter-is-joining-stripe/"&gt;Stripe has bought them&lt;/a&gt; for so much, but they haven&amp;rsquo;t enshitified yet so they&amp;rsquo;re still my favourite dollars-to-tokens provider. We&amp;rsquo;ll use OpenRouter for this example.&lt;/p&gt;&#10;&lt;p&gt;Once you have an API key (I generate one for every project so I can scope it, and see the billing per project), let&amp;rsquo;s drop it in the &lt;code&gt;.env&lt;/code&gt; file:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;OPENROUTER_API_KEY&lt;span style="color:#81a1c1"&gt;=&lt;/span&gt;sk-or-v1-cccccccd8ccccc19dcccc80ccc376ccc70accc84ccca6ccc9fccc47ccc5cccd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MODEL_NAME&lt;span style="color:#81a1c1"&gt;=&lt;/span&gt;z-ai/glm-5.3-flash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="models"&gt;Models&lt;/h2&gt;&#10;&lt;p&gt;You can see I&amp;rsquo;ve also set an environment variable for the model name. We are spoiled for choice when it comes to models. I usually start on the &lt;a href="https://openrouter.ai/models?output_modalities=text"&gt;OpenRouter model comparison&lt;/a&gt; page. Most of the tasks I use LLMs for are summarising or sentiment analysis - both tasks almost any model does well these days, so I put the price slider down to 10c per million then scroll through looking for flash models I recognise. If you click in to the model description, the two part model name you want will be near the top with a copy button.&lt;/p&gt;&#10;&lt;h2 id="fetch"&gt;Fetch&lt;/h2&gt;&#10;&lt;p&gt;For this simplest possible demo, we&amp;rsquo;re going to hit the API endpoint, wait for the response then spit it out to the console. No streaming, and very little error checking etc. Here&amp;rsquo;s the guts of it:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;async&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;function&lt;/span&gt; callLLM&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;prompt&lt;span style="color:#eceff4"&gt;)&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; res &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;await&lt;/span&gt; fetch&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#39;https://openrouter.ai/api/v1/chat/completions&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; method&lt;span style="color:#81a1c1"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; headers&lt;span style="color:#81a1c1"&gt;:&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Authorization&lt;span style="color:#81a1c1"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;`Bearer &lt;/span&gt;&lt;span style="color:#a3be8c"&gt;${&lt;/span&gt;OPENROUTER_API_KEY&lt;span style="color:#a3be8c"&gt;}&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;`&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#39;HTTP-Referer&amp;#39;&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#39;https://blog.iankulin.com&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#39;X-Title&amp;#39;&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#39;llm-call demo script&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; body&lt;span style="color:#81a1c1"&gt;:&lt;/span&gt; JSON&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;stringify&lt;span style="color:#eceff4"&gt;({&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; model&lt;span style="color:#81a1c1"&gt;:&lt;/span&gt; MODEL_NAME&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; messages&lt;span style="color:#81a1c1"&gt;:&lt;/span&gt; &lt;span style="color:#eceff4"&gt;[{&lt;/span&gt; role&lt;span style="color:#81a1c1"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; content&lt;span style="color:#81a1c1"&gt;:&lt;/span&gt; prompt &lt;span style="color:#eceff4"&gt;}],&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;}),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;});&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;if&lt;/span&gt; &lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;!&lt;/span&gt;res&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;ok&lt;span style="color:#eceff4"&gt;)&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;throw&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;new&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;Error&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;`OpenRouter API error &lt;/span&gt;&lt;span style="color:#a3be8c"&gt;${&lt;/span&gt;res&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;status&lt;span style="color:#a3be8c"&gt;}&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;: &lt;/span&gt;&lt;span style="color:#a3be8c"&gt;${&lt;/span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;await&lt;/span&gt; res&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;text&lt;span style="color:#eceff4"&gt;()&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;}&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;`&lt;/span&gt;&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; data &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;await&lt;/span&gt; res&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;json&lt;span style="color:#eceff4"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; text &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; data&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;choices&lt;span style="color:#81a1c1"&gt;?&lt;/span&gt;&lt;span style="color:#eceff4"&gt;.[&lt;/span&gt;&lt;span style="color:#b48ead"&gt;0&lt;/span&gt;&lt;span style="color:#eceff4"&gt;]&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;?&lt;/span&gt;&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;message&lt;span style="color:#81a1c1"&gt;?&lt;/span&gt;&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;content&lt;span style="color:#81a1c1"&gt;?&lt;/span&gt;&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;trim&lt;span style="color:#eceff4"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;if&lt;/span&gt; &lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;!&lt;/span&gt;text&lt;span style="color:#eceff4"&gt;)&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;throw&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;new&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;Error&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;`No content in OpenRouter response: &lt;/span&gt;&lt;span style="color:#a3be8c"&gt;${&lt;/span&gt;JSON&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;stringify&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;data&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;}&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;`&lt;/span&gt;&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;return&lt;/span&gt; text&lt;span style="color:#eceff4"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="request"&gt;Request&lt;/h3&gt;&#10;&lt;p&gt;We&amp;rsquo;re POSTing to the endpoint &lt;code&gt;'https://openrouter.ai/api/v1/chat/completions'&lt;/code&gt; with a header and a body.&lt;/p&gt;&#10;&lt;p&gt;The header must have the &lt;code&gt;Authorization&lt;/code&gt; so the API can use your API key for billing. In this example we&amp;rsquo;re also providing an &lt;code&gt;HTTP-Referer'&lt;/code&gt; and &lt;code&gt;'X-Title'&lt;/code&gt;. These are both optional, but will appear on your billing page which is helpful for figuring out what&amp;rsquo;s going on - for example if you&amp;rsquo;ve used the wrong API key, or your app is making calls for different tasks. There&amp;rsquo;s also an &lt;a href="https://openrouter.ai/rankings#apps"&gt;OpenRouter &amp;ldquo;Top Apps&amp;rdquo;&lt;/a&gt; ranking. If you open up an unguarded chat interface connected to a frontier model you can appear on that page briefly before your credit runs out.&lt;/p&gt;&#10;&lt;p&gt;In the body, we&amp;rsquo;re including the &lt;code&gt;model&lt;/code&gt; name we discussed earlier, the &lt;code&gt;role&lt;/code&gt; (this is the &lt;code&gt;user&lt;/code&gt;, our response will be from the &lt;code&gt;assistant&lt;/code&gt;) and the actual message &lt;code&gt;content&lt;/code&gt; - ie our prompt.&lt;/p&gt;&#10;&lt;h4 id="roles"&gt;Roles&lt;/h4&gt;&#10;&lt;p&gt;In a normal chat app, you need to send the whole conversation on every round, so you&amp;rsquo;d be sending back &lt;code&gt;user&lt;/code&gt; and &lt;code&gt;assistant&lt;/code&gt; message content of the whole chat since this session started. In our demo, we&amp;rsquo;re only ever sending a single &lt;code&gt;user&lt;/code&gt; prompt.&lt;/p&gt;&#10;&lt;p&gt;There&amp;rsquo;s also a &lt;code&gt;system&lt;/code&gt; role - you might use this as some setup at the start of a session - the &amp;ldquo;You are an expert on naming cats who is always helpful&amp;rdquo; type thing.&lt;/p&gt;&#10;&lt;h3 id="response"&gt;Response&lt;/h3&gt;&#10;&lt;p&gt;When we get our response back, we&amp;rsquo;re extracting out the text only with &lt;code&gt;const text = data.choices?.[0]?.message?.content?.trim();&lt;/code&gt; I&amp;rsquo;m sure this immediately prompts you to wonder what other goodies are in the JSON that comes back. The definition for it is &lt;a href="https://developers.openai.com/api/reference/resources/responses/methods/retrieve"&gt;here&lt;/a&gt;, but there is a small amount of variability in how each company and model fill this out.&lt;/p&gt;&#10;&lt;p&gt;It might be fun to look at the actual response I got for &amp;ldquo;Is Sam a good cat name?&amp;rdquo;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;gen-1788593821-aJWuwpz3bKFb026SiqDh&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;object&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;chat.completion&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;created&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#b48ead"&gt;1788593821&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;model&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;z-ai/glm-5.3-flash&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;provider&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;Z.AI&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;system_fingerprint&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;null&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;service_tier&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;null&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;choices&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#eceff4"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;index&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#b48ead"&gt;0&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;logprobs&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;null&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;finish_reason&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;stop&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;native_finish_reason&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;stop&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;message&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;role&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;assistant&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;Sam is a solid choice! It&amp;#39;s short and easy to call out across the house, which matters more than you might think when you&amp;#39;re summoning a cat. It also works for any gender, and there&amp;#39;s something charming about giving cats classic human names—it gives them a bit of a \&amp;#34;little roommate\&amp;#34; personality.\n\nThe only knock against it is that it&amp;#39;s fairly common, so you probably won&amp;#39;t be the only Sam at the vet&amp;#39;s office. But if you like simple, timeless names, it&amp;#39;s hard to go wrong.\n\nAre you naming a new cat?&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;refusal&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;null&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;reasoning&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;The user is asking a casual, subjective question about whether \&amp;#34;Sam\&amp;#34; is a good cat name. This is a light, conversational question. There&amp;#39;s no factual answer here—it&amp;#39;s about opinions and considerations.\n\nWhat makes this question interesting? A few angles:\n1. \&amp;#34;Sam\&amp;#34; is actually a pretty popular cat name—it&amp;#39;s short, easy to say, has a nice sound\n2. It works for both male and female cats (Sam can be short for Samantha)\n3. Cat name considerations: short names with certain sounds are easier for cats to recognize, names ending in vowel sounds or with \&amp;#34;ee\&amp;#34; sounds are often recommended, but short one-syllable names like Sam work well too\n4. It&amp;#39;s a human name, which many people enjoy for pets—the \&amp;#34;little person\&amp;#34; vibe\n5. Famous Sams: Sam from the Lord of the Rings (Samwise), Uncle Sam, etc.\n\nThe question is conversational and casual, so my response should match that tone. I shouldn&amp;#39;t over-formalize this or turn it into an essay. A friendly, conversational response works best.\n\nShould I just say \&amp;#34;yes\&amp;#34;? That&amp;#39;s boring and not helpful. Should I give a thoughtful take? Yes, but briefly. I can affirm it&amp;#39;s a good name and mention why—briefly—and maybe note considerations.\n\nFormat considerations: This should be conversational prose, no headers or bullet points needed for such a casual question. Keep it relatively short—a few sentences to a short paragraph or two. I could share a genuine opinion since the person is asking for one.\n\nLet me think about what&amp;#39;s genuinely good about \&amp;#34;Sam\&amp;#34; as a cat name:\n- One syllable, easy to call across the house\n- Ends in a consonant but the \&amp;#34;m\&amp;#34; is soft\n- Gender-neutral (Sam/Samuel/Samantha)\n- It&amp;#39;s classic and won&amp;#39;t feel dated\n- Human names for cats are charming\n- Easy for kids/guests to remember\n\nPotential downsides (to be balanced):\n- Very common, so less unique\n- No particular meaning\n\nI think a good response affirms it&amp;#39;s a solid choice, gives a couple reasons why, maybe adds a light touch. I shouldn&amp;#39;t hedge endlessly or write a treatise. This is chitchat-adjacent, so warmth and brevity matter.\n\nLet me draft:\n\n\&amp;#34;Sam is a great cat name! It&amp;#39;s short and punchy, which makes it easy to call out, and it works whether you have a boy or girl cat. There&amp;#39;s also something charming about giving cats classic human names—it gives them a bit of personality, like they&amp;#39;re a little roommate rather than a pet. Plus it&amp;#39;s timeless; Sam won&amp;#39;t sound dated in ten years the way trendier names might.\n\nThe only downside is that it&amp;#39;s fairly common, so if uniqueness matters to you, there might be other Sams at the vet&amp;#39;s office. But honestly, a simple, friendly name suits most cats well. What kind of cat are you naming?\&amp;#34;\n\nEnding with a question is nice here—it&amp;#39;s a natural conversational move and shows interest. Though I shouldn&amp;#39;t always end with questions, in this casual context it feels appropriate and warm. Actually, let me consider: the guidance says I can ask follow-up questions when appropriate in conversational contexts. This seems like a good spot for it—someone naming a cat might appreciate engagement.\n\nLength: Keep it to a short paragraph or two. No lists needed.&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;reasoning_details&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#eceff4"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;reasoning.text&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;text&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;The user is asking a casual, subjective question about whether \&amp;#34;Sam\&amp;#34; is a good cat name. This is a light, conversational question. There&amp;#39;s no factual answer here—it&amp;#39;s about opinions and considerations.\n\nWhat makes this question interesting? A few angles:\n1. \&amp;#34;Sam\&amp;#34; is actually a pretty popular cat name—it&amp;#39;s short, easy to say, has a nice sound\n2. It works for both male and female cats (Sam can be short for Samantha)\n3. Cat name considerations: short names with certain sounds are easier for cats to recognize, names ending in vowel sounds or with \&amp;#34;ee\&amp;#34; sounds are often recommended, but short one-syllable names like Sam work well too\n4. It&amp;#39;s a human name, which many people enjoy for pets—the \&amp;#34;little person\&amp;#34; vibe\n5. Famous Sams: Sam from the Lord of the Rings (Samwise), Uncle Sam, etc.\n\nThe question is conversational and casual, so my response should match that tone. I shouldn&amp;#39;t over-formalize this or turn it into an essay. A friendly, conversational response works best.\n\nShould I just say \&amp;#34;yes\&amp;#34;? That&amp;#39;s boring and not helpful. Should I give a thoughtful take? Yes, but briefly. I can affirm it&amp;#39;s a good name and mention why—briefly—and maybe note considerations.\n\nFormat considerations: This should be conversational prose, no headers or bullet points needed for such a casual question. Keep it relatively short—a few sentences to a short paragraph or two. I could share a genuine opinion since the person is asking for one.\n\nLet me think about what&amp;#39;s genuinely good about \&amp;#34;Sam\&amp;#34; as a cat name:\n- One syllable, easy to call across the house\n- Ends in a consonant but the \&amp;#34;m\&amp;#34; is soft\n- Gender-neutral (Sam/Samuel/Samantha)\n- It&amp;#39;s classic and won&amp;#39;t feel dated\n- Human names for cats are charming\n- Easy for kids/guests to remember\n\nPotential downsides (to be balanced):\n- Very common, so less unique\n- No particular meaning\n\nI think a good response affirms it&amp;#39;s a solid choice, gives a couple reasons why, maybe adds a light touch. I shouldn&amp;#39;t hedge endlessly or write a treatise. This is chitchat-adjacent, so warmth and brevity matter.\n\nLet me draft:\n\n\&amp;#34;Sam is a great cat name! It&amp;#39;s short and punchy, which makes it easy to call out, and it works whether you have a boy or girl cat. There&amp;#39;s also something charming about giving cats classic human names—it gives them a bit of personality, like they&amp;#39;re a little roommate rather than a pet. Plus it&amp;#39;s timeless; Sam won&amp;#39;t sound dated in ten years the way trendier names might.\n\nThe only downside is that it&amp;#39;s fairly common, so if uniqueness matters to you, there might be other Sams at the vet&amp;#39;s office. But honestly, a simple, friendly name suits most cats well. What kind of cat are you naming?\&amp;#34;\n\nEnding with a question is nice here—it&amp;#39;s a natural conversational move and shows interest. Though I shouldn&amp;#39;t always end with questions, in this casual context it feels appropriate and warm. Actually, let me consider: the guidance says I can ask follow-up questions when appropriate in conversational contexts. This seems like a good spot for it—someone naming a cat might appreciate engagement.\n\nLength: Keep it to a short paragraph or two. No lists needed.&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;format&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;unknown&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;index&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#b48ead"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;],&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;usage&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;prompt_tokens&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#b48ead"&gt;19&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;completion_tokens&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#b48ead"&gt;822&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;total_tokens&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#b48ead"&gt;841&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;cost&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#b48ead"&gt;0.000206925&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;is_byok&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;false&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;prompt_tokens_details&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;cached_tokens&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#b48ead"&gt;0&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;cache_write_tokens&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#b48ead"&gt;0&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;audio_tokens&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#b48ead"&gt;0&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;video_tokens&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#b48ead"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;cost_details&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;upstream_inference_cost&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#b48ead"&gt;0.000206925&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;upstream_inference_prompt_cost&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#b48ead"&gt;0.000001425&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;upstream_inference_completions_cost&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#b48ead"&gt;0.0002055&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;completion_tokens_details&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;reasoning_tokens&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#b48ead"&gt;706&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;image_tokens&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#b48ead"&gt;0&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;&amp;#34;audio_tokens&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#b48ead"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m not going to go though all of this, but to just pick out a couple of things:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;model/provider - these are the actual ones used. This is helpful since you&amp;rsquo;ll sometimes use a generic model name like &amp;ldquo;glm-flash&amp;rdquo; which will just be mapped to the current version. That way your program won&amp;rsquo;t break every time a model is retired. OpenRouter (as suggested by the name) might route your request to other providers (there&amp;rsquo;s many providers of all the good open weight models) based on cost or workload etc. If you were tracking down a response time issue this is a good field to look at.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;finish reasons - you might run out of credit or hit a max_tokens limit part way through a response forcing an early completion. &lt;code&gt;stop&lt;/code&gt; is the happy path.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;reasoning - is always fun the first few times you see it. I&amp;rsquo;m annoyed when LLM&amp;rsquo;s ask me engagement bait questions at the end, so I was interested to see how that came about. If the token usage for a request seems high, this train of thought is usually where that&amp;rsquo;s happening.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;cost - if you&amp;rsquo;re building LLM functionality into an app this is probably crucial&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;is_byok - &amp;ldquo;Bring Your Own Key&amp;rdquo; - it&amp;rsquo;s possible to use your Anthropic or other key through OpenRouter. I don&amp;rsquo;t know why you&amp;rsquo;d do that, but it would show up here if that&amp;rsquo;s what&amp;rsquo;s been used for billing this response.&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="llm-use-in-apps"&gt;LLM use in apps&lt;/h2&gt;&#10;&lt;p&gt;When I updated my blog to show post summaries instead of the first paragraph, I wrote a script not unlike the one above that sent off the post text with a prompt asking for a summary which was then inserted back in the post to be used by Hugo. That&amp;rsquo;s the sort of thing that plays to LLM strengths - language processing. I&amp;rsquo;ll probably do something similar in the future to improve the tags.&lt;/p&gt;&#10;&lt;p&gt;Demo &lt;a href="https://github.com/IanKulin/demo-llm-calling"&gt;source&lt;/a&gt;&lt;/p&gt;&#10;</description></item></channel></rss>