Skip to content

Releases: DevMortimer/pi-typesafe

v0.13.0

Choose a tag to compare

@github-actions github-actions released this 24 Oct 02:35
a6b79d6

Changed

  • A box question is refused with a validation error that names it. @typesafe-ai/sdk 0.7.0 added the type, which locates a subject in the request's image; this package sends noul, choice, and score, and its state carries no image.
  • A null state is refused with a validation error that names it, because 0.7.0 types state as a non-null entry.
  • A token count the API did not report (usage.input_tokens or output_tokens is null in 0.7.0) adds nothing to the session or daily totals and costs nothing, and the result renders it as not reported instead of null.
  • The package requires @typesafe-ai/sdk 0.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

Choose a tag to compare

@github-actions github-actions released this 15 Oct 03:30
058a18d

Added

  • A subq backend for SubQ's decision model: createTypeSafe({ backend: "subq" }) sends judgments to api.subq.ai under /v1/systemone with the key from SUBQ_API_KEY. The default model is subq-snap-preview, priced at $0.05 per million input tokens. Model ids go to SubQ unchanged. Its model list, under /v1/models, is public, so listModels() there does not verify the key.
  • Per-backend request limits. BackendLimits names the questions in one request, the options in one Choice, and the levels in one Score; DEFAULT_BACKEND_LIMITS holds the schema's bounds, which apply to a backend that declares none. A registry entry or a BackendEndpoint declares its own in limits, and no limit can be above the schema's bound. subq takes at most 16 questions, a Choice of at least 2 options, and a Score of at most 10 levels. ResolvedBackend.limits and TypeSafe.limits give the active backend's limits without a request.
  • chunkEvaluationRequest takes a backend option and chunks to that backend's question limit.

Changed

  • evaluate, evaluateMany, and evaluateAll refuse a request over the backend's limits before they send it, with a validation error. On typesafe, openrouter, commandcode, and liquid the limits are the schema's own, so nothing new is refused there.
  • evaluateAll chunks to the client's question limit, and chunkEvaluationRequest to the backend option's: 16 on subq, 32 elsewhere. A maxQuestions above the limit is now capped at it; before, chunkEvaluationRequest made chunks that larger, which the schema then refused.
  • prepareEvaluationRequest takes an optional limits.
  • A backend that names modelsField without modelsPath now has its model list renamed to the field the SDK reads; before, the field was ignored unless modelsPath was set too. No existing registry backend is affected.
  • TypeSafeBackend now includes "subq"; a consumer with an exhaustive switch over it sees a new member.

v0.9.1

Choose a tag to compare

@github-actions github-actions released this 04 Oct 00:26
56373f0

Fixed

  • The usage ledger lost counts when several processes ran at once. Each process read usage.json once 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 status reported fell short of the real use, and the usdPerDay, requestsPerDay, and inputTokensPerDay caps 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, and today(), blocked(), and describe() 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

Choose a tag to compare

@github-actions github-actions released this 03 Oct 13:48
bca8f72

Added

  • A liquid backend for Liquid AI's decision models: createTypeSafe({ backend: "liquid" }) sends judgments to api.liquid.ai under /decisions/v1/systemone with the key from LIQUID_API_KEY. The default model is d1:free, which is free; pass model: "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, so listModels() verifies it.
  • A registry backend can name a price per model (prices, USD per million input tokens by model id). A client with no usdPerMTok from its caller prices each request at its backend's price for the model it sends, and at DEFAULT_USD_PER_MTOK for a model with no price. backendPrice(backend, model) returns the registry price; RegistryBackendConfig is the new type of a registry entry.
  • UsageLedger.recordSuccess takes an optional third argument, the request's cost in USD.

Changed

  • usdPerMTok accepts 0, 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 usdPerDay cap 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.
  • TypeSafeBackend now includes "liquid"; a consumer with an exhaustive switch over 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:free took a median of about 14 seconds and sometimes failed with HTTP 504 after about 46 seconds; d1 took about 0.5 seconds. With d1:free, raise timeoutMs above its 15-second default, or pass model: "d1".

v0.8.1

Choose a tag to compare

@github-actions github-actions released this 30 Sep 08:42
3a498ea

Fixed

  • Declare host-provided typebox as 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

Choose a tag to compare

@github-actions github-actions released this 24 Sep 00:29
2dd46f8

Fixed

  • A bare Jev model id is mapped to the backend's own form before it is sent — on OpenRouter jev-latest goes as ~typesafe/jev-latest and jev-1.13 as typesafe/jev-1.13, for the client default and a per-request model alike — so OpenRouter no longer answers 400, and /typesafe status reports the model the configured backend actually sends.

v0.7.3

Choose a tag to compare

@github-actions github-actions released this 24 Sep 00:27
43fdebf

Changed

  • Dependency updates: typebox 1.3.31 to 1.3.34 (runtime); typescript 6.0.3 to 7.0.2, @earendil-works/pi-coding-agent and @earendil-works/pi-tui 0.85.1 to 0.86.1, @types/node 22.20.3 to 22.20.4, and tsx 4.23.13 to 4.23.15 (development). No change to the public API.

v0.7.2

Choose a tag to compare

@github-actions github-actions released this 24 Sep 00:15
7b9730a

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 says Insufficient credits. Add credits at https://openrouter.ai/credits. on OpenRouter and Check your account balance. elsewhere without marking the key unusable, and a 429 appends Retry after <n> seconds. when the response carries a numeric Retry-After header. One-argument safeError calls are unchanged.

v0.7.1

Choose a tag to compare

@github-actions github-actions released this 23 Sep 00:36
72e4b5b

Fixed

  • listModels() asks each backend for its own model list. It requested the SDK's /v1/models on every backend, so on OpenRouter it fetched an HTML page and always failed; it now uses /api/v1/models and reads the list from OpenRouter's data field (#11).
  • listModels() on OpenRouter returns model ids (vendor/model), the values model: 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 leaves authState({ backend: "openrouter" }) unverified rather than recording a garbage key as verified.

Added

  • BackendConfig gains optional modelsPath, modelsField, modelsIdField, and modelsVerifyKey, documented in the API reference.

v0.7.0

Choose a tag to compare

@github-actions github-actions released this 22 Sep 14:29
6fa2f2a

Fixed

  • Key reporting and login can name the judgment backend: keySituation(backend), resolveApiKey(backend), authState({ backend }), and ensureApiKey(ctx, { backend }) read the backend's own environment variable, describeAuth labels the key by backend and names the variable to set, and AuthState carries backend. Before, every surface reported the TypeSafe key, so an OpenRouter user saw "TypeSafe key: missing" while judgments ran, and ensureApiKey opened the TypeSafe login and verified the pasted key against api.typesafe.ai (#9).
  • createTypeSafe({ backend: "openrouter" }) no longer falls back to TYPESAFE_API_KEY or the login store when OPENROUTER_API_KEY is unset; a TypeSafe key was being sent to OpenRouter.

Added

  • DEFAULT_BACKEND export and a label on every DECISIONS_BACKENDS entry.

Docs

  • Document the backend option, 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.