@tenzro/ai
v0.4.15
Published
Tenzro AI SDK — discover and run inference across Tenzro Network's decentralized AI providers. Cutting-edge TypeScript developer experience with TDIP identity, TNZO payment, and verifiable responses (TEE attestation, Plonky3 STARK).
Maintainers
Readme
@tenzro/ai
Core SDK for inference on Tenzro Network's decentralized AI providers.
A thin, ergonomic facade over the node's multi-modal inference RPCs (chat, embeddings, vision, forecast, segmentation, detection, audio, video) with TDIP identity, TNZO payment, and verifiable responses (TEE attestation, Plonky3 STARK proofs).
npm install @tenzro/ai
# or
pnpm add @tenzro/aiQuick start
import { generateText, tenzro } from '@tenzro/ai';
const { text } = await generateText({
model: tenzro('llama-3.3-70b'),
prompt: 'What is post-quantum cryptography?',
});That's it — no API key, no identity setup. Calls without a signer run faucet-tier against https://rpc.tenzro.network.
Top-level functions
| Function | Modality | Returns |
|---|---|---|
| generateText | chat | { text, reasoning, usage, finishReason, toolCalls, receipts } |
| streamText | chat | { stream, text, reasoning, usage, finishReason, toolCalls, receipts } |
| generateObject<T> | chat (structured) | { object: T, usage, finishReason, receipts } |
| streamObject<T> | chat (structured) | { partialObjectStream, object, usage, finishReason, receipts } |
| embed | text-embedding | { data: { embeddings, dim }, vector, receipts } |
| embedImage | vision | { data: { embedding, dim }, receipts } |
| imageTextSimilarity | vision | { data: { similarity }, receipts } |
| forecast | timeseries | { data: { forecast, quantiles? }, receipts } |
| segment | segmentation | { data: { masks }, receipts } |
| detect | detection | { data: { detections }, receipts } |
| transcribe | audio (ASR) | { data: { text, segments }, receipts } |
| embedVideo | video | { data: { embedding }, receipts } |
Every function accepts the same base options (model, signer, payment, routing, verify, abortSignal, requestTimeoutMs, maxRetries).
Streaming
import { streamText, tenzro } from '@tenzro/ai';
const { stream } = streamText({
model: tenzro('llama-3.3-70b'),
messages: [
{ role: 'user', parts: [{ type: 'text', text: 'Write a haiku.' }] },
],
});
for await (const part of stream) {
if (part.type === 'text-delta') process.stdout.write(part.text);
}stream is AsyncIterable<TenzroStreamPart>. Discriminated union covers text-delta, reasoning-delta, tool-call, tool-call-delta, tool-result, source, tenzro-attestation, tenzro-zk-proof, tenzro-payment-receipt, finish, error.
Identity + payment
Tenzro has no API keys. Identity is a TDIP DID with hybrid Ed25519 + ML-DSA-65 signing; payment is per-call.
import { generateText, tenzro, InMemorySigner } from '@tenzro/ai';
import { randomBytes } from 'node:crypto';
const signer = new InMemorySigner({
did: 'did:tenzro:human:01HZA...',
ed25519Seed: randomBytes(32),
mlDsa65Seed: randomBytes(32),
});
const { text, receipts } = await generateText({
model: tenzro('llama-3.3-70b', { strategy: 'reputation', requireTee: 'tdx' }),
prompt: 'Summarize this contract.',
signer,
payment: { protocol: 'auto', maxPrice: { amount: 1_000n, currency: 'TNZO' } },
});
// receipts.payment is set when the call settled against a paid provider.
// receipts.attestation is set when the provider attached TEE attestation.payment.protocol: 'auto' lets the SDK negotiate x402 / MPP / micropayment-channel based on the provider's HTTP 402 challenge. Apps that want to lock the protocol can pass 'x402', 'mpp', or 'channel' directly.
The SDK never holds funds. Wallet implementations (e.g. tenzro-wallet) provide a Signer that signs payment authorizations alongside the inference preimage.
Verification
Provider responses can carry TEE attestations and Plonky3 STARK proofs. They're opt-in:
import { generateText, tenzro, verifyAttestation, verifyZkProof } from '@tenzro/ai';
const result = await generateText({
model: tenzro('llama-3.3-70b', { requireTee: 'tdx' }),
prompt: 'Hello.',
verify: 'tee', // 'off' | 'tee' | 'zk' | 'all'
});
if (result.receipts.attestation) {
await verifyAttestation(result.receipts.attestation);
}
if (result.receipts.zkProof) {
await verifyZkProof(result.receipts.zkProof);
}verify: 'tee' makes attestation verification a hard precondition (the call throws AttestationFailedError if verification fails). verify: 'off' (the default) leaves the receipt on the result for the caller to verify out-of-band.
Multi-modal
import { embed, embedImage, forecast, transcribe, tenzro } from '@tenzro/ai';
import fs from 'node:fs/promises';
// Text embedding
const e = await embed({
model: tenzro('qwen3-embedding-0.6b'),
input: 'hello world',
});
console.log(e.vector); // number[]
// Image embedding
const png = await fs.readFile('./photo.png');
const ie = await embedImage({
model: tenzro('siglip2-base'),
image: png,
});
// Timeseries forecast
const f = await forecast({
model: tenzro('chronos-bolt-base'),
history: [/* historical points */],
horizon: 24,
});
// Audio transcription
const wav = await fs.readFile('./speech.wav');
const t = await transcribe({
model: tenzro('whisper-large-v3-turbo'),
audio: wav,
});All modalities share the same { data, receipts, raw } envelope and accept the same identity/payment/verify base options.
Agent loop
Agent runs an OpenAI-compatible tool-calling loop. Tool execution is caller-owned code; the only network calls per step are generateText.
import { Agent, tool, stepCountIs, tenzro } from '@tenzro/ai';
import { z } from 'zod';
const agent = new Agent({
model: tenzro('llama-3.3-70b'),
tools: {
getWeather: tool({
description: 'Get the current weather for a city.',
inputSchema: z.object({ city: z.string() }),
execute: async ({ city }) => {
const res = await fetch(`https://api.example.com/wx?city=${city}`);
return res.json();
},
}),
},
stopWhen: [stepCountIs(5)],
});
const { text, steps, stopReason } = await agent.run({
prompt: 'What is the weather in Tokyo and Berlin? Compare them.',
});Tools that need approval gates expose a needsApproval(input) predicate; bind an approve callback on the agent (or on the run) to handle confirmation.
Direct provider access (advanced)
The default tenzro() flow does discovery + routing + failover. Apps that already know which provider to hit can skip discovery:
import { discoverProviders, generateText } from '@tenzro/ai';
const providers = await discoverProviders({ modality: 'chat' });
const ranked = providers.filter((p) => p.reputation > 700);
const { text } = await generateText({
providers: ranked,
prompt: 'Hello.',
});Stable subpaths
import type { TenzroProvider, UIMessage } from '@tenzro/ai/types';
import { TenzroAIError, RateLimitError } from '@tenzro/ai/errors';The root '@tenzro/ai' re-exports everything — these subpaths are for callers that want a smaller surface.
Status
Pre-alpha. APIs may change without notice until 1.0.
License
Apache-2.0
