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

binario

v0.2.0

Published

Universal AI SDK for Cloudflare Workers - Unified API, smart fallbacks, and cost optimization

Downloads

193

Readme

Binario

Universal AI SDK for Cloudflare Workers — Unified API, smart fallbacks, and cost optimization.

License: MIT TypeScript

⚠️ Status: Beta

This SDK is currently in beta. The hosted API at binario.dev is fully functional. For npm installation, build from source.

✨ Features

| Feature | Status | Notes | |---------|--------|-------| | Chat completions | ✅ Working | Cloudflare Workers AI | | Streaming (SSE) | ✅ Working | Real-time token streaming | | Structured output | ✅ Working | JSON Schema validation | | Embeddings | ✅ Working | @cf/baai/bge-base-en-v1.5 | | Agent framework | ✅ Working | Tool calling with iterations | | React Hooks | ✅ Working | Chat, stream, agent, memory | | Multi-provider | ⚠️ Config required | Needs your own API keys | | Smart caching | ⚠️ Planned | KV-based LRU cache | | Memory system | ⚠️ Client-side | Buffer, summary, vector |

📦 Installation

Option 1: Use the hosted API (Recommended)

Sign up at binario.dev and get an API key.

Option 2: Build from source

git clone https://github.com/your-repo/binario.git
cd binario/packages/binario
npm install && npm run build

🚀 Quick Start

SaaS Mode (Recommended)

The easiest way to get started — use our hosted API with no setup required:

import { Binario } from 'binario';

// Initialize with your API key
const client = new Binario('bsk_your_api_key');

// Simple chat
const response = await client.chat('What is the capital of France?');
console.log(response.content); // "The capital of France is Paris."

// With options
const response = await client.chat('Explain quantum computing', {
  model: 'gpt-4',
  temperature: 0.7,
  maxTokens: 500,
});

Streaming Responses

// Streaming with async iterator
for await (const chunk of client.stream('Tell me a long story')) {
  process.stdout.write(chunk);
}

// Streaming with callbacks
await client.stream('Tell me a story', {
  onToken: (token) => process.stdout.write(token),
  onComplete: (fullText) => console.log('\nDone!'),
  onError: (error) => console.error('Error:', error),
});

Check Usage & Limits

// Get your current usage
const usage = await client.usage();
console.log(`Tokens: ${usage.tokensUsed}/${usage.tokensLimit}`);
console.log(`Requests: ${usage.requestsUsed}/${usage.requestsLimit}`);
console.log(`Plan: ${usage.plan}`);

🏠 Self-Hosted Mode

Run your own backend with Cloudflare Workers for full control:

import { createBinario } from 'binario';

const ai = createBinario({
  providers: {
    cloudflare: {
      binding: env.AI, // Cloudflare AI binding
      accountId: env.CF_ACCOUNT_ID,
    },
    openrouter: {
      apiKey: env.OPENROUTER_API_KEY,
    },
  },
  defaultProvider: 'cloudflare',
});

// Chat with messages array
const response = await ai.chat([
  { role: 'system', content: 'You are a helpful assistant.' },
  { role: 'user', content: 'Hello!' }
]);

// Streaming
const stream = await ai.stream([
  { role: 'user', content: 'Write a poem' }
]);

for await (const chunk of stream) {
  process.stdout.write(chunk);
}

⚛️ React Hooks

SaaS Client Hooks (NEW - Recommended)

These hooks work directly with your API key — no BinarioAI instance needed:

import { Binario } from 'binario';
import { useChat, useStream, useAgent, useUsage } from 'binario/react';

const client = new Binario('bsk_your_api_key');

function ChatApp() {
  const { messages, input, setInput, isLoading, send } = useChat(client, {
    systemPrompt: 'You are a helpful assistant.',
  });

  return (
    <div>
      {messages.map((msg, i) => (
        <div key={i} className={msg.role}>{msg.content}</div>
      ))}
      <input value={input} onChange={e => setInput(e.target.value)} />
      <button onClick={() => send()} disabled={isLoading}>Send</button>
    </div>
  );
}

