<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Chiheb Nabil</title>
    <description>The latest articles on DEV Community by Chiheb Nabil (@chihebnabil).</description>
    <link>https://dev.to/chihebnabil</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F460640%2F00cb7bf4-5eb1-46bf-8578-7845bcc7c720.jpeg</url>
      <title>DEV Community: Chiheb Nabil</title>
      <link>https://dev.to/chihebnabil</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chihebnabil"/>
    <language>en</language>
    <item>
      <title>Your AI calls are already fetch() calls. Track them with one flag.</title>
      <dc:creator>Chiheb Nabil</dc:creator>
      <pubDate>Thu, 03 Sep 2026 13:16:38 +0000</pubDate>
      <link>https://dev.to/chihebnabil/your-ai-calls-are-already-fetch-calls-track-them-with-one-flag-1f63</link>
      <guid>https://dev.to/chihebnabil/your-ai-calls-are-already-fetch-calls-track-them-with-one-flag-1f63</guid>
      <description>&lt;p&gt;If you ship an app with AI features, you probably know roughly what you spend per month the provider dashboard tells you that. What you usually &lt;em&gt;don't know&lt;/em&gt; is which feature, which route, or which user is burning the tokens. The provider dashboard aggregates. &lt;/p&gt;

&lt;p&gt;Your app doesn't.&lt;/p&gt;

&lt;p&gt;And your error tracker doesn't fill the gap either. It'll tell you a request failed, but it has no idea that request was a GPT-4o call that cost you four cents and took eight seconds.&lt;/p&gt;

&lt;p&gt;That's the problem FlareLog's AI observability is built around: treat AI calls as first-class log events with tokens, latency, cost in USD, tool calls, and errors without wrapping every call site in your codebase.&lt;/p&gt;

&lt;p&gt;Here's how it actually works, starting from the documented quick start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with zero config
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @flarelog/sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;flarelog&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@flarelog/sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;flarelog&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;
&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// → console (zero config)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No API key means it just logs to the console. Add a key and it ships to the dashboard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;FLARELOG_API_KEY&lt;/span&gt;=&lt;span class="n"&gt;fl_your_key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I like this setup because you can try it in an existing project without signing up for anything first. Console logging isn't exciting, but it means "install the SDK" isn't a commitment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one flag that matters: ai: true
&lt;/h2&gt;

&lt;p&gt;This is the part worth understanding. From the docs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;flarelog&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@flarelog/sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;flarelog&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FLARELOG_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// one flag — every fetch() to OpenAI/Anthropic/etc. is captured&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One flag. No provider wrappers, no &lt;code&gt;logAiCall()&lt;/code&gt; sprinkled through your handlers. Under the hood it instruments fetch, so every call to OpenAI, Anthropic, Cloudflare Workers AI, the Vercel AI SDK, or any OpenAI-compatible gateway gets captured tokens, latency, cost in USD, tool calls, and errors.&lt;/p&gt;

&lt;p&gt;Because it sits at the fetch level, your existing client code stays untouched. If your app already works, this doesn't change how it works &lt;/p&gt;

&lt;p&gt;it changes what you can see.&lt;/p&gt;

&lt;h2&gt;
  
  
  When you want more control
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ai: true&lt;/code&gt; is the zero-config path. When you need fine-grained behavior, pass a config object instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;flarelog&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FLARELOG_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;captureSamples&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;priceOverrides&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-4o&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things worth calling out here:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;priceOverrides&lt;/code&gt;exists because pricing is a moving target. If you're routing through a custom gateway, running a fine-tuned model, or a provider changed their rates before the SDK caught up, you set the per-token prices yourself and the cost math stays honest.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;captureSamples&lt;/code&gt;gives you request/response samples, which is the fastest way to answer "why did this specific call behave weird?"&lt;/p&gt;

&lt;h2&gt;
  
  
  Attach it manually (and detach it)
&lt;/h2&gt;

&lt;p&gt;If you'd rather control instrumentation explicitly say, only in certain environments — there's a direct API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;flarelog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;flarelogAI&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@flarelog/sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;flarelog&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FLARELOG_API_KEY&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;flarelogAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// handle.dispose() to remove instrumentation later&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Handy for tests, or for turning AI tracking on and off at runtime without rebuilding the logger.&lt;/p&gt;

&lt;h2&gt;
  
  
  The streaming gotcha you'll want to know early
&lt;/h2&gt;

