Skip to content

1 min read

One door for every AI call

Sovica Engineering Platform

Table of Contents

Sovica has dozens of metered AI features: note drafting, dictation, summaries, letters, report questions, review replies. They all call the model through one method, AiService.run(feature, call). Nothing else in the API talks to the provider, which makes metering, refunds and provenance one problem instead of dozens.

Charge before the call

Credits come out of the clinic’s shared balance in a transaction, along with a pending row in ai.usage. Only then does the model get called. Two uses can’t both spend the last credits, because the charge has already happened by the time either one reaches the provider.

The model call itself runs outside any transaction. A long request must not hold a database connection or a row lock.

Refund on failure

If the call throws, a second transaction writes a refund entry to the credit ledger and marks the usage failed. The ledger keeps both entries, so the history stays true. Reports on AI use count only succeeded rows, so a clinic is never charged for nothing.

Which instructions produced this?

The provider handed to each feature is wrapped so that it records the system prompts it sends. Their hash becomes the prompt version:

const promptVersion = () =>
  systems.length
    ? createHash('sha256').update(systems.join('\n---\n')).digest('hex').slice(0, 12)
    : null;

Stored on the usage row with the model and token counts.

Nobody has to remember to bump a version number. If a prompt changes, the hash changes. A successful use also writes an ai.used audit event in the same transaction as its usage row.

Tests never call a model

With AI_PROVIDER=stub, which is what tests and local development use, features return canned output through the same path. Charging, refunds and audit all run for real. The model is the only part swapped out.

The model itself is one setting, AI_MODEL, and because every call already carries its feature key, a per-feature model would be a small change in one method.

1,903 pull requests merged in the past year

Ready to redefine how the world’s clinics run?

Careers at Sovica