function StreamingApp() {
  const { messages, streamingContent, isStreaming, send } = useStream(client);

  return (
    <div>
      {messages.map((msg, i) => (
        <div key={i}>{msg.content}</div>
      ))}
      {isStreaming && <div className="streaming">{streamingContent}</div>}
      <button onClick={() => send('Tell me a story')}>Stream</button>
    </div>
  );
}

Self-Hosted Hooks (BinarioAI core)

For self-hosted mode using the BinarioAI instance:

import { useBinarioChat } from 'binario/react';

function ChatComponent() {
  const { 
    messages, 
    sendMessage, 
    isLoading, 
    error,
    clearMessages 
  } = useBinarioChat({
    apiKey: 'bsk_your_api_key',
    systemPrompt: 'You are a helpful assistant.',
  });

  return (
    <div>
      <div className="messages">
        {messages.map((msg, i) => (
          <div key={i} className={`message ${msg.role}`}>
            {msg.content}
          </div>
        ))}
      </div>
      
      {isLoading && <div>Thinking...</div>}
      {error && <div className="error">{error.message}</div>}
      
      <form onSubmit={handleSubmit}>
        <input name="message" placeholder="Type a message..." />
        <button type="submit" disabled={isLoading}>Send</button>
      </form>
    </div>
  );
}

useBinarioStream

Streaming responses with real-time updates:

import { useBinarioStream } from 'binario/react';

function StreamingComponent() {
  const { 
    content, 
    isStreaming, 
    startStream, 
    stopStream 
  } = useBinarioStream({
    apiKey: 'bsk_your_api_key',
  });

  return (
    <div>
      <div className="output">{content}</div>
      <button onClick={() => startStream('Tell me a story')}>
        Start
      </button>
      {isStreaming && (
        <button onClick={stopStream}>Stop</button>
      )}
    </div>
  );
}

useBinarioAgent

Run AI agents with tools in React:

import { useBinarioAgent } from 'binario/react';
import { defineTool } from 'binario';
import { z } from 'zod';

const weatherTool = defineTool({
  name: 'get_weather',
  description: 'Get weather for a location',
  parameters: z.object({
    location: z.string(),
  }),
  execute: async ({ location }) => {
    return { temperature: 22, condition: 'sunny' };
  },
});

function AgentComponent() {
  const { 
    result, 
    isRunning, 
    runAgent,
    steps 
  } = useBinarioAgent({
    apiKey: 'bsk_your_api_key',
    tools: [weatherTool],
    systemPrompt: 'You help users with weather information.',
  });

  return (
    <div>
      <button onClick={() => runAgent('What\'s the weather in Paris?')}>
        Ask Agent
      </button>
      
      {steps.map((step, i) => (
        <div key={i} className="step">
          {step.type === 'tool_call' && (
            <span>Called: {step.toolName}</span>
          )}
        </div>
      ))}
      
      {result && <div className="result">{result.output}</div>}
    </div>
  );
}

useBinarioCompletion

Simple completions without chat history management:

import { useBinarioCompletion } from 'binario/react';

function CompletionComponent() {
  const { 
    result, 
    isLoading, 
    error,
    complete,
    reset 
  } = useBinarioCompletion({
    apiKey: 'bsk_your_api_key',
    model: 'gpt-4',
    temperature: 0.7,
  });

  return (
    <div>
      <button onClick={() => complete('Explain quantum computing in simple terms')}>
        Generate
      </button>
      {isLoading && <div>Generating...</div>}
      {result && <div className="result">{result.content}</div>}
      {error && <div className="error">{error.message}</div>}
      <button onClick={reset}>Reset</button>
    </div>
  );
}

useBinarioStructured

Type-safe structured outputs with Zod schemas:

import { useBinarioStructured } from 'binario/react';
import { z } from 'zod';

const ProductSchema = z.object({
  name: z.string(),
  price: z.number(),
  category: z.enum(['electronics', 'clothing', 'food']),
  inStock: z.boolean(),
});

