Clients by language
Nine clients implement unified-v1 against the same contract, but their release cadence differs. The table is current as of 2026-10-13. Version numbers and dates are taken from the registry records read that day (npm, NuGet, Maven Central, the GitHub Releases of tansrai/tansr-ios-spm, the Go module proxy, crates.io, PyPI and the GitHub Releases of tansrai/tansr-cpp), and each date is the UTC date of the registry record; HarmonyOS has no public package registry, so it is listed by the HAR shipped with the official download page. Each row ends with the last version on the public channel that still uses the old prefixes: an app installed at that version or earlier works as this chapter describes only after upgrading.
| Client | Public release | /api (unified-v1) support |
|---|---|---|
Node @tansr/api-client |
0.4.0 stable (npm, 2026-10-06, latest) |
Released: ./api is unchanged from 0.3.0 and still aligned with manifest revision 7. Frozen ./sdk2 / ./terminal default to /api when routePrefixes is omitted; pass LEGACY_ROUTE_PREFIXES to keep the old prefixes. ./api exists since 0.3.0; 0.2.0 has no such entry |
.NET Tansr.Sdk / Tansr.Sdk.Windows |
NuGet 0.2.0 (2026-10-07; 0.1.0.2 remains listed) | Released: 0.2.0 matches manifest revision 7; 0.1.0.2 predates that alignment and still uses the old prefixes |
Android com.tansr.sdk:core / client / compose |
Maven Central 0.5.0 (2026-10-07; the optional module receiver-android is first published at the same version) |
Released: 0.5.0 matches manifest revision 7 with unified codes as the primary error signal; 0.4.0 and earlier still use the old prefixes |
iOS tansrai/tansr-ios-spm |
Public binary SPM 0.4.0 (2026-10-09) | Released: 0.4.0 matches manifest revision 7 and is the first to ship the SDK2 client, archive sync and the terminal interfaces; 0.3.0 still uses the old prefixes |
HarmonyOS HAR @tansr/harmony |
Bundled HAR 0.2.0 (2026-10-10; shipped inside the HarmonyOS demo package on the official download page, no OHPM channel) | Released (bundled): 0.2.0 is on the unified-v1 contract and business code goes only through /api; 0.1.0 still uses the old prefixes |
Go github.com/tansrai/tansr-go |
Module v0.3.0 (2026-10-07) | Released: from v0.2.0 the high-level session, executor and archive go through /api; v0.3.0 only moves the module path off github.com/cpple/tansr-go |
Rust tansr-sdk / tansr-sdk-demo |
crates.io 0.1.0 (2026-10-08) | Released: the async client uses the unified /api |
Python tansr-sdk / tansr-sdk-demo |
PyPI 0.1.0 (2026-10-08) | Released: sync and asyncio share one /api implementation |
C++ tansrai/tansr-cpp |
GitHub Release v0.1.0 (2026-10-08) | Released: a static SDK and three standalone demos; not yet in the Conan Center or public vcpkg indexes |
Rules every client shares
Section titled “Rules every client shares”Whatever the language, the official clients all do the following; it doubles as a checklist when you write your own:
- Paths come only from generated code. Every repository holds a path module generated from
api-manifest.json(NodeAPI_OPERATIONS, .NETTansr.Sdk.Api.ApiRoutes, AndroidApiOps, iOSApiOps, HarmonyOSApiOps, Goapi/operations_gen.go, Rustsrc/api/operations.rs, Pythontansr_sdk/api/operations.py, C++include/tansr/operations.hpp); no/v2,/v3/sdk2or/v3/terminalliteral appears in source, and the generated code is locked in the repository together with the upstream commit so that CI can detect drift. - Zero-fallback response gate. Every response (including 2xx and SSE opening) must carry all of
tansr-contract/tansr-manifest-revision/tansr-domain/tansr-schema-hash; a missing, duplicate or malformed header, or atansr-*header outside the vocabulary, fails explicitly (NodeContractUnavailableError, .NETContractUnavailableException, AndroidTansrAgentException.ContractUnavailable/ApiContractException, iOS.contractUnavailable, HarmonyOSApiContractError('contract_unavailable'), Go*api.ContractUnavailableError, RustError::Contract, Python anErrorwhosecode == "contract", C++ErrorCode::contract) with no parser switch, no fallback to the old prefixes and no automatic retry. - Unified codes first. Errors are judged by the 19 unified codes plus the 6
retryActionvalues; the family code is only a detail indetail.domainCode. The old exception types that branched on family codes are kept for one version as a transition bridge and marked deprecated. - The three request headers are validated locally first. A malformed
Idempotency-Key, a weakIf-Matchvalidator or one used on an operation withoutexpectedRevision, or an already expireddeadlineis rejected before sending (no network traffic); a retry keeps the same options, never changes the key and never extends the deadline. - Golden vector replay. Every client replays the 165 vectors of
unified-v1.golden.jsonthrough its real decoders and records any divergence outside the intersection with its declared capabilities.
Node: @tansr/api-client/api
Section titled “Node: @tansr/api-client/api”npm install @tansr/api-clientimport { createApiClient, ApiError, DomainError, ContractUnavailableError, ApiClientError, retryAdvice, retrySameRequest, isTerminalEvent, API_OPERATIONS, API_CONTRACT_LOCK,} from '@tansr/api-client/api';
const api = createApiClient({ baseUrl: 'https://serve.example.com', // origin only: no path, query or credentials token: () => loadEndUserToken(), // or authorize(headers) for custom schemes sessionFamily: 'sdk1', // optional; omitted = deployment preferred family eventEnvelope: 'unified-v1', // optional; negotiate the 7-key event envelope onContract: (seen) => log.debug('contract', seen, API_CONTRACT_LOCK),});
try { const read = await api.call('archive.binding.get', { params: { id: bindingId } }); await api.call('archive.binding.close', { params: { id: bindingId }, body: { reason: 'done' }, idempotencyKey: `close-${bindingId}`, ifMatch: read.meta.etag ?? undefined, deadline: new Date(Date.now() + 30_000), });} catch (error) { if (error instanceof ApiError) { const advice = retryAdvice(error); if (advice.replayable) { /* retrySameRequest(api, { name, options }, error) */ } else if (advice.action === 'refresh') { /* re-read, take the new ETag, resubmit */ } else if (advice.action === 'rediscover') { /* GET /api/sessions/:id/capabilities again */ } } if (error instanceof ContractUnavailableError) { /* not a unified-v1 serve or a gateway stripped the headers */ }}Key points:
- The package is MIT with zero runtime dependencies and its
enginesfield requires Node 20.3 or newer; the./apisub-entry relies only onfetchand other Web standard APIs, pulls in no Node-specific modules and does not load the agent kernel. - Options of
createApiClient:baseUrl(origin only),tokenorauthorize, an injectablefetch,sessionFamily,eventEnvelope,maxResponseBytes(default 2 MiB),maxEventFrameBytes(default 2 MiB),onContract. - Methods:
manifest(),capabilities(),sessionCapabilities(sessionId)(returns{ closure, closureId, meta }, having checked that the response header and theclosureIdin the body agree),call(name, { params, query, body, closureId, idempotencyKey, ifMatch, deadline, signal }),events(name, { params, query, lastEventId, signal, onOpen });lockedandobserved()give the build-time locked and the runtime observed revision /schemaHash. - Result shape
{ status, body, meta };metaholdscontract,manifestRevision,domain,schemaHash,closureId,eventEnvelope,traceId,etag,retryAfterMs. A 202 is acceptance, not completion. - Error types:
ApiError(unified envelope:code,status,retryAction,traceId,requestId,domainCode,detail),DomainError(an un-normalised family envelope, today onlyarchive-sync-v1),ContractUnavailableError,ApiClientError(local:aborted,network_error,envelope_not_negotiated,payload_too_large,invalid_response,deadline_exceeded,if_match_not_applicableand so on). API_OPERATIONSis the catalogue of 81 operations (revision 7), each withmethod,path,params,aliases,domain,family,kind,sse,query,etagPath,expectedRevision,requestIdPath; request bodies of the strict families (sdk2-*,terminal-*,archive-sync-v1) are encoded by the SDK as canonical JSON.- The old entries
./sdk2,./sdk2/node,./terminaland./terminal/nodewere frozen in 0.3.0 and are still shipped. From 0.4.0, omittingroutePrefixessends them to/api. PassLEGACY_ROUTE_PREFIXESto keep the old prefixes. Export names were not added or removed.
dotnet add YourApp.csproj package Tansr.Sdk --version 0.2.0dotnet add YourApp.csproj package Tansr.Sdk.Windows --version 0.2.0The current public version on NuGet is 0.2.0 (Tansr.Sdk and Tansr.Sdk.Windows, 2026-10-07, MIT, source tansrai/tansr-net). Tansr.Sdk targets netstandard2.0 and net10.0 (marked AOT-compatible on net10.0) and covers HTTP / SSE, sessions, execution coordination and the storage interfaces; Tansr.Sdk.Windows targets net48 and net10.0-windows, adds the Windows file / process, local SQLite and DPAPI adapters and depends on the core package automatically. The SDK is a library and does not carry a .NET runtime: .NET Framework apps need the system runtime, modern .NET apps can publish self-contained. It goes only through /api: the path constants Tansr.Sdk.Api.ApiRoutes are generated by node scripts/generate-api-routes.mjs from the vendored contract/api-manifest.json; the generic entry is client.CallAsync(ApiRoutes.X, new ApiCallOptions { IdempotencyKey, IfMatch, Deadline, ClosureId }); the closure comes from client.GetCapabilityClosureAsync(sessionId); the unified envelope decodes to UnifiedApiException (Code / StatusCode / RetryAction are primary, family facts live in Detail.DomainCode / DomainStatus / DomainRetryAction), and UnifiedRetry.Advice(error) with UnifiedRetry.RetrySameRequestAsync(...) carries the retry rules; TansrClientOptions.NegotiateEventEnvelope negotiates the event envelope explicitly and a missing echo throws EnvelopeNotNegotiatedException. The older 0.1.0.2 is still on NuGet and predates this contract alignment; do not treat it as an /api client. There are three examples, WPF, WinForms (.NET Framework 4.8) and console, under examples/ in the source repository.
Android
Section titled “Android”From Maven Central 0.5.0 (2026-10-07) every HTTP request goes only through /api: the generated core/src/main/kotlin/com/tansr/sdk/api/ApiContract.kt (ApiContract constants and the 81 ApiOps operations with etagPath / expectedRevision) and UnifiedContract.kt (UnifiedCode with 19 codes, UnifiedRetryAction with 6 actions); the response gate ApiContractGate.requireUnifiedValues; errors surface as TansrAgentException.Unified (SDK1) or ApiFacadeException (SDK2 / terminal), with the 33 old sealed types deprecated and kept for one version; the three request headers travel optionally through ApiCallOptions(idempotencyKey, ifMatch, deadline) on Sdk2Client.createBinding / acknowledge / closeBinding and TerminalClient.configure / memoryCommand; the generator is node scripts/api/generate-api-contract.mjs --cli <tansr-cli>, and :core:contractCheck includes the same-source mapping table and the 165 golden vector replay. Artefacts 0.4.0 and earlier predate these changes and still use the old prefixes; when upgrading, move core / client / compose to 0.5.0 together, and the optional receiver-android is first published at the same version. For the integration basics see Android SDK.
From the public binary SPM 0.4.0 (2026-10-09, iOS 16 or later, macOS 13 or later) the single path source is Sources/TansrCore/Api/ApiContract.swift (ApiContract, the 81 ApiOps operations); the response header gate ApiContractGate.requireUnified covers every SDK1 2xx response, the opening of event streams and the audio client, and a violation becomes TansrAgentError.contractUnavailable / ApiContractError.contractUnavailable, with the event pump entering the failed terminal state directly on a 2xx-shaped contract failure; the error model is TansrAgentError.kind == .unified (unifiedCode + retryAction) and ApiFacadeError; ApiCallOptions carries the three request headers; onManifestRevisionDrift fires once per client when the response revision differs from the local revision 7; CI contract:check and the full swift test include the golden vector replay. 0.4.0 is also the first release to ship the SDK2 client, archive sync and receiver, the execution journal and the terminal interfaces. 0.3.0 predates these changes and still uses the old prefixes; when upgrading from 0.3.0, rewrite the error branches around the unified codes and retryAction. For the integration basics see iOS SDK.
HarmonyOS
Section titled “HarmonyOS”From the bundled HAR 0.2.0 (2026-10-10, HarmonyOS 6.0 / API 20 at minimum, no OHPM channel) business code references only ApiOps.*.apiPath / apiPath(); the generated tansr/src/main/ets/core/api/ApiContractGenerated.ets, core/api/UnifiedContractGenerated.ets and core/sdk2/client/SchemaGenerated.ets come from node scripts/api/generate-api-contract.mjs --cli <tansr-cli root> out of the manifest, sdk2-ext-v1.schema.json, unified-v1.schema.json and unified-v1.golden.json, and pnpm check:contract verifies that the outputs and the lock agree; a missing one of the four unified response headers is contract_unavailable (with a reason), and the session pump enters the failed terminal state directly on a 2xx-shaped contract failure; SDK1 surfaces errors as AgentError (error.unified, error.retryAction, error.domainCode), SDK2 / terminal throw ApiFacadeError directly; the three request headers are validated locally through ApiCallOptions(idempotencyKey, ifMatch, deadline). The 0.1.0 HAR predates these changes and still uses the old prefixes. For the integration basics see HarmonyOS SDK.
client, err := api.New(api.Options{BaseURL: "http://127.0.0.1:8787", Token: token, EventEnvelope: true})closure, err := client.SessionCapabilities(ctx, sessionID)res, err := client.Call(ctx, api.OpSessionMessageSend, api.CallOptions{ Params: map[string]string{"id": sessionID}, Body: map[string]any{"prompt": "hi"}, ClosureID: closure.ClosureID,})stream, err := client.Events(ctx, api.OpSessionEventsObserve, api.EventsOptions{Params: map[string]string{"id": sessionID}})github.com/tansrai/tansr-go v0.3.0 (2026-10-07, MIT, Go 1.25 or newer, standard library only, no third-party runtime dependencies). The module path moved off github.com/cpple/tansr-go: v0.1.0 covers only api / canonical / sse; from v0.2.0, session, executor and archive are real implementations, with go-chat, go-tools and go-archive. v0.3.0 changes only the module path; protocol behaviour is unchanged from v0.2.0. An upgrade must change go.mod and every import together. Do not mix types from the old and new modules. Install with go get github.com/tansrai/tansr-go@v0.3.0; the three examples install directly as commands, for example go install github.com/tansrai/tansr-go/examples/go-chat@v0.3.0 (likewise go-tools and go-archive). Source is at tansrai/tansr-go.
cargo add tansr-sdk@=0.1.0tansr-sdk and tansr-sdk-demo 0.1.0 are on crates.io (2026-10-08, MIT, edition 2024). Rust 1.85 or newer is required. Windows builds also need the MSVC build tools and NASM on the current shell’s PATH. The async client uses the unified /api. High-level sessions, explicit business tools and a single-device encrypted archive ship in the crate. The three example commands are tansr-chat, tansr-tools and tansr-archive, installed with cargo install tansr-sdk-demo --version 0.1.0 --locked. Source is at tansrai/tansr-rust.
Python
Section titled “Python”python -m pip install tansr-sdk==0.1.0tansr-sdk and tansr-sdk-demo 0.1.0 are on PyPI (2026-10-08, MIT, source tansrai/tansr-python). requires-python is >=3.7,!=3.9.0,!=3.9.1: CPython 3.7 or newer is supported, except 3.9.0 and 3.9.1. The minimum Python version and the TLS baseline are two separate conditions: the default HTTPS transport first checks the standard library’s SSL runtime, and a known affected OpenSSL (such as the 1.1.1g bundled with the official Windows Python 3.7.9) is rejected as unsupported_tls_runtime with no bypass switch; use the isolated runtime described in the release notes, and prefer a maintained interpreter for new projects. The sync API and asyncio share one /api implementation. The example commands tansr-py-chat, tansr-py-tools and tansr-py-archive live in the tansr-sdk-demo package, installed with python -m pip install tansr-sdk-demo==0.1.0.
find_package(TansrSDK 0.1.0 EXACT CONFIG REQUIRED)target_link_libraries(my_app PRIVATE tansr::sdk)GitHub Release v0.1.0 of tansrai/tansr-cpp (2026-10-08, MIT) ships a source package plus Release static SDK and standalone demo builds for Windows x64 (MSVC 19.44), Linux x64 (Ubuntu 24.04 / GCC 13.3, glibc 2.38 or newer) and macOS arm64 (AppleClang 21, macOS 26.0 or later); the Conan / vcpkg recipes are distributed as release assets, and neither Conan Center nor the public vcpkg index lists the SDK yet. The language level is C++17; building from source needs CMake 3.25 or newer and Ninja, the dependencies are pinned to curl 8.22.0, c-ares 1.34.8 and OpenSSL 3.5.9, and you prepare them from the release manifest yourself because CMake does not download them. The three examples are tansr-chat, tansr-tools and tansr-archive.
Next steps
Section titled “Next steps”- To understand the errors and actions every client judges the same way, read Unified request headers, response headers and the error envelope.
- The integration steps of the three mobile SDKs are in Android SDK, iOS SDK and HarmonyOS SDK; new versions of every client are recorded in each repository’s release history and in this site’s release notes.
Was this page helpful?
Thanks for your feedback.