🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@ottorouter/ai-sdk

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ottorouter/ai-sdk

A drop-in SDK for accessing AI models (OpenAI, Anthropic, Google, Moonshot, MiniMax, Z.AI) through the [Setu](https://github.com/slashforge/setu) proxy with automatic x402 payments via Solana USDC.

npmnpm
Version
0.2.1
Version published
Weekly downloads
423
-43.07%
Maintainers
1
Weekly downloads
 
Created
Source

@ottocode/ai-sdk

A drop-in SDK for accessing AI models (OpenAI, Anthropic, Google, Moonshot, MiniMax, Z.AI) through the Setu proxy with automatic x402 payments via Solana USDC.

All you need is a Solana wallet — the SDK handles authentication, payment negotiation, and provider routing automatically.

Normal API requests use bearer auth. The SDK signs a wallet nonce once to exchange for a short-lived Setu token, reuses that token across requests, and refreshes it automatically when needed.

Install

bun add @ottocode/ai-sdk ai
# or
npm install @ottocode/ai-sdk ai

Quick Start

import { createOttoRouter } from '@ottocode/ai-sdk';
import { generateText } from 'ai';

const setu = createOttoRouter({
  auth: { privateKey: process.env.SOLANA_PRIVATE_KEY! },
});

const { text } = await generateText({
  model: setu.model('claude-sonnet-4-20250514'),
  prompt: 'Hello!',
});

console.log(text);

The SDK auto-resolves which provider to use based on the model name. It returns ai-sdk compatible model instances that work directly with generateText(), streamText(), etc.

Under the hood, the first protected request exchanges wallet auth headers for a bearer token via POST /v1/auth/wallet-token. Subsequent requests reuse Authorization: Bearer <token> until refresh is needed.

Provider Auto-Resolution

Models are resolved to providers by prefix:

PrefixProviderAPI Format
claude-AnthropicMessages
gpt-, o1, o3, o4, codex-OpenAIResponses
gemini-GoogleNative
kimi-MoonshotOpenAI Chat
MiniMax-MiniMaxMessages
z1-Z.AIOpenAI Chat
setu.model('claude-sonnet-4-20250514');   // → anthropic
setu.model('gpt-4o');                      // → openai
setu.model('gemini-2.5-pro');             // → google
setu.model('kimi-k2');                    // → moonshot

Explicit Provider

Override auto-resolution when needed:

const model = setu.provider('openai').model('gpt-4o');
const model = setu.provider('anthropic', 'anthropic-messages').model('claude-sonnet-4-20250514');

Configuration

const setu = createOttoRouter({
  // Required: Solana wallet private key (base58)
  auth: { privateKey: '...' },

  // Optional: Setu API base URL (default: https://api.ottorouter.org)
  baseURL: 'https://api.ottorouter.org',

  // Optional: Solana RPC URL (default: https://api.mainnet-beta.solana.com)
  rpcURL: 'https://api.mainnet-beta.solana.com',

  // Optional: Payment callbacks
  callbacks: { /* see Payment Callbacks */ },

  // Optional: Cache configuration
  cache: { /* see Caching */ },

  // Optional: Payment options
  payment: { /* see Payment Options */ },

  // Optional: Custom model→provider mappings
  modelMap: {
    'my-custom-model': 'openai',
  },

  // Optional: Register custom providers
  providers: [
    {
      id: 'my-provider',
      apiFormat: 'openai-chat',
      modelPrefix: 'myp-',
    },
  ],
});

Payment Callbacks

Monitor and control the payment lifecycle:

Request authentication and payment signing are separate: bearer auth is used for normal Setu HTTP requests, while your wallet still signs the x402 payment transaction during topups.

const setu = createOttoRouter({
  auth: { privateKey: '...' },
  callbacks: {
    // Called when a 402 is received and payment is needed
    onPaymentRequired: (amountUsd, currentBalance) => {
      console.log(`Payment required: $${amountUsd}`);
    },

    // Called when the SDK is signing a transaction
    onPaymentSigning: () => {
      console.log('Signing payment...');
    },

    // Called after successful payment
    onPaymentComplete: ({ amountUsd, newBalance, transactionId }) => {
      console.log(`Paid $${amountUsd}, balance: $${newBalance}`);
    },

    // Called on payment failure
    onPaymentError: (error) => {
      console.error('Payment failed:', error);
    },

    // Called after each request with cost info (streaming & non-streaming)
    onBalanceUpdate: ({ costUsd, balanceRemaining, inputTokens, outputTokens }) => {
      console.log(`Cost: $${costUsd}, remaining: $${balanceRemaining}`);
    },

    // Optional: interactive approval before payment
    onPaymentApproval: async ({ amountUsd, currentBalance }) => {
      // return 'crypto' to pay, 'fiat' for fiat flow, 'cancel' to abort
      return 'crypto';
    },
  },
});

Payment Options

const setu = createOttoRouter({
  auth: { privateKey: '...' },
  payment: {
    // 'auto' (default) — pay automatically
    // 'approval' — call onPaymentApproval before each payment
    topupApprovalMode: 'auto',

    // Auto-pay without approval if wallet USDC balance >= threshold
    autoPayThresholdUsd: 5.0,

    // Max retries for a single API request (default: 3)
    maxRequestAttempts: 3,

    // Max total payment attempts per wallet (default: 20)
    maxPaymentAttempts: 20,
  },
});

Caching

Anthropic Cache Control

By default, the SDK automatically injects cache_control: { type: 'ephemeral' } on the first system block and the last message for Anthropic models. This saves ~90% on cached token costs.

// Default: auto caching (1 system + 1 message breakpoint)
createOttoRouter({ auth });

// Disable completely
createOttoRouter({ auth, cache: { anthropicCaching: false } });

// Manual: SDK won't inject cache_control — set it yourself in messages
createOttoRouter({ auth, cache: { anthropicCaching: { strategy: 'manual' } } });

// Custom breakpoint count and placement
createOttoRouter({
  auth,
  cache: {
    anthropicCaching: {
      systemBreakpoints: 2,       // cache first 2 system blocks
      systemPlacement: 'first',   // 'first' | 'last' | 'all'
      messageBreakpoints: 3,      // cache last 3 messages
      messagePlacement: 'last',   // 'first' | 'last' | 'all'
    },
  },
});

// Full custom transform
createOttoRouter({
  auth,
  cache: {
    anthropicCaching: {
      strategy: 'custom',
      transform: (body) => {
        // modify body however you want
        return body;
      },
    },
  },
});
OptionDefaultDescription
strategy'auto''auto', 'manual', 'custom', or false
systemBreakpoints1Number of system blocks to cache
messageBreakpoints1Number of messages to cache
systemPlacement'first'Which system blocks: 'first', 'last', 'all'
messagePlacement'last'Which messages: 'first', 'last', 'all'
cacheType'ephemeral'The cache_control.type value

Setu Server-Side Caching

Provider-agnostic caching at the Setu proxy layer:

createOttoRouter({
  auth,
  cache: {
    promptCacheKey: 'my-session-123',
    promptCacheRetention: 'in_memory', // or '24h'
  },
});

OpenAI / Google

  • OpenAI: Automatic server-side prefix caching — no configuration needed
  • Google: Requires pre-uploaded cachedContent at the application level

Balance

// Setu account balance
const balance = await setu.balance();
// { walletAddress, balance, totalSpent, totalTopups, requestCount }

// On-chain USDC balance
const wallet = await setu.walletBalance('mainnet');
// { walletAddress, usdcBalance, network }

// Wallet address
console.log(setu.walletAddress);

Custom Providers

Register providers at init or runtime:

// At init
const setu = createOttoRouter({
  auth,
  providers: [
    { id: 'my-provider', apiFormat: 'openai-chat', modelPrefix: 'myp-' },
  ],
});

// At runtime
setu.registry.register({
  id: 'another-provider',
  apiFormat: 'anthropic-messages',
  models: ['specific-model-id'],
});

// Map a specific model to a provider
setu.registry.mapModel('some-model', 'openai');

API Formats

FormatDescriptionUsed by
openai-responsesOpenAI Responses APIOpenAI
anthropic-messagesAnthropic Messages APIAnthropic, MiniMax
openai-chatOpenAI Chat Completions (compatible)Moonshot, Z.AI
google-nativeGoogle GenerativeAI nativeGoogle

Low-Level: Custom Fetch

Use the x402-aware fetch wrapper directly:

setu.fetch() uses bearer auth for normal requests and automatically refreshes the Setu access token on 401 once before retrying.

const customFetch = setu.fetch();

const response = await customFetch('https://api.ottorouter.org/v1/messages', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ model: 'claude-sonnet-4-20250514', messages: [...] }),
});