&lt;p&gt;This is the kind of detail you'd normally discover in production, so here it is up front: OpenAI streaming doesn't report usage by default. If you want token capture on streamed responses, you have to opt in on the request itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.openai.com/v1/chat/completions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-4o&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;stream_options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;include_usage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// ← required for streaming token capture&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anthropic and Workers AI report usage automatically — no changes needed there. But if your streaming OpenAI calls show tokens of zero, this line is why.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this works on edge
&lt;/h2&gt;

&lt;p&gt;The SDK is zero-dependency, so there's nothing to audit and nothing to conflict with your bundle. It runs on Cloudflare Workers, Vercel, Node.js, and browsers. On Workers specifically, flushing uses &lt;code&gt;ctx.waitUntil&lt;/code&gt;, so your logs actually survive after the response is sent — a classic edge gotcha that most logging tools don't handle.&lt;/p&gt;

&lt;p&gt;It also does &lt;code&gt;W3C trace&lt;/code&gt; propagation, so an AI call shows up in the context of the request that triggered it, not as an isolated event.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lock-in question
&lt;/h2&gt;

&lt;p&gt;Fair to ask: does your observability data now live in one vendor's dashboard? FlareLog is OTLP-compatible, so it ships to Grafana, Honeycomb, Datadog, or any OTLP backend. The instrumentation lives in your code; where the data goes is your call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;The pitch is simple: AI calls are already &lt;code&gt;fetch()&lt;/code&gt;calls flowing through your app, and one flag turns them into structured, costed, searchable events. The full flow is four lines of setup, and the only real gotcha — streaming usage on OpenAI is one line in your request body.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links if you want to dig in:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://flarelog.dev/" rel="noopener noreferrer"&gt;FlareLog&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/@flarelog/sdk" rel="noopener noreferrer"&gt;SDK on npm&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.flarelog.dev/" rel="noopener noreferrer"&gt;Docs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://flarelog.dev/ai-observability" rel="noopener noreferrer"&gt;AI observability dashboard&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How are you tracking AI spend per feature right now provider dashboards, spreadsheets? Curious what's actually working for people.&lt;/p&gt;

</description>
      <category>observability</category>
      <category>ai</category>
      <category>typescript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Testing OpenAI integrations without paying per call</title>
      <dc:creator>Chiheb Nabil</dc:creator>
      <pubDate>Mon, 29 Jan 2024 15:27:54 +0000</pubDate>
      <link>https://dev.to/chihebnabil/openai-api-mock-for-devs-on-a-budget-2785</link>
      <guid>https://dev.to/chihebnabil/openai-api-mock-for-devs-on-a-budget-2785</guid>
      <description>&lt;p&gt;Testing code that calls the OpenAI API gets expensive fast. Every iteration costs money, you burn through rate limits, and CI pipelines need a real API key to run. So I built a small library that fakes the OpenAI API: &lt;a href="https://www.npmjs.com/package/openai-api-mock" rel="noopener noreferrer"&gt;openai-api-mock&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It works with anything that speaks the OpenAI API since the mock intercepts by base URL, it also covers &lt;strong&gt;OpenAI-compatible&lt;/strong&gt; providers like Azure OpenAI, Groq, Together, or a local Ollama instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem it solves
&lt;/h2&gt;

&lt;p&gt;While building a project that used function calling, I had to test structured responses over and over. Each run cost money, and I couldn't run tests in CI without exposing a key. I wanted something I could drop into a test setup and forget about, so I wrote it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;nstall it as a dev dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; openai-api-mock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then call one function before your code makes OpenAI requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mockOpenAIResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;openai-api-mock&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;mockOpenAIResponse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// from here on, every OpenAI API call returns a mock response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood it uses nock to intercept HTTP requests to the OpenAI API and &lt;code&gt;@faker-js/faker&lt;/code&gt; to generate the fake data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's new in 0.4.1
&lt;/h2&gt;

&lt;p&gt;Version 0.4.1 adds support for the embeddings endpoint — including deterministic vectors (same input → same output), all input types, and both &lt;code&gt;float&lt;/code&gt;and &lt;code&gt;base64&lt;/code&gt;encoding formats. This means you can test semantic search, RAG pipelines, and clustering with reproducible results.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Request base64-encoded embeddings&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-embedding-3-small&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;encoding_format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// base64 string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you hit a case it doesn't handle, open an issue on the repo. Feedback welcome.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/chihebnabil/openai-api-mock" rel="noopener noreferrer"&gt;Github Repo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>openai</category>
      <category>mock</category>
      <category>opensource</category>
      <category>npm</category>
    </item>
  </channel>
</rss>