function StructuredComponent() {
  const { 
    data, 
    isLoading, 
    error,
    extract 
  } = useBinarioStructured<z.infer<typeof ProductSchema>>({
    apiKey: 'bsk_your_api_key',
    schema: ProductSchema,
  });

  return (
    <div>
      <button onClick={() => extract('iPhone 15 Pro, $999, electronics, in stock')}>
        Extract Product
      </button>
      {data && (
        <div>
          <p>Name: {data.name}</p>
          <p>Price: ${data.price}</p>
          <p>Category: {data.category}</p>
          <p>In Stock: {data.inStock ? 'Yes' : 'No'}</p>
        </div>
      )}
    </div>
  );
}

useBinarioTools

Tool calling with automatic execution:

import { useBinarioTools } from 'binario/react';
import { z } from 'zod';

function ToolsComponent() {
  const { 
    messages,
    toolCalls,
    isExecuting,
    sendMessage,
  } = useBinarioTools({
    apiKey: 'bsk_your_api_key',
    tools: {
      get_weather: {
        description: 'Get weather for a location',
        parameters: z.object({
          location: z.string(),
        }),
        execute: async ({ location }) => {
          return { temperature: 22, condition: 'sunny', location };
        },
      },
      calculate: {
        description: 'Perform calculations',
        parameters: z.object({
          expression: z.string(),
        }),
        execute: async ({ expression }) => {
          return { result: eval(expression) };
        },
      },
    },
  });

  return (
    <div>
      <button onClick={() => sendMessage('What is the weather in Paris?')}>
        Ask
      </button>
      {toolCalls.map((call, i) => (
        <div key={i}>Tool: {call.name} → {JSON.stringify(call.result)}</div>
      ))}
    </div>
  );
}

useBinarioMemory

Memory management for persistent conversations:

import { useBinarioMemory } from 'binario/react';

function MemoryComponent() {
  const { 
    messages,
    context,
    addMessage,
    getContext,
    clear,
    isLoading,
    tokenCount,
  } = useBinarioMemory({
    type: 'buffer',
    maxMessages: 50,
    maxTokens: 4000,
  });

  // Add messages
  const handleSend = async (content: string) => {
    await addMessage({ role: 'user', content });
    // Get AI response and add it
    await addMessage({ role: 'assistant', content: 'Response...' });
  };

  return (
    <div>
      <div>Messages: {messages.length}</div>
      <div>Tokens: {tokenCount}</div>
      <button onClick={clear}>Clear Memory</button>
    </div>
  );
}

useBinarioChatWithMemory

Chat with automatic persistent memory:

import { useBinarioChatWithMemory } from 'binario/react';

function PersistentChatComponent() {
  const { 
    messages,
    sendMessage,
    isLoading,
    error,
    summary,
    memoryStats,
    clearMemory,
  } = useBinarioChatWithMemory({
    apiKey: 'bsk_your_api_key',
    memoryType: 'summary-buffer', // 'buffer' | 'summary' | 'summary-buffer' | 'vector'
    memoryOptions: {
      maxMessages: 20,
      summarizeThreshold: 10,
    },
    systemPrompt: 'You are a helpful assistant with memory.',
  });

  return (
    <div>
      <div className="stats">
        <span>Messages in memory: {memoryStats.messageCount}</span>
        <span>Tokens used: {memoryStats.tokenCount}</span>
      </div>
      
      {summary && (
        <div className="summary">
          <strong>Conversation summary:</strong> {summary}
        </div>
      )}
      
      <div className="messages">
        {messages.map((msg, i) => (
          <div key={i} className={msg.role}>{msg.content}</div>
        ))}
      </div>
      
      <input 
        onKeyDown={(e) => {
          if (e.key === 'Enter') {
            sendMessage(e.currentTarget.value);
            e.currentTarget.value = '';
          }
        }}
      />
      
      <button onClick={clearMemory}>Clear Memory</button>
    </div>
  );
}

useBinarioEmbed

Generate embeddings for semantic operations:

import { useBinarioEmbed } from 'binario/react';

function EmbeddingsComponent() {
  const { 
    embed,
    embedMany,
    similarity,
    findSimilar,
    isLoading,
    error,
  } = useBinarioEmbed({
    model: 'bge-base-en-v1.5',
    cacheResults: true,
  });

  // Generate single embedding
  const handleEmbed = async () => {
    const result = await embed('Hello, world!');
    console.log('Embedding dimensions:', result.embedding.length);
  };

  // Generate batch embeddings
  const handleBatchEmbed = async () => {
    const results = await embedMany([
      'First text',
      'Second text',
      'Third text',
    ]);
    console.log('Generated embeddings:', results.embeddings.length);
  };

  // Calculate similarity between texts
  const handleSimilarity = async () => {
    const score = await similarity(
      'I love programming',
      'Coding is my passion'
    );
    console.log('Similarity score:', score); // ~0.85
  };

  // Find similar texts
  const handleFindSimilar = async () => {
    const documents = [
      'JavaScript is a programming language',
      'Python is great for data science',
      'The weather is nice today',
      'React is a UI library',
    ];
    
    const similar = await findSimilar('frontend development', documents, {
      topK: 2,
      minScore: 0.5,
    });
    
    console.log('Similar documents:', similar);
    // [{ text: 'React is a UI library', score: 0.78 }, ...]
  };

  return (
    <div>
      <button onClick={handleEmbed}>Generate Embedding</button>
      <button onClick={handleBatchEmbed}>Batch Embed</button>
      <button onClick={handleSimilarity}>Check Similarity</button>
      <button onClick={handleFindSimilar}>Find Similar</button>
      {isLoading && <div>Processing...</div>}
    </div>
  );
}

useBinarioSemanticSearch

Full semantic search solution with document management:

import { useBinarioSemanticSearch } from 'binario/react';

function SemanticSearchComponent() {
  const { 
    addDocument,
    addDocuments,
    search,
    removeDocument,
    clear,
    documentCount,
    isLoading,
  } = useBinarioSemanticSearch({
    model: 'bge-base-en-v1.5',
  });

  // Add documents to the index
  const handleAddDocuments = async () => {
    await addDocuments([
      { id: 'doc1', content: 'React is a JavaScript library for building UIs' },
      { id: 'doc2', content: 'Vue.js is a progressive JavaScript framework' },
      { id: 'doc3', content: 'Angular is a platform for building web apps' },
      { id: 'doc4', content: 'Python is popular for machine learning' },
    ]);
  };

  // Search for similar documents
  const handleSearch = async () => {
    const results = await search('frontend framework for web development', {
      maxResults: 3,
      minScore: 0.5,
    });
    
    console.log('Search results:', results);
    // [
    //   { id: 'doc3', content: 'Angular...', score: 0.82 },
    //   { id: 'doc1', content: 'React...', score: 0.79 },
    //   { id: 'doc2', content: 'Vue.js...', score: 0.77 },
    // ]
  };

  return (
    <div>
      <div>Documents indexed: {documentCount}</div>
      <button onClick={handleAddDocuments}>Add Documents</button>
      <button onClick={handleSearch}>Search</button>
      <button onClick={() => removeDocument('doc1')}>Remove doc1</button>
      <button onClick={clear}>Clear Index</button>
    </div>
  );
}

🧠 Memory System

The Memory System provides persistent conversation context with multiple strategies for different use cases.

Memory Types

| Type | Description | Best For | |------|-------------|----------| | buffer | Sliding window of recent messages | Simple chatbots, short conversations | | summary | LLM-powered summarization | Long conversations, context compression | | summary-buffer | Hybrid (buffer + summary) | Balanced memory with both recent and historical context | | vector | Semantic search with embeddings | RAG, document Q&A, knowledge retrieval |

BufferMemory

Keeps a sliding window of the most recent messages:

import { createMemory } from 'binario';

const memory = createMemory({
  type: 'buffer',
  options: {
    maxMessages: 50,    // Keep last 50 messages
    maxTokens: 4000,    // Or limit by token count
  },
});

// Add messages
await memory.add({ role: 'user', content: 'Hello!' });
await memory.add({ role: 'assistant', content: 'Hi there!' });

// Get context for AI
const context = await memory.getContext();
console.log(context.messages); // Recent messages
console.log(context.tokenCount); // Approximate tokens

SummaryMemory

Automatically summarizes conversations when they exceed a threshold:

import { createMemory } from 'binario';

const memory = createMemory({
  type: 'summary',
  options: {
    summarizeThreshold: 20,  // Summarize after 20 messages
    summaryMaxTokens: 500,   // Max tokens for summary
  },
});

// Add messages as usual
await memory.add({ role: 'user', content: 'Tell me about Paris' });
await memory.add({ role: 'assistant', content: 'Paris is the capital of France...' });

// Get context includes summary
const context = await memory.getContext();
console.log(context.summary); // "User asked about Paris. Assistant explained..."
console.log(context.messages); // Recent messages after summary

SummaryBufferMemory

Combines buffer memory with automatic summarization:

import { createMemory } from 'binario';

const memory = createMemory({
  type: 'summary-buffer',
  options: {
    maxMessages: 10,          // Keep 10 recent messages
    summarizeThreshold: 20,   // Summarize when total exceeds 20
    summaryMaxTokens: 500,
  },
});

// Best of both worlds
const context = await memory.getContext();
console.log(context.summary);   // Summarized older context
console.log(context.messages);  // Recent 10 messages

VectorMemory

Semantic retrieval for relevant context:

import { createMemory } from 'binario';

const memory = createMemory({
  type: 'vector',
  options: {
    topK: 5,           // Retrieve top 5 relevant messages
    minScore: 0.7,     // Minimum similarity threshold
    embeddings: embeddingsProvider, // Your embeddings provider
  },
});

// Add messages (embeddings generated automatically)
await memory.add({ role: 'user', content: 'How do I deploy to Cloudflare?' });
await memory.add({ role: 'assistant', content: 'Use wrangler deploy command...' });

// Search retrieves semantically relevant messages
const results = await memory.search('cloudflare deployment');
// Returns messages about deployment, even if exact words don't match

Storage Backends

Memory supports multiple storage backends:

import { 
  createMemory, 
  InMemoryStore, 
  LocalStorageStore, 
  CloudflareKVStore 
} from 'binario';

// In-Memory (default, development)
const memoryDev = createMemory({
  type: 'buffer',
  store: new InMemoryStore(),
});

// LocalStorage (browser persistence)
const memoryBrowser = createMemory({
  type: 'buffer',
  store: new LocalStorageStore('my-chat-'),
});

// Cloudflare KV (production, distributed)
const memoryProd = createMemory({
  type: 'buffer',
  store: new CloudflareKVStore(env.CHAT_KV),
});

🔍 Embeddings API

Generate text embeddings for semantic search, similarity, and RAG applications.

CloudflareEmbeddings

Use Cloudflare Workers AI for embeddings:

import { CloudflareEmbeddings, createCloudflareEmbeddings } from 'binario';

// With Workers AI binding (recommended in Workers)
const embeddings = new CloudflareEmbeddings({
  binding: env.AI,
  model: 'bge-base-en-v1.5',
});

// With REST API (for external use)
const embeddings = createCloudflareEmbeddings({
  accountId: process.env.CF_ACCOUNT_ID,
  apiKey: process.env.CF_API_KEY,
  model: 'bge-large-en-v1.5',
});

Available Models

| Model | Dimensions | Use Case | |-------|------------|----------| | bge-small-en-v1.5 | 384 | Fast, lightweight | | bge-base-en-v1.5 | 768 | Balanced (default) | | bge-large-en-v1.5 | 1024 | Highest quality |

Generate Embeddings

// Single embedding
const result = await embeddings.embed('Hello, world!');
console.log(result.embedding);  // Float32Array(768)
console.log(result.model);      // 'bge-base-en-v1.5'

// Batch embeddings (more efficient)
const batch = await embeddings.embedMany([
  'First document',
  'Second document',
  'Third document',
]);
console.log(batch.embeddings.length); // 3

Similarity Search

// Calculate cosine similarity between two embeddings
function cosineSimilarity(a: number[], b: number[]): number {
  let dotProduct = 0;
  let normA = 0;
  let normB = 0;
  
  for (let i = 0; i < a.length; i++) {
    dotProduct += a[i] * b[i];
    normA += a[i] * a[i];
    normB += b[i] * b[i];
  }
  
  return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
}