Standalone Utilities

import {
  fetchBalance,
  fetchWalletUsdcBalance,
  getPublicKeyFromPrivate,
  addAnthropicCacheControl,
  createOttoRouterFetch,
  createWalletContext,
} from '@ottocode/ai-sdk';

// Get wallet address from private key
const address = getPublicKeyFromPrivate(privateKey);

// Fetch balance without creating a full Setu instance
const balance = await fetchBalance({ privateKey });

// Fetch on-chain USDC
const usdc = await fetchWalletUsdcBalance({ privateKey }, 'mainnet');

// Create a standalone x402-aware fetch
const ottorouterFetch = createOttoRouterFetch({
  wallet: createWalletContext({ privateKey }),
  baseURL: 'https://api.ottorouter.org',
});

createWalletContext() remains available for advanced usage. Its wallet headers are now intended for token exchange only; regular API traffic should go through createOttoRouter(), setu.fetch(), createOttoRouterFetch(), or fetchBalance() so bearer auth refresh is handled automatically.

How It Works

  • You call setu.model('claude-sonnet-4-20250514') — the SDK resolves this to Anthropic
  • It creates an ai-sdk provider (@ai-sdk/anthropic) pointed at the Setu proxy
  • A custom fetch wrapper intercepts all requests to:
    • Exchange signed wallet headers for a short-lived bearer token when needed
    • Inject Authorization: Bearer <token> into normal API requests
    • Inject Anthropic cache control (if enabled)
    • Handle 401 by refreshing the bearer token once and retrying
    • Handle 402 responses by signing USDC payments via x402
    • Sniff balance/cost info from SSE stream comments
  • During topups, the wallet still signs the x402 transaction, but the /v1/topup HTTP request itself uses bearer auth
  • The Setu proxy verifies the wallet/token, checks balance, forwards to the real provider, and tracks usage

Requirements

  • Solana wallet with USDC (for payments)
  • ai SDK v6+ as a peer dependency
  • Node.js 18+ or Bun

License

MIT

FAQs

Package last updated on 23 Apr 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts