npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tangle-network/tcloud

v0.4.12

Published

TypeScript SDK and CLI for Tangle AI Cloud — decentralized LLM inference

Readme

tcloud

TypeScript SDK and CLI for Tangle AI Cloud — decentralized LLM inference with operator routing, reputation-based selection, and anonymous payments via ShieldedCredits.

Zero framework dependencies. Pure fetch + SSE. Works in Node.js, Deno, Bun, and edge runtimes.

Table of Contents

Installation

npm install tcloud

Or run the CLI directly:

npx tcloud chat "What is Tangle?"

SDK

Quick Start

import { TCloud } from 'tcloud'

// Set model at client creation — explicit and consistent.
const client = new TCloud({
  apiKey: 'sk-tan-...',
  model: 'gpt-4o-mini',
})

const answer = await client.ask('What is Tangle Network?') // string
console.log(answer)

Quick Start — direct cli-bridge (subscription-backed coding harness)

When you have your own cli-bridge running (locally or on your own VPS), point the SDK straight at it. cli-bridge is OpenAI-compatible (/v1/chat/completions) so chat / ask / askStream work unchanged — and your CLI subscriptions on the bridge box pay for the LLM tokens directly (no router, no per-token billing).

# 1. clone + run cli-bridge (one terminal)
gh repo clone drewstone/cli-bridge && cd cli-bridge
echo "BRIDGE_BEARER=$(openssl rand -hex 32)" >> .env.local
echo "BRIDGE_BACKENDS=claude,passthrough"     >> .env.local
export $(grep -v '^#' .env.local | xargs) && pnpm exec tsx src/server.ts

# 2. authenticate your harness CLI
claude /login    # or: kimi login, codex login, opencode auth login
import { TCloudClient } from '@tangle-network/tcloud'

const client = TCloudClient.fromCliBridge({
  url: 'http://127.0.0.1:3344',           // or any reachable URL
  bearer: process.env.CLI_BRIDGE_BEARER!, // value of BRIDGE_BEARER from .env.local
})

// model id = `<harness>/<model>` — no `bridge/` prefix in direct mode
const reply = await client.ask('reply with OK', 'claude-code/sonnet')

// streaming + full chat work the same
for await (const chunk of client.askStream('write a haiku', 'kimi-code/kimi-for-coding')) {
  process.stdout.write(chunk)
}

See examples/14-direct-cli-bridge.ts for the full pattern. Direct cli-bridge clients also support client.bridge({ harness, model, resume }); in direct mode the SDK sends <harness>/<model> and maps resume to cli-bridge's session_id.

Model Selection

Model is set at client creation. Override per-request when needed:

// Default model for all requests
const client = new TCloud({ apiKey: '...', model: 'gpt-4o-mini' })
await client.ask('Hello')  // returns string

// Full control per-request (OpenAI-compatible)
const completion = await client.chat({
  model: 'claude-sonnet-4-6',
  messages: [{ role: 'user', content: 'Hello' }],
  temperature: 0.5,
  maxTokens: 100,
}) // returns ChatCompletion { id, model, choices: [{ index, message, finish_reason }], usage? }

// Get full response with usage stats
const full = await client.askFull('Hello') // returns ChatCompletion
console.log(full.model, full.usage?.total_tokens)

// Search available models
const llamas = await client.searchModels('llama') // returns Model[]

Streaming

for await (const chunk of client.askStream('Explain zero-knowledge proofs')) {
  process.stdout.write(chunk)
}

// With model override
for await (const chunk of client.askStream('Hello', 'claude-sonnet-4-6')) {
  process.stdout.write(chunk)
}

Full Chat Completion

OpenAI-compatible request/response format:

const completion = await client.chat({
  model: 'meta-llama/llama-4-maverick',
  messages: [
    { role: 'system', content: 'You are a helpful assistant.' },
    { role: 'user', content: 'Hello' },
  ],
  temperature: 0.7,
  maxTokens: 1024,
}) // returns ChatCompletion

console.log(completion.choices[0].message.content)
// completion.usage => { prompt_tokens, completion_tokens, total_tokens }

Private Inference

Anonymous inference with no API key. Uses EIP-712 SpendAuth signatures — the operator verifies payment without learning your identity.

import { TCloud } from 'tcloud'

const client = TCloud.shielded()
const answer = await client.ask('Hello from the shadows')

Under the hood: generates an ephemeral wallet, signs a SpendAuth payload, and sends it as an X-Payment-Signature header. The operator validates the cryptographic proof and serves inference without knowing who you are.

