It was one line of code. So why did it need an SDK?

by•

Last time I wrote about , no idea which feature spent it, so I built a tiny logger. One line after every LLM call, sending model and token counts to my endpoint.

That line still exists. So the question I kept asking myself: if the integration is one line, what’s an SDK for? (an "SDK" sounded very cool in my head at that time, someone who -before making this product- had no clue what an SDK is btw).

The first version was a raw fetch call. It worked fine with one provider and one model, which is the setup where everything works.

Then I started reading other people’s usage objects, and the old routine kicked back in: open a docs page, hit a word I didn’t know, open another tab to look it up, repeat.

Cached tokens: OpenAI counts them inside the prompt number, Anthropic reports them next to it. Get that backwards and the math breaks. On a request with 10,000 prompt tokens, 8,000 cached, at $2 per million input and $0.20 cached, the real cost is $0.0056. Read it the wrong way and you get $0.0216. Almost 4x, on every warm-cache call.

Reasoning tokens: Anthropic puts thinking inside output_tokens, OpenAI reports it separately. Pass it twice and you’ve paid twice on paper.

Idempotency, which I’d never heard of: if a send fails and you retry, but the first one landed, that request now counts double. A stable key per event lets the server skip the repeat. Retry on timeouts and 5xx, never on a 4xx, since a bad payload stays bad.

None of that fits in a line someone copies off a docs page. So the SDK holds it. track() never throws or blocks your request. The adapters (fromOpenAIUsage(), fromAnthropicUsage()) only rename fields, and a missing field comes back undefined, never 0, because a 0 looks like a real number.

I still got one wrong. I double-charged cached and reasoning tokens on OpenAI-style responses until I fixed it on Oct 1. Embarrassing, but that’s building in public.

So, the answer: the one line was never the hard part. The SDK is everything that line can’t know. You still write one line; the 0.2.0 is what I had to learn so you don’t.

llmtrack.track({ provider: 'openai', model: completion.model, feature: 'summarize',
  ...fromOpenAIUsage(completion.usage) });

or .

4 views

Add a comment

Replies

Be the first to reply

Have a question or a thought to share? Add a comment above to start the conversation.