// Find similar documents
const query = await embeddings.embed('machine learning');
const docs = await embeddings.embedMany([
  'artificial intelligence and neural networks',
  'cooking recipes for beginners',
  'deep learning models',
]);

const similarities = docs.embeddings.map((emb, i) => ({
  index: i,
  score: cosineSimilarity(query.embedding, emb),
}));

similarities.sort((a, b) => b.score - a.score);
console.log(similarities);
// [{ index: 2, score: 0.89 }, { index: 0, score: 0.82 }, { index: 1, score: 0.12 }]

RAG (Retrieval Augmented Generation)

import { Binario, CloudflareEmbeddings, createMemory } from 'binario';

// Setup
const client = new Binario('bsk_your_api_key');
const embeddings = new CloudflareEmbeddings({ binding: env.AI });

// Create vector memory for documents
const memory = createMemory({
  type: 'vector',
  options: {
    topK: 3,
    embeddings,
  },
});

// Index your documents
const documents = [
  'Binario is an AI SDK for Cloudflare Workers',
  'It supports multiple AI providers including OpenAI and Anthropic',
  'The Memory System provides persistent conversation context',
  'Embeddings can be generated using Cloudflare Workers AI',
];

for (const doc of documents) {
  await memory.add({ role: 'system', content: doc });
}

// Query with RAG
async function queryWithRAG(question: string) {
  // Retrieve relevant context
  const results = await memory.search(question);
  const context = results.map(r => r.content).join('\n');
  
  // Generate answer with context
  const response = await client.chat([
    { role: 'system', content: `Answer based on this context:\n${context}` },
    { role: 'user', content: question },
  ]);
  
  return response.content;
}

const answer = await queryWithRAG('What AI providers does Binario support?');
// "Binario supports multiple AI providers including OpenAI and Anthropic."

🤖 Agent Framework

Create powerful AI agents with tool calling:

import { Binario, defineTool } from 'binario';
import { z } from 'zod';

const client = new Binario('bsk_your_api_key');

// Define tools with Zod schemas
const calculatorTool = defineTool({
  name: 'calculator',
  description: 'Perform mathematical calculations',
  parameters: z.object({
    operation: z.enum(['add', 'subtract', 'multiply', 'divide']),
    a: z.number().describe('First number'),
    b: z.number().describe('Second number'),
  }),
  execute: async ({ operation, a, b }) => {
    switch (operation) {
      case 'add': return { result: a + b };
      case 'subtract': return { result: a - b };
      case 'multiply': return { result: a * b };
      case 'divide': return { result: a / b };
    }
  },
});

const searchTool = defineTool({
  name: 'web_search',
  description: 'Search the web for information',
  parameters: z.object({
    query: z.string().describe('Search query'),
    limit: z.number().optional().default(5),
  }),
  execute: async ({ query, limit }) => {
    // Your search implementation
    return { results: ['Result 1', 'Result 2'] };
  },
});

// Create agent with tools
const agent = client.agent({
  systemPrompt: 'You are a helpful assistant with access to tools.',
  tools: [calculatorTool, searchTool],
  maxIterations: 10,
});

// Run the agent
const result = await agent.run('What is 25 * 4, then search for that number');

console.log(result.output);
console.log('Steps taken:', result.steps.length);
console.log('Tokens used:', result.usage.totalTokens);

☁️ Cloudflare Workers

Utilities for building AI-powered Workers:

import { 
  runWithTools, 
  tool,
  calculateNeurons,
  getRecommendedModel,
  CLOUDFLARE_MODELS,
} from 'binario/cloudflare';

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // Get recommended model based on task
    const model = getRecommendedModel('chat', true); // true = prefer free tier
    
    // Define tools using the simple helper
    const weatherTool = tool('get_weather', 'Get weather info', {
      location: { type: 'string', description: 'City name' },
    });
    
    // Run with tool support
    const result = await runWithTools(
      env.AI,
      model,
      [{ role: 'user', content: 'What is the weather in Tokyo?' }],
      [weatherTool],
      {
        onToolCall: async (name, args) => {
          if (name === 'get_weather') {
            return { temperature: 18, condition: 'cloudy' };
          }
        },
      }
    );
    
    // Calculate neuron usage for billing
    const neurons = calculateNeurons(model, result.usage);
    
    return Response.json({
      response: result.content,
      model,
      neurons,
    });
  },
};