Embeddings

const response = await client.embeddings({
  model: 'text-embedding-3-small',
  input: 'What is Tangle?',
}) // returns EmbeddingResponse
// EmbeddingResponse: { object, data: [{ object, embedding: number[], index }], model, usage }
console.log(response.data[0].embedding.length) // 1536

Web Search

const results = await client.search({
  query: 'latest Tangle docs',
  provider: 'exa',
  maxResults: 5,
})

console.log(results.data[0].title)
console.log(results.citations)

Use search inside chat with either the typed gateway shorthand or OpenRouter-compatible plugins:

await client.ask('What changed in Tangle this week?', {
  webSearch: { provider: 'exa', maxResults: 5, searchRecency: 'week' },
})

await client.chat({
  messages: [{ role: 'user', content: 'Summarize recent AI video model releases.' }],
  plugins: [{ id: 'web', engine: 'parallel', max_results: 5 }],
})

Video & Avatar Generation

// Generate a video from a text prompt
const video = await client.videoGenerate({
  prompt: 'A sunset over mountains',
  duration: 5,
}) // returns VideoResponse { id, status, url?, error? }

// Generate a talking-head avatar video
const avatar = await client.avatarGenerate({
  audio_url: 'https://example.com/narration.mp3',
  image_url: 'https://example.com/face.jpg',
}) // returns AvatarGenerateResponse { job_id, status, result?, error? }

Async Jobs

Avatar and video generation are asynchronous. Use watchJob() for real-time SSE streaming of job progress, or poll with avatarJobStatus().

// Submit an avatar job
const job = await client.avatarGenerate({
  audio_url: 'https://...',
  image_url: 'https://...',
})
console.log(job.job_id) // 'job-abc123'
console.log(job.status) // 'queued'

// Watch until complete (SSE streaming)
const result = await client.watchJob(job.job_id, {
  onEvent: (e) => console.log(`${e.status} ${e.progress ?? ''}%`),
}) // returns JobEvent { status, progress?, result?, error?, timestamp }
console.log(result.result) // { video_url: 'https://...' }

// Or just poll
const status = await client.avatarJobStatus(job.job_id)
// returns AvatarJobStatus { job_id, status, result?, error? }

Operator Routing

Route requests to specific operators or use strategy-based selection:

const client = new TCloud({
  apiKey: 'sk-tan-...',
  routing: {
    prefer: 'operator-slug',    // specific operator
    strategy: 'lowest-latency', // or 'lowest-price', 'highest-reputation'
    region: 'us-east',          // geographic preference
  },
})

The gateway selects the best operator based on a composite score (reputation 40%, latency 30%, price 30%) and returns the selection in response headers:

// After a request, check which operator served it:
// X-Tangle-Operator: <slug>
// X-Tangle-Price-Input: <per-token>
// X-Tangle-Price-Output: <per-token>

Models and Operators

// List all available models
const models = await client.models() // returns Model[]
// Model: { id, name, context_length, pricing: { prompt, completion }, _provider? }
models.forEach(m => console.log(m.id, m._provider))

// Search models by name, provider, or capability
const llamas = await client.searchModels('llama') // returns Model[]
const anthropic = await client.searchModels('anthropic')

// List active operators with stats
const { operators, stats } = await client.operators()
// returns { operators: Operator[], stats: any }
// Operator: { id, slug, name, status, endpointUrl, reputationScore, avgLatencyMs, models, ... }
console.log(`${stats.activeOperators} operators serving ${stats.totalModels} models`)

// Check credit balance
const credits = await client.credits() // returns CreditBalance
// CreditBalance: { balance: number, transactions: [{ id, amount, type, description, createdAt }] }
console.log(`Balance: $${credits.balance}`)

API Key Management

Create, list, and revoke API keys programmatically:

// Create a new key
const { key, id } = await client.createKey('my-app')
console.log(key) // sk-tan-... (shown once, store it)

// List all keys
const keys = await client.keys()
keys.forEach(k => console.log(k.name, k.prefix, k.lastUsedAt))

// Revoke a key
await client.revokeKey(id)

Cost Estimation

Preview cost before sending a request:

const cost = await client.estimateCost({
  model: 'gpt-4o',
  inputTokens: 1000,
  outputTokens: 500,
}) // returns { inputCost: number, outputCost: number, total: number }
console.log(`Estimated: $${cost.total.toFixed(6)}`)
// { inputCost: 0.005, outputCost: 0.0075, total: 0.0125 }

Spending Limits

Prevent runaway costs with per-request and total budget caps:

