Repository navigation
Releases: DevMortimer/pi-typesafe
Releases · DevMortimer/pi-typesafe
Release list
v0.13.0
Changed
- A
boxquestion is refused with avalidationerror that names it.@typesafe-ai/sdk0.7.0 added the type, which locates a subject in the request's image; this package sendsnoul,choice, andscore, and its state carries no image. - A
nullstate is refused with avalidationerror that names it, because 0.7.0 typesstateas a non-null entry. - A token count the API did not report (
usage.input_tokensoroutput_tokensisnullin 0.7.0) adds nothing to the session or daily totals and costs nothing, and the result renders it asnot reportedinstead ofnull. - The package requires
@typesafe-ai/sdk0.7.0. - Requests are sent uncompressed. 0.7.0 compresses any body of 1 KiB or more with zstd by default, and none of this package's five backends is measured for that encoding.
v0.10.0
Added
- A
subqbackend for SubQ's decision model:createTypeSafe({ backend: "subq" })sends judgments toapi.subq.aiunder/v1/systemonewith the key fromSUBQ_API_KEY. The default model issubq-snap-preview, priced at $0.05 per million input tokens. Model ids go to SubQ unchanged. Its model list, under/v1/models, is public, solistModels()there does not verify the key. - Per-backend request limits.
BackendLimitsnames the questions in one request, the options in one Choice, and the levels in one Score;DEFAULT_BACKEND_LIMITSholds the schema's bounds, which apply to a backend that declares none. A registry entry or aBackendEndpointdeclares its own inlimits, and no limit can be above the schema's bound.subqtakes at most 16 questions, a Choice of at least 2 options, and a Score of at most 10 levels.ResolvedBackend.limitsandTypeSafe.limitsgive the active backend's limits without a request. chunkEvaluationRequesttakes abackendoption and chunks to that backend's question limit.
Changed
evaluate,evaluateMany, andevaluateAllrefuse a request over the backend's limits before they send it, with avalidationerror. Ontypesafe,openrouter,commandcode, andliquidthe limits are the schema's own, so nothing new is refused there.evaluateAllchunks to the client's question limit, andchunkEvaluationRequestto thebackendoption's: 16 onsubq, 32 elsewhere. AmaxQuestionsabove the limit is now capped at it; before,chunkEvaluationRequestmade chunks that larger, which the schema then refused.prepareEvaluationRequesttakes an optionallimits.- A backend that names
modelsFieldwithoutmodelsPathnow has its model list renamed to the field the SDK reads; before, the field was ignored unlessmodelsPathwas set too. No existing registry backend is affected. TypeSafeBackendnow includes"subq"; a consumer with an exhaustiveswitchover it sees a new member.
v0.9.1
Fixed
- The usage ledger lost counts when several processes ran at once. Each process read
usage.jsononce and then wrote its own copy over the file, so the last writer won: in a test, 2 processes making 200 updates each left 200, not 400. The spend that/typesafe statusreported fell short of the real use, and theusdPerDay,requestsPerDay, andinputTokensPerDaycaps did not stop at their limit. Each update now adds its count to the file's current content under a lock file next to it, andtoday(),blocked(), anddescribe()read the file, so the caps count every process. An update waits at most 200 milliseconds for the lock, takes over a lock older than 5 seconds, and keeps a count it could not write until its next update.UsageLedger.flush()adds any such count at once. Older versions still replace the whole file on each write and can erase the counts of processes that run this one.
v0.9.0
Added
- A
liquidbackend for Liquid AI's decision models:createTypeSafe({ backend: "liquid" })sends judgments toapi.liquid.aiunder/decisions/v1/systemonewith the key fromLIQUID_API_KEY. The default model isd1:free, which is free; passmodel: "d1"for the paid model, priced at $0.040 per million input tokens. Model ids go to Liquid unchanged. Its model list, under/decisions/v1/models, checks the key, solistModels()verifies it. - A registry backend can name a price per model (
prices, USD per million input tokens by model id). A client with nousdPerMTokfrom its caller prices each request at its backend's price for the model it sends, and atDEFAULT_USD_PER_MTOKfor a model with no price.backendPrice(backend, model)returns the registry price;RegistryBackendConfigis the new type of a registry entry. UsageLedger.recordSuccesstakes an optional third argument, the request's cost in USD.
Changed
usdPerMTokaccepts0, for a free model.- The usage ledger records each request's cost at its own price, so the day's spend in reports and the
usdPerDaycap stay right when one ledger holds requests to backends or models with different prices. Free requests add nothing to the spend. A ledger file written before this change keeps working: days without a recorded cost are estimated at the ledger's rate, as before. TypeSafeBackendnow includes"liquid"; a consumer with an exhaustiveswitchover it sees a new member.
Notes
- Liquid counts the state once per question, where TypeSafe counts it once per request, so a request with N questions costs Liquid about N times the state. The same state of about 4,000 tokens with 3 questions was 4,301 input tokens on TypeSafe and 11,918 on Liquid.
- Speed, measured on 2026-10-03 with one request at a time:
d1:freetook a median of about 14 seconds and sometimes failed with HTTP 504 after about 46 seconds;d1took about 0.5 seconds. Withd1:free, raisetimeoutMsabove its 15-second default, or passmodel: "d1".
v0.8.1
Fixed
- Declare host-provided
typeboxas a wildcard peer instead of a runtime dependency, avoiding Pi's extension-loader warning (#21). Keep it required for standalone library consumers and available in development installs.
v0.7.4
Fixed
- A bare Jev model id is mapped to the backend's own form before it is sent — on OpenRouter
jev-latestgoes as~typesafe/jev-latestandjev-1.13astypesafe/jev-1.13, for the client default and a per-requestmodelalike — so OpenRouter no longer answers 400, and/typesafe statusreports the model the configured backend actually sends.
v0.7.3
Changed
- Dependency updates:
typebox1.3.31 to 1.3.34 (runtime);typescript6.0.3 to 7.0.2,@earendil-works/pi-coding-agentand@earendil-works/pi-tui0.85.1 to 0.86.1,@types/node22.20.3 to 22.20.4, andtsx4.23.13 to 4.23.15 (development). No change to the public API.
v0.7.2
Fixed
- HTTP advice is backend-aware:
safeError(error, backend?)names the backend's key variable on a 401 (Check OPENROUTER_API_KEY.on OpenRouter,Check TYPESAFE_API_KEY.by default), a 402 now saysInsufficient credits. Add credits at https://openrouter.ai/credits.on OpenRouter andCheck your account balance.elsewhere without marking the key unusable, and a 429 appendsRetry after <n> seconds.when the response carries a numericRetry-Afterheader. One-argumentsafeErrorcalls are unchanged.
v0.7.1
Fixed
listModels()asks each backend for its own model list. It requested the SDK's/v1/modelson every backend, so on OpenRouter it fetched an HTML page and always failed; it now uses/api/v1/modelsand reads the list from OpenRouter'sdatafield (#11).listModels()on OpenRouter returns model ids (vendor/model), the valuesmodel:accepts, instead of display names.- A public model list no longer proves a key. OpenRouter serves its list without checking the key, so a successful
listModels()there leavesauthState({ backend: "openrouter" })unverified rather than recording a garbage key as verified.
Added
BackendConfiggains optionalmodelsPath,modelsField,modelsIdField, andmodelsVerifyKey, documented in the API reference.
v0.7.0
Fixed
- Key reporting and login can name the judgment backend:
keySituation(backend),resolveApiKey(backend),authState({ backend }), andensureApiKey(ctx, { backend })read the backend's own environment variable,describeAuthlabels the key by backend and names the variable to set, andAuthStatecarriesbackend. Before, every surface reported the TypeSafe key, so an OpenRouter user saw "TypeSafe key: missing" while judgments ran, andensureApiKeyopened the TypeSafe login and verified the pasted key against api.typesafe.ai (#9). createTypeSafe({ backend: "openrouter" })no longer falls back toTYPESAFE_API_KEYor the login store whenOPENROUTER_API_KEYis unset; a TypeSafe key was being sent to OpenRouter.
Added
DEFAULT_BACKENDexport and alabelon everyDECISIONS_BACKENDSentry.
Docs
- Document the
backendoption,DECISIONS_BACKENDS, and which key each backend reads in the README and the API reference; the OpenRouter backend shipped in 0.6.0 without either.