Contraire
by @anirudhux —
XLinkedIn
Build log

What we tried, what we changed

Each card is one decision from the build — the path we dropped, the one we kept, and the reason it changed.

01sarvam-105bthe council reasons

The model kept returning nothing

Tried

Raise max_tokens and let it reason freely

Moved to

reasoning_effort: low — there is no “off”

Reasoning is mandatory on 105B and counts against the output cap. Left free, it used the whole token budget, so the answer came back empty with finish reason “length”.

02text-lid + 105breplies in your language

A Hindi draft got answered in English

Tried

Assume the shared Sarvam pipeline would match the input language

Moved to

Detect the language on paste, then tell the model to reply in it

The prompts were written in English and nothing named a target language, so the council answered in English. Language detection now flows from the paste into every call.

03Doc AIreads your PDF

Parsed PDFs came back as garbage

Tried

Read the results response as plain JSON text

Moved to

Check for the gzip marker and unzip it by hand

Doc AI returns results gzipped but without a Content-Encoding header, so nothing unzips them automatically. We now sniff the first two bytes (1f 8b) and gunzip.

04Doc AIreads your PDF

Every upload was rejected with a 400

Tried

output_format: “markdown”

Moved to

output_format: “md”

The API rejected “markdown” outright. It only accepts “html” or “md”, which the docs don’t spell out.

05Mayura + 105bmeasured, not claimed

Saying “we support Hindi” on a hunch

Tried

Claim support because one Hindi run looked fine

Moved to

Run the full pipeline in Kannada, Hindi and Tamil and record the numbers

One good run isn’t evidence. We now record tokens, cost, how much of the output is in the native script, and any truncation — so the support claim is backed by data.

06sarvam-105bno dropped voices

One reader in a run came back blank

Tried

Take whatever the model returns on the first try

Moved to

Detect an empty, truncated reply and re-roll once

In one full run, a single persona hit the token cap and returned nothing. A guard now retries once before giving up, so a run doesn’t ship with a missing voice.

07Saarikahears your voice

The mic recording was rejected as an invalid file type

Tried

Send the clip as its real type, audio/webm;codecs=opus

Moved to

Send it as application/octet-stream

Saarika whitelists by the declared file type and rejects webm;codecs=opus — the exact thing a browser’s MediaRecorder produces — even though it decodes the audio fine. Sent as octet-stream, it sniffs the real container, and it works the same across Chrome, Firefox and Safari.