TypeScript SDK Budgets
Enforce Cloud-authoritative budgets, choose an outage posture, and understand run-scoped token leases.
The TypeScript SDK obtains budget authority before it dispatches a tracked provider call. Configure limits and their live enforcement mode in Solwyn Cloud; the SDK enforces the decision Cloud returns.
Handle a hard denial
An ordinary hard budget denial becomes BudgetExceededError before provider dispatch. A denial
whose period is run_stopped for the active run becomes RunStoppedError instead. The budget
error carries the live or retained values that produced the decision:
import { BudgetExceededError, Solwyn } from "@solwyn/sdk";
import OpenAI from "openai";
const solwynApiKey = process.env.SOLWYN_API_KEY;
if (!solwynApiKey) throw new Error("SOLWYN_API_KEY is required");
const client = new Solwyn(new OpenAI(), { apiKey: solwynApiKey });
try {
await client.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "Summarize today's queue." }],
max_completion_tokens: 128,
});
} catch (error: unknown) {
if (!(error instanceof BudgetExceededError)) throw error;
console.error({
projectId: error.projectId,
budgetLimit: error.budgetLimit,
currentUsage: error.currentUsage,
estimatedCost: error.estimatedCost,
budgetPeriod: error.budgetPeriod,
mode: error.mode,
});
} finally {
await client.close();
}See typed errors for the complete error hierarchy.
Live mode comes from Solwyn Cloud
Every successful live budget check returns both an allowed verdict and a mode. That response is
authoritative for the call:
| Live Cloud response | SDK behavior |
|---|---|
| Allowed | Dispatch the provider call and retain any reservation for settlement. An allowed alert_only response at or above its limit also logs the budget warning, at most once every 30 seconds per client. |
Denied with mode: "alert_only" | Warn and dispatch the provider call. |
Denied with mode: "hard_deny" | Throw BudgetExceededError for an ordinary budget denial, or RunStoppedError for an active run_stopped denial; do not call the provider. |
Configure the project budget, scoped rules, and their modes in Solwyn Cloud. A hard-deny scoped rule can therefore block its matching call even when the project's general mode is alert-only.
budgetMode on the Solwyn constructor does not enable live hard-deny behavior. The SDK does not
send that option in BudgetCheckRequest; it is only the mode label attached to SDK-local outage
results. A local fail-closed result can deny even when that diagnostic label is "alert_only".
import { Solwyn } from "@solwyn/sdk";
import OpenAI from "openai";
const solwynApiKey = process.env.SOLWYN_API_KEY;
if (!solwynApiKey) throw new Error("SOLWYN_API_KEY is required");
const strictClient = new Solwyn(new OpenAI(), {
apiKey: solwynApiKey,
failOpen: false,
budgetMode: "hard_deny", // local outage-result label, not the live Cloud policy
});
await strictClient.close();The accepted values are "alert_only" and "hard_deny". See
configuration for environment-variable precedence and validation.
Admission and settlement
For an ordinary tracked text call, the SDK:
- Computes a length-based estimated input-token count inside your process.
- Checks the primary provider and model with Solwyn Cloud before any provider attempt.
- Dispatches only if the result allows it.
- Normalizes provider-reported usage and privately queues reservation settlement.
- Queues a content-free metadata event. A blocked call is reported as
budget_denied.
A caller's request AbortSignal also cancels the budget preflight; cancellation rejects without
being treated as a control-plane outage, and an already-aborted request skips budget I/O. With
less than 50 milliseconds left on the shared preflight deadline, the SDK skips network I/O,
applies local policy, and logs budget.preflight_skipped_deadline.
Settlement is automatic; there is no public confirmation method. Buffered calls settle after their
response is available. Streams settle exactly once when they end or are abandoned; see
streaming. Await client.close() so queued confirmations and events get
a bounded final flush.
Solwyn Cloud owns provider and model pricing. The SDK reports token counts and media quantities; it does not calculate the actual cost of successful calls.
Untagged calls outside a run can reuse an allowed check for the same provider/model/fallback/modality
chain for up to budgetCheckCacheTtl seconds (5 by default). Run-scoped and tagged checks bypass
that cache. Denials are never cached.
When the budget service is unreachable
The ordinary per-call path evaluates outage authority in this order:
- Preserve an applicable retained run stop or hard denial.
- If
failOpen: true(the default), allow and record the local fallback estimate. - If
failOpen: falseand no successful budget snapshot has ever been received, deny withdenyReason: "no_prior_budget_limit". - If
failOpen: falseand a snapshot exists, compare this process's current UTC-day local estimate bucket plus the new estimate with the last-known Cloud budget limit. Allow and accrue within the limit; otherwise deny withdenyReason: "local_budget_exceeded".
failOpen is consulted only after stronger authority. Setting it to true cannot reopen a hard
denial the SDK has already received for the applicable scope.
| Option | Default | Ordinary check-path outage behavior |
|---|---|---|
failOpen | true | Allow after retained-authority checks and add the estimate to the local UTC-day bucket. |
failOpen | false | Enforce against the last-known limit; deny when no prior limit exists. |
budgetMode | "alert_only" | Label SDK-local outage results; it does not replace the live Cloud mode. |
The fixed local estimate has exactly two uses
The SDK multiplies estimated input tokens by $0.00003 per token in exactly two places:
- Ordinary outage decisions and their in-process UTC-day estimate bucket.
- The
estimatedCostdiagnostic onBudgetExceededError, including an error produced by a live Cloud denial.
That constant is not a provider price, does not select routes, and does not settle successful calls. Cloud remains authoritative for real provider/model pricing.
Retained authority
A semantically valid hard denial remains authoritative during a later outage:
- Project-period authority applies across calls on the client.
agent_rundenials and run stops apply only to the exact run ID.- A tag-period denial is enforced for the checked tag selector but is not retained as future outage authority, because tags can change on the next call.
- A later applicable Cloud allow can clear older retained budget authority. Run stops have their own exact-ID lifecycle; see runs.
A response containing a run-control directive for a different run is treated as contract drift. For
an otherwise ordinary allow or budget denial, the SDK enforces that call's verdict without retaining
the tainted composite as future authority. A foreign run_stopped response is not trusted as a stop
and enters the configured outage path.
Run-scoped token leases
With leaseEnabled: true (the default), an eligible text call inside a Node run can reserve tokens
from local, bounded authority rather than perform a blocking budget check for every call:
import { Solwyn } from "@solwyn/sdk";
import { run } from "@solwyn/sdk/node";
import OpenAI from "openai";
const solwynApiKey = process.env.SOLWYN_API_KEY;
if (!solwynApiKey) throw new Error("SOLWYN_API_KEY is required");
const client = new Solwyn(new OpenAI(), { apiKey: solwynApiKey });
try {
await run("nightly-summary", async () => {
await client.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "Summarize the first batch." }],
max_completion_tokens: 128,
});
await client.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "Summarize the second batch." }],
max_completion_tokens: 128,
});
});
} finally {
await client.close();
}The first eligible call requests a grant. Later calls reserve estimated input tokens plus a
structural output bound from that grant. If no usable output cap is present, the reservation uses
leaseOutputBoundDefault (4096). Renewal is demand-driven, generation-fenced, and detached from
the call path. When a run finishes, its remaining authority is surrendered through one bounded
dispatcher per client, with at most four requests in flight and 64 waiting. A surrender that is
refused, overflows the queue, or passes its deadline is dropped and reported in an aggregated
lease.surrenders_dropped warning; the unused tokens then return when the lease expires.
close() drains outstanding surrenders within a separate one-second budget and logs any it could
not finish in lease.close_release_summary.
Lease eligibility is deliberately narrow:
| Uses a run lease | Uses the ordinary per-call check |
|---|---|
Untagged text call inside run(...) or RunHandle.activate(...) | Call outside a run |
| Model and fallback models covered by the grant | Any call with client, run, or per-call tags |
| No applicable retained hard denial or run stop | Media and embedding calls |
| Lease subsystem enabled and Cloud marks the run eligible | Model chain not yet covered by the grant, lease-ineligible run, or leaseEnabled: false |
When a per-call check allows a call whose model chain the lease does not cover, the SDK renews the lease in the background to cover that chain, and later calls on it use the lease. Widening to a more expensive model re-prices the lease, so every model's token grant shrinks. Denied, unreachable, tagged, and media calls never widen a lease. If Cloud refuses a grant with HTTP 409 or answers a renewal as ineligible, the run falls back to per-call checks for at most 150 seconds; after an ineligible renewal the SDK releases the lease and acquires a new one. Models that a widening renewal was refused for keep per-call checks for the rest of the run.
The grant is denominated in tokens, not dollars, and carries Cloud-selected posture and bounded
headroom for outages. While the grant is live, local reservations continue from its remaining
tokens. If the grant is exhausted while Cloud is reachable, the call returns to the per-call check.
During an outage, the holder can draw from the grant's headroom share; after that, the posture
carried by the grant decides whether hard-deny blocks or alert-only continues. After the lease
deadline, the grant's unreachable posture determines whether calls proceed uncounted for later
renewal reporting or enforce against the last-known share. Calls admitted against the outage share
or after lease expiry accrue the fixed local estimate in the current UTC-day bucket, and a
fail-open lease posture never relaxes a client configured with failOpen: false.
Tags stay on the live check path
Tags are explicit attribution labels supplied by your application. The SDK never infers them from prompts or responses. Keep them content-free—use stable labels such as tenant IDs, workflow names, or environments, and never put prompts, responses, personal data, or secrets in them.
Client, run, and per-call tag layers are merged for the call. The merged snapshot is sent on the
budget check so tag-scoped rules stay authoritative, and solwyn_tags is removed from intercepted
requests before provider dispatch. Because lease grants do not carry per-call tag authority, every
tagged call bypasses the run lease and performs the ordinary per-call check.
See runs and tags for merge precedence, validation, and detached run handles, and privacy for the outbound metadata boundary.
Relevant options
| Option | Default | Purpose |
|---|---|---|
failOpen | true | Select the ordinary outage posture after retained-authority checks. |
budgetMode | "alert_only" | Label SDK-local outage decisions only. |
budgetCheckTimeout | 1 | Budget preflight timeout cap in seconds; at least 0.1. A lease attempt and its per-call fallback share it. |
budgetCheckCacheTtl | 5 | Untagged, unscoped allow-cache lifetime in seconds; 0 disables it. |
leaseEnabled | true | Enable eligible run-scoped token leases. |
leaseOutputBoundDefault | 4096 | Output-token reservation for a lease-funded request without a usable cap. |
Use offline testing to exercise hard denials, outages, leases, and run-stop paths without Cloud or provider network traffic.