const client = new TCloud({
  apiKey: 'sk-tan-...',
  model: 'gpt-4o-mini',
  limits: {
    maxCostPerRequest: 0.01,     // $0.01 max per request
    maxTotalSpend: 1.00,         // $1.00 lifetime budget
    maxRequests: 100,            // hard request cap
    onLimitWarning: (info) => {
      console.warn(`${info.type} at ${info.current}/${info.limit}`)
    },
  },
})

// Requests that would exceed limits are blocked with TCloudError (429)
await client.ask('Hello')

// Check metering
const { totalSpent, requestCount } = client.usage

CLI

Authentication

tcloud auth login              # Browser-based device flow
tcloud auth set-key sk-tan-... # Set key directly
tcloud auth status             # Check current auth

Chat

tcloud chat "Explain zero-knowledge proofs"
tcloud chat -m meta-llama/llama-4-maverick "Hello"
tcloud chat --private "Anonymous request"  # ShieldedCredits mode
tcloud chat                                # Interactive mode

Browse

tcloud models                  # List available models
tcloud models -s llama         # Search models
tcloud search "Tangle docs" --provider exa --max-results 5
tcloud operators               # List active operators

Credits and Keys

tcloud credits balance         # Check balance
tcloud credits add 10          # Add credits
tcloud keys create my-app      # Create a new API key
tcloud keys list               # List keys

Wallet Management

For private inference, manage ephemeral wallets:

tcloud wallet generate                    # Create wallet
tcloud wallet generate -l "research"      # With label
tcloud wallet list                        # List wallets

Wallets use BIP-39 mnemonics with BIP-44 derivation. Private keys are encrypted at rest with AES-256-GCM (PBKDF2 210K iterations).

Configuration

Config stored in ~/.tcloud/config.json:

tcloud config --api-url https://router.tangle.tools
tcloud config --model gpt-4o-mini

Environment variables:

  • TANGLE_API_KEY — API key (primary). One key for router + sandbox + all Tangle products.
  • TCLOUD_API_KEY — Deprecated alias, still honored for backwards compatibility.
  • OPENAI_API_KEY — Fallback API key (works because the API is OpenAI-compatible).
  • TCLOUD_BASE_URL — Override API base URL.

OpenAI SDK Compatibility

tcloud's API is OpenAI-compatible. You can use the OpenAI SDK directly:

import OpenAI from 'openai'

const client = new OpenAI({
  apiKey: 'sk-tan-...',
  baseURL: 'https://router.tangle.tools/v1',
})

const completion = await client.chat.completions.create({
  model: 'meta-llama/llama-4-maverick',
  messages: [{ role: 'user', content: 'Hello' }],
})

Vercel AI SDK Compatibility

Use with the Vercel AI SDK's OpenAI provider:

import { createOpenAI } from '@ai-sdk/openai'
import { generateText } from 'ai'

const tangle = createOpenAI({
  apiKey: 'sk-tan-...',
  baseURL: 'https://router.tangle.tools/v1',
})

const { text } = await generateText({
  model: tangle('meta-llama/llama-4-maverick'),
  prompt: 'What is decentralized AI?',
})

Examples

See the examples/ directory — each is a self-contained script:

| # | Example | What it shows | |---|---------|---------------| | 01 | Quick Start | Minimum viable setup | | 02 | Model Selection | Three ways to pick a model, search, browse | | 03 | Streaming | Real-time SSE output, text + chunk modes | | 04 | Private Inference | ShieldedCredits, ephemeral wallets, auto-replenish | | 05 | Operator Routing | Prefer operator, strategy, region, list operators | | 06 | Cost & Usage | Estimate cost, track tokens, check balance | | 07 | API Keys | Create, list, revoke keys programmatically | | 08 | OpenAI SDK | Drop-in replacement via baseURL | | 09 | Vercel AI SDK | generateText + streamText with Tangle | | 10 | Spending Limits | Budget caps, request limits, warning callbacks | | 11 | Inference Strategies | Min-exposure + operator rotation patterns | | 12 | Bridge Sessions | Persistent bridge sessions for harness routing | | 13 | Bridge Chat App | Multi-turn bridge application | | 14 | Direct cli-bridge | Local cli-bridge, no router | | 15 | Sandbox Agents | Sandbox agents + inline AgentProfile | | 16 | Tangle Intelligence Hook | Trace inference into hosted intelligence (one OTLP block) |

Run any example:

TANGLE_API_KEY=sk-tan-... npx tsx examples/01-quick-start.ts

License

Apache-2.0