Available Cloudflare Models

import { CLOUDFLARE_MODELS, NEURON_COSTS } from 'binario/cloudflare';

// All available models
console.log(CLOUDFLARE_MODELS);
// ['@cf/meta/llama-3.3-70b-instruct-fp8-fast', '@cf/meta/llama-3.2-3b-instruct', ...]

// Check neuron costs
console.log(NEURON_COSTS['@cf/meta/llama-3.3-70b-instruct-fp8-fast']);
// { input: 0.0001, output: 0.0003 }

📊 Structured Outputs

Get type-safe structured data from AI:

import { Binario, createSchema, z } from 'binario';

const client = new Binario('bsk_your_api_key');

// Define output schema
const ProductSchema = createSchema('Product', z.object({
  name: z.string().describe('Product name'),
  price: z.number().describe('Price in USD'),
  category: z.enum(['electronics', 'clothing', 'food']),
  inStock: z.boolean(),
}));

// Get structured output
const product = await client.structured(
  'Extract product info: iPhone 15 Pro, $999, electronics, available',
  ProductSchema
);

console.log(product.name);     // "iPhone 15 Pro"
console.log(product.price);    // 999
console.log(product.category); // "electronics"
console.log(product.inStock);  // true

🔌 Supported Providers

| Provider | Status | Models | Free Tier | |----------|--------|--------|-----------| | Cloudflare Workers AI | ✅ Full | Llama 3.2/3.3, Mistral, Qwen, DeepSeek | ✅ 10K neurons/day | | OpenRouter | ✅ Full | 100+ models | ✅ Free models available | | OpenAI | ✅ Full | GPT-4, GPT-4o, GPT-3.5 | ❌ | | Anthropic | ✅ Full | Claude 3.5, Claude 3 | ❌ | | Google | ✅ Full | Gemini Pro, Gemini Flash | ✅ Free tier | | Mistral | ✅ Full | Mistral Large, Medium, Small | ❌ |

💰 Pricing

| Plan | Requests/Month | Tokens/Month | Price | |------|---------------|--------------|-------| | Free | 1,000 | 50,000 | $0 | | Pro | 50,000 | 500,000 | $19/mo | | Team | 200,000 | 2,000,000 | $79/mo | | Enterprise | Unlimited | Unlimited | Custom |

🔑 Getting Your API Key

  1. Sign up at binario.dev
  2. Go to Dashboard → API Keys
  3. Create a new key starting with bsk_
  4. Use it in your application

🛠️ Error Handling

import { Binario, BinarioRateLimitError, BinarioPaymentError } from 'binario';

const client = new Binario('bsk_your_api_key');

try {
  const response = await client.chat('Hello');
} catch (error) {
  if (error instanceof BinarioRateLimitError) {
    console.log('Rate limited. Retry after:', error.retryAfter);
  } else if (error instanceof BinarioPaymentError) {
    console.log('Upgrade required:', error.message);
  } else {
    throw error;
  }
}

📚 API Reference

Binario Class

new Binario(apiKey: string)
new Binario(options: BinarioOptions)

interface BinarioOptions {
  apiKey: string;
  baseUrl?: string;      // Custom API endpoint
  timeout?: number;      // Request timeout in ms
  retries?: number;      // Number of retries
}

Methods

| Method | Description | |--------|-------------| | chat(message, options?) | Send a chat message | | stream(message, options?) | Stream a response | | structured(message, schema) | Get structured output | | agent(config) | Create an agent | | usage() | Get usage statistics |

🧪 Testing

# Run tests
npm test

# Run with coverage
npm run test:coverage

# Watch mode
npm run test:watch

📄 License

MIT © Binario Team

🔗 Links