TypeSafeAI .NET SDK

September 18, 2026 · View on GitHub

CI NuGet NuGet downloads License: MIT .NET

Ask typed, answerable questions about any text or JSON state, and get structured, probability-backed answers back: yes/no probabilities, a chosen option out of a set you define, or a position on a rubric you define.

This is a community SDK. It is an independent client for the TypeSafe AI System One HTTP API, written and maintained by the community.

Links below point at the repository, because NuGet renders this file as a standalone page where relative paths do not resolve.

Important

This project is not affiliated with, sponsored by, or endorsed by TypeSafe AI. It is an independent, community-maintained client library. "TypeSafe" and "System One" are used only to describe the API this library talks to. For the API, the service, the models, and anything about accounts, billing, or uptime, contact TypeSafe AI directly through typesafe.ai and console.typesafe.ai. See SUPPORT.md for which venue to use for what.

Why this SDK

  • Typed answers, not prose. Every question is declared with a kind and answered inside the constraints you supplied, so nothing has to be parsed out of generated text.
  • One round trip for many questions. Questions in a single request are evaluated in parallel against the same state. Adding a speculative question is nearly free, which makes fan-out and confidence-gated routing practical instead of expensive.
  • Confidence is reported, never invented. When the API reports a confidence, the SDK surfaces it verbatim and never recomputes or substitutes it.
  • Nothing is lost relative to the raw HTTP API. Unmodelled response and request fields, unknown answer kinds, and new question kinds all survive with RawJson, RawQuestion, and UnknownAnswer.
  • Forward compatible by default. A new answer kind does not fail the response; the other answers in the same payload are unaffected.
  • Trimming- and AOT-clean. The library is annotated, analyzer-clean, and ships a source-generator-friendly overload for serializing your own state types.
  • Batteries included, dependencies minimal. The core package depends on exactly one package, Microsoft.Extensions.Logging.Abstractions. Retry, backoff, Retry-After handling, and per-attempt timeouts are implemented in the library.
  • Built for .NET 8 and .NET 10, with nullable reference types, XML documentation on every public member, and a public API surface that is checked in and enforced at build time.

Install

dotnet add package TypeSafeAI.Sdk
dotnet add package TypeSafeAI.Sdk.DependencyInjection

The DI package is optional and adds IServiceCollection registration on top of IHttpClientFactory.

60-second quickstart

Get an API key from the TypeSafe console and put it in the TYPESAFE_API_KEY environment variable:

export TYPESAFE_API_KEY="ts_..."
$env:TYPESAFE_API_KEY = "ts_..."

Then:

using TypeSafeAI;

var client = new TypeSafeClient();               // reads TYPESAFE_API_KEY
var result = await client.SystemOneAsync(
    "My card was charged twice, please fix this ASAP.",
    [
        new NoulQuestion("is_urgent", "Does this convey urgency?"),
        new ChoiceQuestion("department", "Which team should handle this?", ["billing", "technical", "sales"]),
        new ScoreQuestion("frustration", "How frustrated is the customer?", ["Calm", "Frustrated", "Very angry"]),
    ]);
Console.WriteLine(result.Noul("is_urgent").Probability);
Console.WriteLine(result.Choice("department").Label);
Console.WriteLine(result.Score("frustration").Score);

That is the whole loop. Probability is a number from 0 to 1, Label is one of the options you supplied, and Score is the probability-weighted position along your rubric, so it can land between levels.

The NuGet packages and C# namespaces now use the TypeSafeAI brand. Existing users must update both their package references and using directives; see the package migration guide.

Continue with docs/quickstart.md for configuration, dependency injection, structured state, and error handling.

At a glance

Client

TypePurpose
TypeSafeClientThe default client. Thread-safe, reuses one pooled HttpClient, implements IDisposable.
ITypeSafeClientThe interface to depend on. TypeSafeClient is the shipped implementation.
TypeSafeClientOptionsAPI key, base URL, default model, per-attempt timeout, retry policy, headers, ILoggerFactory.
TypeSafeRequestOptionsPer-call overrides of model, retry, timeout, headers, and extra body fields.
SystemOneRequestA whole request — state, questions, model, options, extra body fields — as one object.

SystemOneAsync has five overloads: a SystemOneRequest, a string state, a JsonNode? state, an arbitrary TState with a JsonTypeInfo<TState> (trim/AOT-safe), and an arbitrary TState using reflection.

Questions

TypeAnswer typeWire type
NoulQuestionNoulAnswernoul
ChoiceQuestionChoiceAnswerchoice
ScoreQuestionScoreAnswerscore
RawQuestionUnknownAnswer (or a modelled answer if the kind matches)caller-supplied
QuestionSetan ordered, duplicate-rejecting collection of questions
NoulCriteriaoptional descriptions of what yes and no mean

A NoulQuestion asks a yes/no question. A ChoiceQuestion selects one label from a set of up to 255 you supply. A ScoreQuestion places the state on an ordered rubric of 2 to 10 levels. See docs/questions.md.

Answers

TypeMembers
SystemOneResultNoul(id), Choice(id), Score(id), Get(id), TryGet(id, …), Get<TAnswer>(question), TryGet<TAnswer>(question, …), Contains(id), Ids, Answers, Nouls, Choices, Scores, UnknownAnswers, Model, Usage, RequestId, RawJson
NoulAnswerProbability — a calibrated probability from 0 to 1. No confidence; see below.
ChoiceAnswerLabel, Confidence, Probabilities, TopLabel, TopProbability, ProbabilityOf, ProbabilityOrDefault, TryGetProbability, Ranked(), Top(n), NormalizedEntropy()
ScoreAnswerScore, Confidence, Legend, Probabilities, LevelCount, MaxLevel, NormalizedScore, ExpectedLevel, Variance, ProbabilityAtLevel, TryGetProbability, LegendAtLevel, LegendTextAtLevel, NormalizedEntropy()
UnknownAnswerType, Raw — for answer kinds newer than this SDK release
AnswerId, Type, AdditionalProperties, TryGetConfidence(out double)

Every answer type carries Id and AdditionalProperties, the response fields this SDK version does not model.

Combining answers in code

TypePurpose
CompositeScore.Weighted(parts)Weighted mean of several ScoreAnswers, each normalised by its own rubric length.
CompositeScore.Profiles(parts, profiles)Several named weightings over the same answers.
WeightedScoreOne ScoreAnswer plus its relative weight.
ProbabilityMathNormalizedEntropy, ExpectedLevel, Variance for callers who want their own statistic.

See docs/patterns.md for fan-out, confidence-gated routing, composite scoring, and intent routing.

Configuration and diagnostics

TypePurpose
RetryPolicyRetry count, backoff, jitter, retryable status codes, Retry-After handling, total budget.
RetryAttemptThe attempt number, the delay, and the failure, passed to RetryPolicy.OnRetry.
TypeSafeDefaultsEnvironment variable names and the defaults applied when nothing overrides them.
TypeSafeJsonOptions, plus Serialize/Deserialize helpers for results, answers, and questions.
UsageInputTokens, OutputTokens, TotalTokens, when the API reports them.
IModelsResource, ModelsResult, ModelMetadataclient.Models.ListAsync() — the models available to the account.

Errors

Every error the SDK raises derives from TypeSafeException. Authentication, permissions, bad requests, not found, unprocessable entities, rate limits, and server errors derive from TypeSafeApiException and carry StatusCode, Details, RequestId, Endpoint, Headers, DocumentationUrl, and the raw Body. See docs/retries-and-errors.md for the full table.

Dependency injection

using TypeSafeAI.DependencyInjection;

builder.Services.AddTypeSafeClient(builder.Configuration);

AddTypeSafeClient registers ITypeSafeClient and TypeSafeClient as singletons on top of IHttpClientFactory, binds the TypeSafe configuration section, and redacts credentials from the framework's own HTTP logging.

Confidence, and what it is not

ChoiceAnswer.Confidence and ScoreAnswer.Confidence are values the API reported. The SDK reads them from the wire and never recomputes, adjusts, or substitutes them. NoulAnswer has no confidence at all — a noul's Probability is itself the signal, and the SDK deliberately offers no confidence member rather than inventing one.

NormalizedEntropy(), ProbabilityMath, Variance, and ExpectedLevel exist for callers who want to compute their own statistic from the full distribution. They are not the API's confidence, and the SDK never uses them to populate it. Thresholds belong in your code, next to the decision they gate. Read docs/answers-and-confidence.md before wiring a threshold into production.

Requirements

RequirementValue
Target frameworksnet8.0, net10.0
.NET SDK to build from source.NET 10 SDK (10.0.100 or later)
Core package dependenciesMicrosoft.Extensions.Logging.Abstractions only
DI package dependenciesthe core package, Microsoft.Extensions.Http, Microsoft.Extensions.Configuration.Abstractions, Microsoft.Extensions.DependencyInjection.Abstractions
LicenceMIT

The SDK uses only .NET 8-era APIs (JsonNode, TimeProvider, JsonNamingPolicy.SnakeCaseLower, [JsonExtensionData]), so both target frameworks are first-class and neither is a compatibility shim. The net8.0 asset is dropped in the first release after .NET 8 reaches end of support.

Configuration

Values are resolved in this order: an explicitly set option, then the environment variable, then the SDK default. Empty or whitespace-only environment values are treated as unset.

Environment variableOptionDefault
TYPESAFE_API_KEYTypeSafeClientOptions.ApiKeynone — required
TYPESAFE_BASE_URLTypeSafeClientOptions.BaseUrlhttps://api.typesafe.ai
TYPESAFE_ENDPOINTTypeSafeClientOptions.BaseUrlaccepted as an alias; TYPESAFE_BASE_URL wins
TYPESAFE_DEFAULT_MODELTypeSafeClientOptions.Modeljev-latest

The same names configure the official TypeSafe Python and JavaScript SDKs, so one set of variables configures every TypeSafe SDK in a polyglot deployment.

Documentation

Browse the SDK documentation site for searchable guides, code examples, and a suggested reading order. The same guides are available below as Markdown in this repository.

DocumentWhat it covers
docs/README.mdIndex of every document, and the suggested reading order.
docs/quickstart.mdInstall, configure, first request, DI, structured state, errors.
docs/questions.mdNoul, choice, and score questions, with their documented limits.
docs/answers-and-confidence.mdThe answer types, confidence semantics, and threshold guidance.
docs/patterns.mdFan-out, confidence-gated routing, composite scoring, intent routing.
docs/forward-compatibility.mdExtra fields, RawQuestion, UnknownAnswer, RawJson.
docs/retries-and-errors.mdRetry knobs and defaults, the exception hierarchy, timeouts and budgets.
docs/package-migration.mdMove from the former NuGet package IDs and C# namespaces.

Contributing

Contributions are welcome. Start with CONTRIBUTING.md for the development setup, the coding standards, and how to add a public API. By taking part you agree to the Code of Conduct.

Change history lives in CHANGELOG.md. Maintainers cutting a release should follow RELEASING.md.

Licence

MIT. See LICENSE.