binario 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,1140 +1,1175 @@
1
- # Binario
2
-
3
- > Universal AI SDK for Cloudflare Workers — Unified API, smart fallbacks, and cost optimization.
4
-
5
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
- [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
7
-
8
- ## ⚠️ Status: Beta
9
-
10
- This SDK is currently in **beta**. The hosted API at binario.dev is fully functional. For npm installation, build from source.
11
-
12
- ## ✨ Features
13
-
14
- | Feature | Status | Notes |
15
- |---------|--------|-------|
16
- | Chat completions | ✅ Working | Cloudflare Workers AI |
17
- | Streaming (SSE) | ✅ Working | Real-time token streaming |
18
- | Structured output | ✅ Working | JSON Schema validation |
19
- | Embeddings | ✅ Working | `@cf/baai/bge-base-en-v1.5` |
20
- | Agent framework | ✅ Working | Tool calling with iterations |
21
- | React Hooks | ✅ Working | Chat, stream, agent, memory |
22
- | Multi-provider | ⚠️ Config required | Needs your own API keys |
23
- | Smart caching | ⚠️ Planned | KV-based LRU cache |
24
- | Memory system | ⚠️ Client-side | Buffer, summary, vector |
25
-
26
- ## 📦 Installation
27
-
28
- ### Option 1: Use the hosted API (Recommended)
29
-
30
- Sign up at [binario.dev](https://binario.dev) and get an API key.
31
-
32
- ### Option 2: Build from source
33
-
34
- ```bash
35
- git clone https://github.com/your-repo/binario.git
36
- cd binario/packages/binario
37
- npm install && npm run build
38
- ```
39
-
40
- ## 🚀 Quick Start
41
-
42
- ### SaaS Mode (Recommended)
43
-
44
- The easiest way to get started — use our hosted API with no setup required:
45
-
46
- ```typescript
47
- import { Binario } from 'binario';
48
-
49
- // Initialize with your API key
50
- const client = new Binario('bsk_your_api_key');
51
-
52
- // Simple chat
53
- const response = await client.chat('What is the capital of France?');
54
- console.log(response.content); // "The capital of France is Paris."
55
-
56
- // With options
57
- const response = await client.chat('Explain quantum computing', {
58
- model: 'gpt-4',
59
- temperature: 0.7,
60
- maxTokens: 500,
61
- });
62
- ```
63
-
64
- ### Streaming Responses
65
-
66
- ```typescript
67
- // Streaming with async iterator
68
- for await (const chunk of client.stream('Tell me a long story')) {
69
- process.stdout.write(chunk);
70
- }
71
-
72
- // Streaming with callbacks
73
- await client.stream('Tell me a story', {
74
- onToken: (token) => process.stdout.write(token),
75
- onComplete: (fullText) => console.log('\nDone!'),
76
- onError: (error) => console.error('Error:', error),
77
- });
78
- ```
79
-
80
- ### Check Usage & Limits
81
-
82
- ```typescript
83
- // Get your current usage
84
- const usage = await client.usage();
85
- console.log(`Tokens: ${usage.tokensUsed}/${usage.tokensLimit}`);
86
- console.log(`Requests: ${usage.requestsUsed}/${usage.requestsLimit}`);
87
- console.log(`Plan: ${usage.plan}`);
88
- ```
89
-
90
- ## 🏠 Self-Hosted Mode
91
-
92
- Run your own backend with Cloudflare Workers for full control:
93
-
94
- ```typescript
95
- import { createBinario } from 'binario';
96
-
97
- const ai = createBinario({
98
- providers: {
99
- cloudflare: {
100
- binding: env.AI, // Cloudflare AI binding
101
- accountId: env.CF_ACCOUNT_ID,
102
- },
103
- openrouter: {
104
- apiKey: env.OPENROUTER_API_KEY,
105
- },
106
- },
107
- defaultProvider: 'cloudflare',
108
- });
109
-
110
- // Chat with messages array
111
- const response = await ai.chat([
112
- { role: 'system', content: 'You are a helpful assistant.' },
113
- { role: 'user', content: 'Hello!' }
114
- ]);
115
-
116
- // Streaming
117
- const stream = await ai.stream([
118
- { role: 'user', content: 'Write a poem' }
119
- ]);
120
-
121
- for await (const chunk of stream) {
122
- process.stdout.write(chunk);
123
- }
124
- ```
125
-
126
- ## ⚛️ React Hooks
127
-
128
- ### useBinarioChat
129
-
130
- Full-featured chat hook with message history:
131
-
132
- ```tsx
133
- import { useBinarioChat } from 'binario/react';
134
-
135
- function ChatComponent() {
136
- const {
137
- messages,
138
- sendMessage,
139
- isLoading,
140
- error,
141
- clearMessages
142
- } = useBinarioChat({
143
- apiKey: 'bsk_your_api_key',
144
- systemPrompt: 'You are a helpful assistant.',
145
- });
146
-
147
- const handleSubmit = (e: React.FormEvent) => {
148
- e.preventDefault();
149
- const input = e.target.message.value;
150
- sendMessage(input);
151
- };
152
-
153
- return (
154
- <div>
155
- <div className="messages">
156
- {messages.map((msg, i) => (
157
- <div key={i} className={`message ${msg.role}`}>
158
- {msg.content}
159
- </div>
160
- ))}
161
- </div>
162
-
163
- {isLoading && <div>Thinking...</div>}
164
- {error && <div className="error">{error.message}</div>}
165
-
166
- <form onSubmit={handleSubmit}>
167
- <input name="message" placeholder="Type a message..." />
168
- <button type="submit" disabled={isLoading}>Send</button>
169
- </form>
170
- </div>
171
- );
172
- }
173
- ```
174
-
175
- ### useBinarioStream
176
-
177
- Streaming responses with real-time updates:
178
-
179
- ```tsx
180
- import { useBinarioStream } from 'binario/react';
181
-
182
- function StreamingComponent() {
183
- const {
184
- content,
185
- isStreaming,
186
- startStream,
187
- stopStream
188
- } = useBinarioStream({
189
- apiKey: 'bsk_your_api_key',
190
- });
191
-
192
- return (
193
- <div>
194
- <div className="output">{content}</div>
195
- <button onClick={() => startStream('Tell me a story')}>
196
- Start
197
- </button>
198
- {isStreaming && (
199
- <button onClick={stopStream}>Stop</button>
200
- )}
201
- </div>
202
- );
203
- }
204
- ```
205
-
206
- ### useBinarioAgent
207
-
208
- Run AI agents with tools in React:
209
-
210
- ```tsx
211
- import { useBinarioAgent } from 'binario/react';
212
- import { defineTool } from 'binario';
213
- import { z } from 'zod';
214
-
215
- const weatherTool = defineTool({
216
- name: 'get_weather',
217
- description: 'Get weather for a location',
218
- parameters: z.object({
219
- location: z.string(),
220
- }),
221
- execute: async ({ location }) => {
222
- return { temperature: 22, condition: 'sunny' };
223
- },
224
- });
225
-
226
- function AgentComponent() {
227
- const {
228
- result,
229
- isRunning,
230
- runAgent,
231
- steps
232
- } = useBinarioAgent({
233
- apiKey: 'bsk_your_api_key',
234
- tools: [weatherTool],
235
- systemPrompt: 'You help users with weather information.',
236
- });
237
-
238
- return (
239
- <div>
240
- <button onClick={() => runAgent('What\'s the weather in Paris?')}>
241
- Ask Agent
242
- </button>
243
-
244
- {steps.map((step, i) => (
245
- <div key={i} className="step">
246
- {step.type === 'tool_call' && (
247
- <span>Called: {step.toolName}</span>
248
- )}
249
- </div>
250
- ))}
251
-
252
- {result && <div className="result">{result.output}</div>}
253
- </div>
254
- );
255
- }
256
- ```
257
-
258
- ### useBinarioCompletion
259
-
260
- Simple completions without chat history management:
261
-
262
- ```tsx
263
- import { useBinarioCompletion } from 'binario/react';
264
-
265
- function CompletionComponent() {
266
- const {
267
- result,
268
- isLoading,
269
- error,
270
- complete,
271
- reset
272
- } = useBinarioCompletion({
273
- apiKey: 'bsk_your_api_key',
274
- model: 'gpt-4',
275
- temperature: 0.7,
276
- });
277
-
278
- return (
279
- <div>
280
- <button onClick={() => complete('Explain quantum computing in simple terms')}>
281
- Generate
282
- </button>
283
- {isLoading && <div>Generating...</div>}
284
- {result && <div className="result">{result.content}</div>}
285
- {error && <div className="error">{error.message}</div>}
286
- <button onClick={reset}>Reset</button>
287
- </div>
288
- );
289
- }
290
- ```
291
-
292
- ### useBinarioStructured
293
-
294
- Type-safe structured outputs with Zod schemas:
295
-
296
- ```tsx
297
- import { useBinarioStructured } from 'binario/react';
298
- import { z } from 'zod';
299
-
300
- const ProductSchema = z.object({
301
- name: z.string(),
302
- price: z.number(),
303
- category: z.enum(['electronics', 'clothing', 'food']),
304
- inStock: z.boolean(),
305
- });
306
-
307
- function StructuredComponent() {
308
- const {
309
- data,
310
- isLoading,
311
- error,
312
- extract
313
- } = useBinarioStructured<z.infer<typeof ProductSchema>>({
314
- apiKey: 'bsk_your_api_key',
315
- schema: ProductSchema,
316
- });
317
-
318
- return (
319
- <div>
320
- <button onClick={() => extract('iPhone 15 Pro, $999, electronics, in stock')}>
321
- Extract Product
322
- </button>
323
- {data && (
324
- <div>
325
- <p>Name: {data.name}</p>
326
- <p>Price: ${data.price}</p>
327
- <p>Category: {data.category}</p>
328
- <p>In Stock: {data.inStock ? 'Yes' : 'No'}</p>
329
- </div>
330
- )}
331
- </div>
332
- );
333
- }
334
- ```
335
-
336
- ### useBinarioTools
337
-
338
- Tool calling with automatic execution:
339
-
340
- ```tsx
341
- import { useBinarioTools } from 'binario/react';
342
- import { z } from 'zod';
343
-
344
- function ToolsComponent() {
345
- const {
346
- messages,
347
- toolCalls,
348
- isExecuting,
349
- sendMessage,
350
- } = useBinarioTools({
351
- apiKey: 'bsk_your_api_key',
352
- tools: {
353
- get_weather: {
354
- description: 'Get weather for a location',
355
- parameters: z.object({
356
- location: z.string(),
357
- }),
358
- execute: async ({ location }) => {
359
- return { temperature: 22, condition: 'sunny', location };
360
- },
361
- },
362
- calculate: {
363
- description: 'Perform calculations',
364
- parameters: z.object({
365
- expression: z.string(),
366
- }),
367
- execute: async ({ expression }) => {
368
- return { result: eval(expression) };
369
- },
370
- },
371
- },
372
- });
373
-
374
- return (
375
- <div>
376
- <button onClick={() => sendMessage('What is the weather in Paris?')}>
377
- Ask
378
- </button>
379
- {toolCalls.map((call, i) => (
380
- <div key={i}>Tool: {call.name} → {JSON.stringify(call.result)}</div>
381
- ))}
382
- </div>
383
- );
384
- }
385
- ```
386
-
387
- ### useBinarioMemory
388
-
389
- Memory management for persistent conversations:
390
-
391
- ```tsx
392
- import { useBinarioMemory } from 'binario/react';
393
-
394
- function MemoryComponent() {
395
- const {
396
- messages,
397
- context,
398
- addMessage,
399
- getContext,
400
- clear,
401
- isLoading,
402
- tokenCount,
403
- } = useBinarioMemory({
404
- type: 'buffer',
405
- maxMessages: 50,
406
- maxTokens: 4000,
407
- });
408
-
409
- // Add messages
410
- const handleSend = async (content: string) => {
411
- await addMessage({ role: 'user', content });
412
- // Get AI response and add it
413
- await addMessage({ role: 'assistant', content: 'Response...' });
414
- };
415
-
416
- return (
417
- <div>
418
- <div>Messages: {messages.length}</div>
419
- <div>Tokens: {tokenCount}</div>
420
- <button onClick={clear}>Clear Memory</button>
421
- </div>
422
- );
423
- }
424
- ```
425
-
426
- ### useBinarioChatWithMemory
427
-
428
- Chat with automatic persistent memory:
429
-
430
- ```tsx
431
- import { useBinarioChatWithMemory } from 'binario/react';
432
-
433
- function PersistentChatComponent() {
434
- const {
435
- messages,
436
- sendMessage,
437
- isLoading,
438
- error,
439
- summary,
440
- memoryStats,
441
- clearMemory,
442
- } = useBinarioChatWithMemory({
443
- apiKey: 'bsk_your_api_key',
444
- memoryType: 'summary-buffer', // 'buffer' | 'summary' | 'summary-buffer' | 'vector'
445
- memoryOptions: {
446
- maxMessages: 20,
447
- summarizeThreshold: 10,
448
- },
449
- systemPrompt: 'You are a helpful assistant with memory.',
450
- });
451
-
452
- return (
453
- <div>
454
- <div className="stats">
455
- <span>Messages in memory: {memoryStats.messageCount}</span>
456
- <span>Tokens used: {memoryStats.tokenCount}</span>
457
- </div>
458
-
459
- {summary && (
460
- <div className="summary">
461
- <strong>Conversation summary:</strong> {summary}
462
- </div>
463
- )}
464
-
465
- <div className="messages">
466
- {messages.map((msg, i) => (
467
- <div key={i} className={msg.role}>{msg.content}</div>
468
- ))}
469
- </div>
470
-
471
- <input
472
- onKeyDown={(e) => {
473
- if (e.key === 'Enter') {
474
- sendMessage(e.currentTarget.value);
475
- e.currentTarget.value = '';
476
- }
477
- }}
478
- />
479
-
480
- <button onClick={clearMemory}>Clear Memory</button>
481
- </div>
482
- );
483
- }
484
- ```
485
-
486
- ### useBinarioEmbed
487
-
488
- Generate embeddings for semantic operations:
489
-
490
- ```tsx
491
- import { useBinarioEmbed } from 'binario/react';
492
-
493
- function EmbeddingsComponent() {
494
- const {
495
- embed,
496
- embedMany,
497
- similarity,
498
- findSimilar,
499
- isLoading,
500
- error,
501
- } = useBinarioEmbed({
502
- model: 'bge-base-en-v1.5',
503
- cacheResults: true,
504
- });
505
-
506
- // Generate single embedding
507
- const handleEmbed = async () => {
508
- const result = await embed('Hello, world!');
509
- console.log('Embedding dimensions:', result.embedding.length);
510
- };
511
-
512
- // Generate batch embeddings
513
- const handleBatchEmbed = async () => {
514
- const results = await embedMany([
515
- 'First text',
516
- 'Second text',
517
- 'Third text',
518
- ]);
519
- console.log('Generated embeddings:', results.embeddings.length);
520
- };
521
-
522
- // Calculate similarity between texts
523
- const handleSimilarity = async () => {
524
- const score = await similarity(
525
- 'I love programming',
526
- 'Coding is my passion'
527
- );
528
- console.log('Similarity score:', score); // ~0.85
529
- };
530
-
531
- // Find similar texts
532
- const handleFindSimilar = async () => {
533
- const documents = [
534
- 'JavaScript is a programming language',
535
- 'Python is great for data science',
536
- 'The weather is nice today',
537
- 'React is a UI library',
538
- ];
539
-
540
- const similar = await findSimilar('frontend development', documents, {
541
- topK: 2,
542
- minScore: 0.5,
543
- });
544
-
545
- console.log('Similar documents:', similar);
546
- // [{ text: 'React is a UI library', score: 0.78 }, ...]
547
- };
548
-
549
- return (
550
- <div>
551
- <button onClick={handleEmbed}>Generate Embedding</button>
552
- <button onClick={handleBatchEmbed}>Batch Embed</button>
553
- <button onClick={handleSimilarity}>Check Similarity</button>
554
- <button onClick={handleFindSimilar}>Find Similar</button>
555
- {isLoading && <div>Processing...</div>}
556
- </div>
557
- );
558
- }
559
- ```
560
-
561
- ### useBinarioSemanticSearch
562
-
563
- Full semantic search solution with document management:
564
-
565
- ```tsx
566
- import { useBinarioSemanticSearch } from 'binario/react';
567
-
568
- function SemanticSearchComponent() {
569
- const {
570
- addDocument,
571
- addDocuments,
572
- search,
573
- removeDocument,
574
- clear,
575
- documentCount,
576
- isLoading,
577
- } = useBinarioSemanticSearch({
578
- model: 'bge-base-en-v1.5',
579
- });
580
-
581
- // Add documents to the index
582
- const handleAddDocuments = async () => {
583
- await addDocuments([
584
- { id: 'doc1', content: 'React is a JavaScript library for building UIs' },
585
- { id: 'doc2', content: 'Vue.js is a progressive JavaScript framework' },
586
- { id: 'doc3', content: 'Angular is a platform for building web apps' },
587
- { id: 'doc4', content: 'Python is popular for machine learning' },
588
- ]);
589
- };
590
-
591
- // Search for similar documents
592
- const handleSearch = async () => {
593
- const results = await search('frontend framework for web development', {
594
- maxResults: 3,
595
- minScore: 0.5,
596
- });
597
-
598
- console.log('Search results:', results);
599
- // [
600
- // { id: 'doc3', content: 'Angular...', score: 0.82 },
601
- // { id: 'doc1', content: 'React...', score: 0.79 },
602
- // { id: 'doc2', content: 'Vue.js...', score: 0.77 },
603
- // ]
604
- };
605
-
606
- return (
607
- <div>
608
- <div>Documents indexed: {documentCount}</div>
609
- <button onClick={handleAddDocuments}>Add Documents</button>
610
- <button onClick={handleSearch}>Search</button>
611
- <button onClick={() => removeDocument('doc1')}>Remove doc1</button>
612
- <button onClick={clear}>Clear Index</button>
613
- </div>
614
- );
615
- }
616
- ```
617
-
618
- ## 🧠 Memory System
619
-
620
- The Memory System provides persistent conversation context with multiple strategies for different use cases.
621
-
622
- ### Memory Types
623
-
624
- | Type | Description | Best For |
625
- |------|-------------|----------|
626
- | `buffer` | Sliding window of recent messages | Simple chatbots, short conversations |
627
- | `summary` | LLM-powered summarization | Long conversations, context compression |
628
- | `summary-buffer` | Hybrid (buffer + summary) | Balanced memory with both recent and historical context |
629
- | `vector` | Semantic search with embeddings | RAG, document Q&A, knowledge retrieval |
630
-
631
- ### BufferMemory
632
-
633
- Keeps a sliding window of the most recent messages:
634
-
635
- ```typescript
636
- import { createMemory } from 'binario';
637
-
638
- const memory = createMemory({
639
- type: 'buffer',
640
- options: {
641
- maxMessages: 50, // Keep last 50 messages
642
- maxTokens: 4000, // Or limit by token count
643
- },
644
- });
645
-
646
- // Add messages
647
- await memory.add({ role: 'user', content: 'Hello!' });
648
- await memory.add({ role: 'assistant', content: 'Hi there!' });
649
-
650
- // Get context for AI
651
- const context = await memory.getContext();
652
- console.log(context.messages); // Recent messages
653
- console.log(context.tokenCount); // Approximate tokens
654
- ```
655
-
656
- ### SummaryMemory
657
-
658
- Automatically summarizes conversations when they exceed a threshold:
659
-
660
- ```typescript
661
- import { createMemory } from 'binario';
662
-
663
- const memory = createMemory({
664
- type: 'summary',
665
- options: {
666
- summarizeThreshold: 20, // Summarize after 20 messages
667
- summaryMaxTokens: 500, // Max tokens for summary
668
- },
669
- });
670
-
671
- // Add messages as usual
672
- await memory.add({ role: 'user', content: 'Tell me about Paris' });
673
- await memory.add({ role: 'assistant', content: 'Paris is the capital of France...' });
674
-
675
- // Get context includes summary
676
- const context = await memory.getContext();
677
- console.log(context.summary); // "User asked about Paris. Assistant explained..."
678
- console.log(context.messages); // Recent messages after summary
679
- ```
680
-
681
- ### SummaryBufferMemory
682
-
683
- Combines buffer memory with automatic summarization:
684
-
685
- ```typescript
686
- import { createMemory } from 'binario';
687
-
688
- const memory = createMemory({
689
- type: 'summary-buffer',
690
- options: {
691
- maxMessages: 10, // Keep 10 recent messages
692
- summarizeThreshold: 20, // Summarize when total exceeds 20
693
- summaryMaxTokens: 500,
694
- },
695
- });
696
-
697
- // Best of both worlds
698
- const context = await memory.getContext();
699
- console.log(context.summary); // Summarized older context
700
- console.log(context.messages); // Recent 10 messages
701
- ```
702
-
703
- ### VectorMemory
704
-
705
- Semantic retrieval for relevant context:
706
-
707
- ```typescript
708
- import { createMemory } from 'binario';
709
-
710
- const memory = createMemory({
711
- type: 'vector',
712
- options: {
713
- topK: 5, // Retrieve top 5 relevant messages
714
- minScore: 0.7, // Minimum similarity threshold
715
- embeddings: embeddingsProvider, // Your embeddings provider
716
- },
717
- });
718
-
719
- // Add messages (embeddings generated automatically)
720
- await memory.add({ role: 'user', content: 'How do I deploy to Cloudflare?' });
721
- await memory.add({ role: 'assistant', content: 'Use wrangler deploy command...' });
722
-
723
- // Search retrieves semantically relevant messages
724
- const results = await memory.search('cloudflare deployment');
725
- // Returns messages about deployment, even if exact words don't match
726
- ```
727
-
728
- ### Storage Backends
729
-
730
- Memory supports multiple storage backends:
731
-
732
- ```typescript
733
- import {
734
- createMemory,
735
- InMemoryStore,
736
- LocalStorageStore,
737
- CloudflareKVStore
738
- } from 'binario';
739
-
740
- // In-Memory (default, development)
741
- const memoryDev = createMemory({
742
- type: 'buffer',
743
- store: new InMemoryStore(),
744
- });
745
-
746
- // LocalStorage (browser persistence)
747
- const memoryBrowser = createMemory({
748
- type: 'buffer',
749
- store: new LocalStorageStore('my-chat-'),
750
- });
751
-
752
- // Cloudflare KV (production, distributed)
753
- const memoryProd = createMemory({
754
- type: 'buffer',
755
- store: new CloudflareKVStore(env.CHAT_KV),
756
- });
757
- ```
758
-
759
- ## 🔍 Embeddings API
760
-
761
- Generate text embeddings for semantic search, similarity, and RAG applications.
762
-
763
- ### CloudflareEmbeddings
764
-
765
- Use Cloudflare Workers AI for embeddings:
766
-
767
- ```typescript
768
- import { CloudflareEmbeddings, createCloudflareEmbeddings } from 'binario';
769
-
770
- // With Workers AI binding (recommended in Workers)
771
- const embeddings = new CloudflareEmbeddings({
772
- binding: env.AI,
773
- model: 'bge-base-en-v1.5',
774
- });
775
-
776
- // With REST API (for external use)
777
- const embeddings = createCloudflareEmbeddings({
778
- accountId: process.env.CF_ACCOUNT_ID,
779
- apiKey: process.env.CF_API_KEY,
780
- model: 'bge-large-en-v1.5',
781
- });
782
- ```
783
-
784
- ### Available Models
785
-
786
- | Model | Dimensions | Use Case |
787
- |-------|------------|----------|
788
- | `bge-small-en-v1.5` | 384 | Fast, lightweight |
789
- | `bge-base-en-v1.5` | 768 | Balanced (default) |
790
- | `bge-large-en-v1.5` | 1024 | Highest quality |
791
-
792
- ### Generate Embeddings
793
-
794
- ```typescript
795
- // Single embedding
796
- const result = await embeddings.embed('Hello, world!');
797
- console.log(result.embedding); // Float32Array(768)
798
- console.log(result.model); // 'bge-base-en-v1.5'
799
-
800
- // Batch embeddings (more efficient)
801
- const batch = await embeddings.embedMany([
802
- 'First document',
803
- 'Second document',
804
- 'Third document',
805
- ]);
806
- console.log(batch.embeddings.length); // 3
807
- ```
808
-
809
- ### Similarity Search
810
-
811
- ```typescript
812
- // Calculate cosine similarity between two embeddings
813
- function cosineSimilarity(a: number[], b: number[]): number {
814
- let dotProduct = 0;
815
- let normA = 0;
816
- let normB = 0;
817
-
818
- for (let i = 0; i < a.length; i++) {
819
- dotProduct += a[i] * b[i];
820
- normA += a[i] * a[i];
821
- normB += b[i] * b[i];
822
- }
823
-
824
- return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
825
- }
826
-
827
- // Find similar documents
828
- const query = await embeddings.embed('machine learning');
829
- const docs = await embeddings.embedMany([
830
- 'artificial intelligence and neural networks',
831
- 'cooking recipes for beginners',
832
- 'deep learning models',
833
- ]);
834
-
835
- const similarities = docs.embeddings.map((emb, i) => ({
836
- index: i,
837
- score: cosineSimilarity(query.embedding, emb),
838
- }));
839
-
840
- similarities.sort((a, b) => b.score - a.score);
841
- console.log(similarities);
842
- // [{ index: 2, score: 0.89 }, { index: 0, score: 0.82 }, { index: 1, score: 0.12 }]
843
- ```
844
-
845
- ### RAG (Retrieval Augmented Generation)
846
-
847
- ```typescript
848
- import { Binario, CloudflareEmbeddings, createMemory } from 'binario';
849
-
850
- // Setup
851
- const client = new Binario('bsk_your_api_key');
852
- const embeddings = new CloudflareEmbeddings({ binding: env.AI });
853
-
854
- // Create vector memory for documents
855
- const memory = createMemory({
856
- type: 'vector',
857
- options: {
858
- topK: 3,
859
- embeddings,
860
- },
861
- });
862
-
863
- // Index your documents
864
- const documents = [
865
- 'Binario is an AI SDK for Cloudflare Workers',
866
- 'It supports multiple AI providers including OpenAI and Anthropic',
867
- 'The Memory System provides persistent conversation context',
868
- 'Embeddings can be generated using Cloudflare Workers AI',
869
- ];
870
-
871
- for (const doc of documents) {
872
- await memory.add({ role: 'system', content: doc });
873
- }
874
-
875
- // Query with RAG
876
- async function queryWithRAG(question: string) {
877
- // Retrieve relevant context
878
- const results = await memory.search(question);
879
- const context = results.map(r => r.content).join('\n');
880
-
881
- // Generate answer with context
882
- const response = await client.chat([
883
- { role: 'system', content: `Answer based on this context:\n${context}` },
884
- { role: 'user', content: question },
885
- ]);
886
-
887
- return response.content;
888
- }
889
-
890
- const answer = await queryWithRAG('What AI providers does Binario support?');
891
- // "Binario supports multiple AI providers including OpenAI and Anthropic."
892
- ```
893
-
894
- ## 🤖 Agent Framework
895
-
896
- Create powerful AI agents with tool calling:
897
-
898
- ```typescript
899
- import { Binario, defineTool } from 'binario';
900
- import { z } from 'zod';
901
-
902
- const client = new Binario('bsk_your_api_key');
903
-
904
- // Define tools with Zod schemas
905
- const calculatorTool = defineTool({
906
- name: 'calculator',
907
- description: 'Perform mathematical calculations',
908
- parameters: z.object({
909
- operation: z.enum(['add', 'subtract', 'multiply', 'divide']),
910
- a: z.number().describe('First number'),
911
- b: z.number().describe('Second number'),
912
- }),
913
- execute: async ({ operation, a, b }) => {
914
- switch (operation) {
915
- case 'add': return { result: a + b };
916
- case 'subtract': return { result: a - b };
917
- case 'multiply': return { result: a * b };
918
- case 'divide': return { result: a / b };
919
- }
920
- },
921
- });
922
-
923
- const searchTool = defineTool({
924
- name: 'web_search',
925
- description: 'Search the web for information',
926
- parameters: z.object({
927
- query: z.string().describe('Search query'),
928
- limit: z.number().optional().default(5),
929
- }),
930
- execute: async ({ query, limit }) => {
931
- // Your search implementation
932
- return { results: ['Result 1', 'Result 2'] };
933
- },
934
- });
935
-
936
- // Create agent with tools
937
- const agent = client.agent({
938
- systemPrompt: 'You are a helpful assistant with access to tools.',
939
- tools: [calculatorTool, searchTool],
940
- maxIterations: 10,
941
- });
942
-
943
- // Run the agent
944
- const result = await agent.run('What is 25 * 4, then search for that number');
945
-
946
- console.log(result.output);
947
- console.log('Steps taken:', result.steps.length);
948
- console.log('Tokens used:', result.usage.totalTokens);
949
- ```
950
-
951
- ## ☁️ Cloudflare Workers
952
-
953
- Utilities for building AI-powered Workers:
954
-
955
- ```typescript
956
- import {
957
- runWithTools,
958
- tool,
959
- calculateNeurons,
960
- getRecommendedModel,
961
- CLOUDFLARE_MODELS,
962
- } from 'binario/cloudflare';
963
-
964
- export default {
965
- async fetch(request: Request, env: Env): Promise<Response> {
966
- // Get recommended model based on task
967
- const model = getRecommendedModel('chat', true); // true = prefer free tier
968
-
969
- // Define tools using the simple helper
970
- const weatherTool = tool('get_weather', 'Get weather info', {
971
- location: { type: 'string', description: 'City name' },
972
- });
973
-
974
- // Run with tool support
975
- const result = await runWithTools(
976
- env.AI,
977
- model,
978
- [{ role: 'user', content: 'What is the weather in Tokyo?' }],
979
- [weatherTool],
980
- {
981
- onToolCall: async (name, args) => {
982
- if (name === 'get_weather') {
983
- return { temperature: 18, condition: 'cloudy' };
984
- }
985
- },
986
- }
987
- );
988
-
989
- // Calculate neuron usage for billing
990
- const neurons = calculateNeurons(model, result.usage);
991
-
992
- return Response.json({
993
- response: result.content,
994
- model,
995
- neurons,
996
- });
997
- },
998
- };
999
- ```
1000
-
1001
- ### Available Cloudflare Models
1002
-
1003
- ```typescript
1004
- import { CLOUDFLARE_MODELS, NEURON_COSTS } from 'binario/cloudflare';
1005
-
1006
- // All available models
1007
- console.log(CLOUDFLARE_MODELS);
1008
- // ['@cf/meta/llama-3.3-70b-instruct-fp8-fast', '@cf/meta/llama-3.2-3b-instruct', ...]
1009
-
1010
- // Check neuron costs
1011
- console.log(NEURON_COSTS['@cf/meta/llama-3.3-70b-instruct-fp8-fast']);
1012
- // { input: 0.0001, output: 0.0003 }
1013
- ```
1014
-
1015
- ## 📊 Structured Outputs
1016
-
1017
- Get type-safe structured data from AI:
1018
-
1019
- ```typescript
1020
- import { Binario, createSchema, z } from 'binario';
1021
-
1022
- const client = new Binario('bsk_your_api_key');
1023
-
1024
- // Define output schema
1025
- const ProductSchema = createSchema('Product', z.object({
1026
- name: z.string().describe('Product name'),
1027
- price: z.number().describe('Price in USD'),
1028
- category: z.enum(['electronics', 'clothing', 'food']),
1029
- inStock: z.boolean(),
1030
- }));
1031
-
1032
- // Get structured output
1033
- const product = await client.structured(
1034
- 'Extract product info: iPhone 15 Pro, $999, electronics, available',
1035
- ProductSchema
1036
- );
1037
-
1038
- console.log(product.name); // "iPhone 15 Pro"
1039
- console.log(product.price); // 999
1040
- console.log(product.category); // "electronics"
1041
- console.log(product.inStock); // true
1042
- ```
1043
-
1044
- ## 🔌 Supported Providers
1045
-
1046
- | Provider | Status | Models | Free Tier |
1047
- |----------|--------|--------|-----------|
1048
- | Cloudflare Workers AI | ✅ Full | Llama 3.2/3.3, Mistral, Qwen, DeepSeek | ✅ 10K neurons/day |
1049
- | OpenRouter | ✅ Full | 100+ models | ✅ Free models available |
1050
- | OpenAI | ✅ Full | GPT-4, GPT-4o, GPT-3.5 | ❌ |
1051
- | Anthropic | ✅ Full | Claude 3.5, Claude 3 | ❌ |
1052
- | Google | Full | Gemini Pro, Gemini Flash | ✅ Free tier |
1053
- | Mistral | ✅ Full | Mistral Large, Medium, Small | ❌ |
1054
-
1055
- ## 💰 Pricing
1056
-
1057
- | Plan | Requests/Month | Tokens/Month | Price |
1058
- |------|---------------|--------------|-------|
1059
- | Free | 1,000 | 50,000 | $0 |
1060
- | Pro | 50,000 | 500,000 | $19/mo |
1061
- | Team | 200,000 | 2,000,000 | $79/mo |
1062
- | Enterprise | Unlimited | Unlimited | Custom |
1063
-
1064
- ## 🔑 Getting Your API Key
1065
-
1066
- 1. Sign up at [binario.dev](https://binario.dev)
1067
- 2. Go to Dashboard → API Keys
1068
- 3. Create a new key starting with `bsk_`
1069
- 4. Use it in your application
1070
-
1071
- ## 🛠️ Error Handling
1072
-
1073
- ```typescript
1074
- import { Binario, BinarioRateLimitError, BinarioPaymentError } from 'binario';
1075
-
1076
- const client = new Binario('bsk_your_api_key');
1077
-
1078
- try {
1079
- const response = await client.chat('Hello');
1080
- } catch (error) {
1081
- if (error instanceof BinarioRateLimitError) {
1082
- console.log('Rate limited. Retry after:', error.retryAfter);
1083
- } else if (error instanceof BinarioPaymentError) {
1084
- console.log('Upgrade required:', error.message);
1085
- } else {
1086
- throw error;
1087
- }
1088
- }
1089
- ```
1090
-
1091
- ## 📚 API Reference
1092
-
1093
- ### Binario Class
1094
-
1095
- ```typescript
1096
- new Binario(apiKey: string)
1097
- new Binario(options: BinarioOptions)
1098
-
1099
- interface BinarioOptions {
1100
- apiKey: string;
1101
- baseUrl?: string; // Custom API endpoint
1102
- timeout?: number; // Request timeout in ms
1103
- retries?: number; // Number of retries
1104
- }
1105
- ```
1106
-
1107
- ### Methods
1108
-
1109
- | Method | Description |
1110
- |--------|-------------|
1111
- | `chat(message, options?)` | Send a chat message |
1112
- | `stream(message, options?)` | Stream a response |
1113
- | `structured(message, schema)` | Get structured output |
1114
- | `agent(config)` | Create an agent |
1115
- | `usage()` | Get usage statistics |
1116
-
1117
- ## 🧪 Testing
1118
-
1119
- ```bash
1120
- # Run tests
1121
- npm test
1122
-
1123
- # Run with coverage
1124
- npm run test:coverage
1125
-
1126
- # Watch mode
1127
- npm run test:watch
1128
- ```
1129
-
1130
- ## 📄 License
1131
-
1132
- MIT © Binario Team
1133
-
1134
- ## 🔗 Links
1135
-
1136
- - [Documentation](https://binario.dev/docs)
1137
- - [API Reference](https://binario.dev/docs/api)
1138
- - [Examples](https://github.com/binario-ai/binario/tree/main/examples)
1139
- - [Discord Community](https://discord.gg/binario)
1140
- - [Twitter](https://twitter.com/binario_ai)
1
+ # Binario
2
+
3
+ > Universal AI SDK for Cloudflare Workers — Unified API, smart fallbacks, and cost optimization.
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
7
+
8
+ ## ⚠️ Status: Beta
9
+
10
+ This SDK is currently in **beta**. The hosted API at binario.dev is fully functional. For npm installation, build from source.
11
+
12
+ ## ✨ Features
13
+
14
+ | Feature | Status | Notes |
15
+ |---------|--------|-------|
16
+ | Chat completions | ✅ Working | Cloudflare Workers AI |
17
+ | Streaming (SSE) | ✅ Working | Real-time token streaming |
18
+ | Structured output | ✅ Working | JSON Schema validation |
19
+ | Embeddings | ✅ Working | `@cf/baai/bge-base-en-v1.5` |
20
+ | Agent framework | ✅ Working | Tool calling with iterations |
21
+ | React Hooks | ✅ Working | Chat, stream, agent, memory |
22
+ | Multi-provider | ⚠️ Config required | Needs your own API keys |
23
+ | Smart caching | ⚠️ Planned | KV-based LRU cache |
24
+ | Memory system | ⚠️ Client-side | Buffer, summary, vector |
25
+
26
+ ## 📦 Installation
27
+
28
+ ### Option 1: Use the hosted API (Recommended)
29
+
30
+ Sign up at [binario.dev](https://binario.dev) and get an API key.
31
+
32
+ ### Option 2: Build from source
33
+
34
+ ```bash
35
+ git clone https://github.com/your-repo/binario.git
36
+ cd binario/packages/binario
37
+ npm install && npm run build
38
+ ```
39
+
40
+ ## 🚀 Quick Start
41
+
42
+ ### SaaS Mode (Recommended)
43
+
44
+ The easiest way to get started — use our hosted API with no setup required:
45
+
46
+ ```typescript
47
+ import { Binario } from 'binario';
48
+
49
+ // Initialize with your API key
50
+ const client = new Binario('bsk_your_api_key');
51
+
52
+ // Simple chat
53
+ const response = await client.chat('What is the capital of France?');
54
+ console.log(response.content); // "The capital of France is Paris."
55
+
56
+ // With options
57
+ const response = await client.chat('Explain quantum computing', {
58
+ model: 'gpt-4',
59
+ temperature: 0.7,
60
+ maxTokens: 500,
61
+ });
62
+ ```
63
+
64
+ ### Streaming Responses
65
+
66
+ ```typescript
67
+ // Streaming with async iterator
68
+ for await (const chunk of client.stream('Tell me a long story')) {
69
+ process.stdout.write(chunk);
70
+ }
71
+
72
+ // Streaming with callbacks
73
+ await client.stream('Tell me a story', {
74
+ onToken: (token) => process.stdout.write(token),
75
+ onComplete: (fullText) => console.log('\nDone!'),
76
+ onError: (error) => console.error('Error:', error),
77
+ });
78
+ ```
79
+
80
+ ### Check Usage & Limits
81
+
82
+ ```typescript
83
+ // Get your current usage
84
+ const usage = await client.usage();
85
+ console.log(`Tokens: ${usage.tokensUsed}/${usage.tokensLimit}`);
86
+ console.log(`Requests: ${usage.requestsUsed}/${usage.requestsLimit}`);
87
+ console.log(`Plan: ${usage.plan}`);
88
+ ```
89
+
90
+ ## 🏠 Self-Hosted Mode
91
+
92
+ Run your own backend with Cloudflare Workers for full control:
93
+
94
+ ```typescript
95
+ import { createBinario } from 'binario';
96
+
97
+ const ai = createBinario({
98
+ providers: {
99
+ cloudflare: {
100
+ binding: env.AI, // Cloudflare AI binding
101
+ accountId: env.CF_ACCOUNT_ID,
102
+ },
103
+ openrouter: {
104
+ apiKey: env.OPENROUTER_API_KEY,
105
+ },
106
+ },
107
+ defaultProvider: 'cloudflare',
108
+ });
109
+
110
+ // Chat with messages array
111
+ const response = await ai.chat([
112
+ { role: 'system', content: 'You are a helpful assistant.' },
113
+ { role: 'user', content: 'Hello!' }
114
+ ]);
115
+
116
+ // Streaming
117
+ const stream = await ai.stream([
118
+ { role: 'user', content: 'Write a poem' }
119
+ ]);
120
+
121
+ for await (const chunk of stream) {
122
+ process.stdout.write(chunk);
123
+ }
124
+ ```
125
+
126
+ ## ⚛️ React Hooks
127
+
128
+ ### SaaS Client Hooks (NEW - Recommended)
129
+
130
+ These hooks work directly with your API key — no BinarioAI instance needed:
131
+
132
+ ```tsx
133
+ import { Binario } from 'binario';
134
+ import { useChat, useStream, useAgent, useUsage } from 'binario/react';
135
+
136
+ const client = new Binario('bsk_your_api_key');
137
+
138
+ function ChatApp() {
139
+ const { messages, input, setInput, isLoading, send } = useChat(client, {
140
+ systemPrompt: 'You are a helpful assistant.',
141
+ });
142
+
143
+ return (
144
+ <div>
145
+ {messages.map((msg, i) => (
146
+ <div key={i} className={msg.role}>{msg.content}</div>
147
+ ))}
148
+ <input value={input} onChange={e => setInput(e.target.value)} />
149
+ <button onClick={() => send()} disabled={isLoading}>Send</button>
150
+ </div>
151
+ );
152
+ }
153
+
154
+ function StreamingApp() {
155
+ const { messages, streamingContent, isStreaming, send } = useStream(client);
156
+
157
+ return (
158
+ <div>
159
+ {messages.map((msg, i) => (
160
+ <div key={i}>{msg.content}</div>
161
+ ))}
162
+ {isStreaming && <div className="streaming">{streamingContent}</div>}
163
+ <button onClick={() => send('Tell me a story')}>Stream</button>
164
+ </div>
165
+ );
166
+ }
167
+ ```
168
+
169
+ ### Self-Hosted Hooks (BinarioAI core)
170
+
171
+ For self-hosted mode using the `BinarioAI` instance:
172
+
173
+ ```tsx
174
+ import { useBinarioChat } from 'binario/react';
175
+
176
+ function ChatComponent() {
177
+ const {
178
+ messages,
179
+ sendMessage,
180
+ isLoading,
181
+ error,
182
+ clearMessages
183
+ } = useBinarioChat({
184
+ apiKey: 'bsk_your_api_key',
185
+ systemPrompt: 'You are a helpful assistant.',
186
+ });
187
+
188
+ return (
189
+ <div>
190
+ <div className="messages">
191
+ {messages.map((msg, i) => (
192
+ <div key={i} className={`message ${msg.role}`}>
193
+ {msg.content}
194
+ </div>
195
+ ))}
196
+ </div>
197
+
198
+ {isLoading && <div>Thinking...</div>}
199
+ {error && <div className="error">{error.message}</div>}
200
+
201
+ <form onSubmit={handleSubmit}>
202
+ <input name="message" placeholder="Type a message..." />
203
+ <button type="submit" disabled={isLoading}>Send</button>
204
+ </form>
205
+ </div>
206
+ );
207
+ }
208
+ ```
209
+
210
+ ### useBinarioStream
211
+
212
+ Streaming responses with real-time updates:
213
+
214
+ ```tsx
215
+ import { useBinarioStream } from 'binario/react';
216
+
217
+ function StreamingComponent() {
218
+ const {
219
+ content,
220
+ isStreaming,
221
+ startStream,
222
+ stopStream
223
+ } = useBinarioStream({
224
+ apiKey: 'bsk_your_api_key',
225
+ });
226
+
227
+ return (
228
+ <div>
229
+ <div className="output">{content}</div>
230
+ <button onClick={() => startStream('Tell me a story')}>
231
+ Start
232
+ </button>
233
+ {isStreaming && (
234
+ <button onClick={stopStream}>Stop</button>
235
+ )}
236
+ </div>
237
+ );
238
+ }
239
+ ```
240
+
241
+ ### useBinarioAgent
242
+
243
+ Run AI agents with tools in React:
244
+
245
+ ```tsx
246
+ import { useBinarioAgent } from 'binario/react';
247
+ import { defineTool } from 'binario';
248
+ import { z } from 'zod';
249
+
250
+ const weatherTool = defineTool({
251
+ name: 'get_weather',
252
+ description: 'Get weather for a location',
253
+ parameters: z.object({
254
+ location: z.string(),
255
+ }),
256
+ execute: async ({ location }) => {
257
+ return { temperature: 22, condition: 'sunny' };
258
+ },
259
+ });
260
+
261
+ function AgentComponent() {
262
+ const {
263
+ result,
264
+ isRunning,
265
+ runAgent,
266
+ steps
267
+ } = useBinarioAgent({
268
+ apiKey: 'bsk_your_api_key',
269
+ tools: [weatherTool],
270
+ systemPrompt: 'You help users with weather information.',
271
+ });
272
+
273
+ return (
274
+ <div>
275
+ <button onClick={() => runAgent('What\'s the weather in Paris?')}>
276
+ Ask Agent
277
+ </button>
278
+
279
+ {steps.map((step, i) => (
280
+ <div key={i} className="step">
281
+ {step.type === 'tool_call' && (
282
+ <span>Called: {step.toolName}</span>
283
+ )}
284
+ </div>
285
+ ))}
286
+
287
+ {result && <div className="result">{result.output}</div>}
288
+ </div>
289
+ );
290
+ }
291
+ ```
292
+
293
+ ### useBinarioCompletion
294
+
295
+ Simple completions without chat history management:
296
+
297
+ ```tsx
298
+ import { useBinarioCompletion } from 'binario/react';
299
+
300
+ function CompletionComponent() {
301
+ const {
302
+ result,
303
+ isLoading,
304
+ error,
305
+ complete,
306
+ reset
307
+ } = useBinarioCompletion({
308
+ apiKey: 'bsk_your_api_key',
309
+ model: 'gpt-4',
310
+ temperature: 0.7,
311
+ });
312
+
313
+ return (
314
+ <div>
315
+ <button onClick={() => complete('Explain quantum computing in simple terms')}>
316
+ Generate
317
+ </button>
318
+ {isLoading && <div>Generating...</div>}
319
+ {result && <div className="result">{result.content}</div>}
320
+ {error && <div className="error">{error.message}</div>}
321
+ <button onClick={reset}>Reset</button>
322
+ </div>
323
+ );
324
+ }
325
+ ```
326
+
327
+ ### useBinarioStructured
328
+
329
+ Type-safe structured outputs with Zod schemas:
330
+
331
+ ```tsx
332
+ import { useBinarioStructured } from 'binario/react';
333
+ import { z } from 'zod';
334
+
335
+ const ProductSchema = z.object({
336
+ name: z.string(),
337
+ price: z.number(),
338
+ category: z.enum(['electronics', 'clothing', 'food']),
339
+ inStock: z.boolean(),
340
+ });
341
+
342
+ function StructuredComponent() {
343
+ const {
344
+ data,
345
+ isLoading,
346
+ error,
347
+ extract
348
+ } = useBinarioStructured<z.infer<typeof ProductSchema>>({
349
+ apiKey: 'bsk_your_api_key',
350
+ schema: ProductSchema,
351
+ });
352
+
353
+ return (
354
+ <div>
355
+ <button onClick={() => extract('iPhone 15 Pro, $999, electronics, in stock')}>
356
+ Extract Product
357
+ </button>
358
+ {data && (
359
+ <div>
360
+ <p>Name: {data.name}</p>
361
+ <p>Price: ${data.price}</p>
362
+ <p>Category: {data.category}</p>
363
+ <p>In Stock: {data.inStock ? 'Yes' : 'No'}</p>
364
+ </div>
365
+ )}
366
+ </div>
367
+ );
368
+ }
369
+ ```
370
+
371
+ ### useBinarioTools
372
+
373
+ Tool calling with automatic execution:
374
+
375
+ ```tsx
376
+ import { useBinarioTools } from 'binario/react';
377
+ import { z } from 'zod';
378
+
379
+ function ToolsComponent() {
380
+ const {
381
+ messages,
382
+ toolCalls,
383
+ isExecuting,
384
+ sendMessage,
385
+ } = useBinarioTools({
386
+ apiKey: 'bsk_your_api_key',
387
+ tools: {
388
+ get_weather: {
389
+ description: 'Get weather for a location',
390
+ parameters: z.object({
391
+ location: z.string(),
392
+ }),
393
+ execute: async ({ location }) => {
394
+ return { temperature: 22, condition: 'sunny', location };
395
+ },
396
+ },
397
+ calculate: {
398
+ description: 'Perform calculations',
399
+ parameters: z.object({
400
+ expression: z.string(),
401
+ }),
402
+ execute: async ({ expression }) => {
403
+ return { result: eval(expression) };
404
+ },
405
+ },
406
+ },
407
+ });
408
+
409
+ return (
410
+ <div>
411
+ <button onClick={() => sendMessage('What is the weather in Paris?')}>
412
+ Ask
413
+ </button>
414
+ {toolCalls.map((call, i) => (
415
+ <div key={i}>Tool: {call.name} → {JSON.stringify(call.result)}</div>
416
+ ))}
417
+ </div>
418
+ );
419
+ }
420
+ ```
421
+
422
+ ### useBinarioMemory
423
+
424
+ Memory management for persistent conversations:
425
+
426
+ ```tsx
427
+ import { useBinarioMemory } from 'binario/react';
428
+
429
+ function MemoryComponent() {
430
+ const {
431
+ messages,
432
+ context,
433
+ addMessage,
434
+ getContext,
435
+ clear,
436
+ isLoading,
437
+ tokenCount,
438
+ } = useBinarioMemory({
439
+ type: 'buffer',
440
+ maxMessages: 50,
441
+ maxTokens: 4000,
442
+ });
443
+
444
+ // Add messages
445
+ const handleSend = async (content: string) => {
446
+ await addMessage({ role: 'user', content });
447
+ // Get AI response and add it
448
+ await addMessage({ role: 'assistant', content: 'Response...' });
449
+ };
450
+
451
+ return (
452
+ <div>
453
+ <div>Messages: {messages.length}</div>
454
+ <div>Tokens: {tokenCount}</div>
455
+ <button onClick={clear}>Clear Memory</button>
456
+ </div>
457
+ );
458
+ }
459
+ ```
460
+
461
+ ### useBinarioChatWithMemory
462
+
463
+ Chat with automatic persistent memory:
464
+
465
+ ```tsx
466
+ import { useBinarioChatWithMemory } from 'binario/react';
467
+
468
+ function PersistentChatComponent() {
469
+ const {
470
+ messages,
471
+ sendMessage,
472
+ isLoading,
473
+ error,
474
+ summary,
475
+ memoryStats,
476
+ clearMemory,
477
+ } = useBinarioChatWithMemory({
478
+ apiKey: 'bsk_your_api_key',
479
+ memoryType: 'summary-buffer', // 'buffer' | 'summary' | 'summary-buffer' | 'vector'
480
+ memoryOptions: {
481
+ maxMessages: 20,
482
+ summarizeThreshold: 10,
483
+ },
484
+ systemPrompt: 'You are a helpful assistant with memory.',
485
+ });
486
+
487
+ return (
488
+ <div>
489
+ <div className="stats">
490
+ <span>Messages in memory: {memoryStats.messageCount}</span>
491
+ <span>Tokens used: {memoryStats.tokenCount}</span>
492
+ </div>
493
+
494
+ {summary && (
495
+ <div className="summary">
496
+ <strong>Conversation summary:</strong> {summary}
497
+ </div>
498
+ )}
499
+
500
+ <div className="messages">
501
+ {messages.map((msg, i) => (
502
+ <div key={i} className={msg.role}>{msg.content}</div>
503
+ ))}
504
+ </div>
505
+
506
+ <input
507
+ onKeyDown={(e) => {
508
+ if (e.key === 'Enter') {
509
+ sendMessage(e.currentTarget.value);
510
+ e.currentTarget.value = '';
511
+ }
512
+ }}
513
+ />
514
+
515
+ <button onClick={clearMemory}>Clear Memory</button>
516
+ </div>
517
+ );
518
+ }
519
+ ```
520
+
521
+ ### useBinarioEmbed
522
+
523
+ Generate embeddings for semantic operations:
524
+
525
+ ```tsx
526
+ import { useBinarioEmbed } from 'binario/react';
527
+
528
+ function EmbeddingsComponent() {
529
+ const {
530
+ embed,
531
+ embedMany,
532
+ similarity,
533
+ findSimilar,
534
+ isLoading,
535
+ error,
536
+ } = useBinarioEmbed({
537
+ model: 'bge-base-en-v1.5',
538
+ cacheResults: true,
539
+ });
540
+
541
+ // Generate single embedding
542
+ const handleEmbed = async () => {
543
+ const result = await embed('Hello, world!');
544
+ console.log('Embedding dimensions:', result.embedding.length);
545
+ };
546
+
547
+ // Generate batch embeddings
548
+ const handleBatchEmbed = async () => {
549
+ const results = await embedMany([
550
+ 'First text',
551
+ 'Second text',
552
+ 'Third text',
553
+ ]);
554
+ console.log('Generated embeddings:', results.embeddings.length);
555
+ };
556
+
557
+ // Calculate similarity between texts
558
+ const handleSimilarity = async () => {
559
+ const score = await similarity(
560
+ 'I love programming',
561
+ 'Coding is my passion'
562
+ );
563
+ console.log('Similarity score:', score); // ~0.85
564
+ };
565
+
566
+ // Find similar texts
567
+ const handleFindSimilar = async () => {
568
+ const documents = [
569
+ 'JavaScript is a programming language',
570
+ 'Python is great for data science',
571
+ 'The weather is nice today',
572
+ 'React is a UI library',
573
+ ];
574
+
575
+ const similar = await findSimilar('frontend development', documents, {
576
+ topK: 2,
577
+ minScore: 0.5,
578
+ });
579
+
580
+ console.log('Similar documents:', similar);
581
+ // [{ text: 'React is a UI library', score: 0.78 }, ...]
582
+ };
583
+
584
+ return (
585
+ <div>
586
+ <button onClick={handleEmbed}>Generate Embedding</button>
587
+ <button onClick={handleBatchEmbed}>Batch Embed</button>
588
+ <button onClick={handleSimilarity}>Check Similarity</button>
589
+ <button onClick={handleFindSimilar}>Find Similar</button>
590
+ {isLoading && <div>Processing...</div>}
591
+ </div>
592
+ );
593
+ }
594
+ ```
595
+
596
+ ### useBinarioSemanticSearch
597
+
598
+ Full semantic search solution with document management:
599
+
600
+ ```tsx
601
+ import { useBinarioSemanticSearch } from 'binario/react';
602
+
603
+ function SemanticSearchComponent() {
604
+ const {
605
+ addDocument,
606
+ addDocuments,
607
+ search,
608
+ removeDocument,
609
+ clear,
610
+ documentCount,
611
+ isLoading,
612
+ } = useBinarioSemanticSearch({
613
+ model: 'bge-base-en-v1.5',
614
+ });
615
+
616
+ // Add documents to the index
617
+ const handleAddDocuments = async () => {
618
+ await addDocuments([
619
+ { id: 'doc1', content: 'React is a JavaScript library for building UIs' },
620
+ { id: 'doc2', content: 'Vue.js is a progressive JavaScript framework' },
621
+ { id: 'doc3', content: 'Angular is a platform for building web apps' },
622
+ { id: 'doc4', content: 'Python is popular for machine learning' },
623
+ ]);
624
+ };
625
+
626
+ // Search for similar documents
627
+ const handleSearch = async () => {
628
+ const results = await search('frontend framework for web development', {
629
+ maxResults: 3,
630
+ minScore: 0.5,
631
+ });
632
+
633
+ console.log('Search results:', results);
634
+ // [
635
+ // { id: 'doc3', content: 'Angular...', score: 0.82 },
636
+ // { id: 'doc1', content: 'React...', score: 0.79 },
637
+ // { id: 'doc2', content: 'Vue.js...', score: 0.77 },
638
+ // ]
639
+ };
640
+
641
+ return (
642
+ <div>
643
+ <div>Documents indexed: {documentCount}</div>
644
+ <button onClick={handleAddDocuments}>Add Documents</button>
645
+ <button onClick={handleSearch}>Search</button>
646
+ <button onClick={() => removeDocument('doc1')}>Remove doc1</button>
647
+ <button onClick={clear}>Clear Index</button>
648
+ </div>
649
+ );
650
+ }
651
+ ```
652
+
653
+ ## 🧠 Memory System
654
+
655
+ The Memory System provides persistent conversation context with multiple strategies for different use cases.
656
+
657
+ ### Memory Types
658
+
659
+ | Type | Description | Best For |
660
+ |------|-------------|----------|
661
+ | `buffer` | Sliding window of recent messages | Simple chatbots, short conversations |
662
+ | `summary` | LLM-powered summarization | Long conversations, context compression |
663
+ | `summary-buffer` | Hybrid (buffer + summary) | Balanced memory with both recent and historical context |
664
+ | `vector` | Semantic search with embeddings | RAG, document Q&A, knowledge retrieval |
665
+
666
+ ### BufferMemory
667
+
668
+ Keeps a sliding window of the most recent messages:
669
+
670
+ ```typescript
671
+ import { createMemory } from 'binario';
672
+
673
+ const memory = createMemory({
674
+ type: 'buffer',
675
+ options: {
676
+ maxMessages: 50, // Keep last 50 messages
677
+ maxTokens: 4000, // Or limit by token count
678
+ },
679
+ });
680
+
681
+ // Add messages
682
+ await memory.add({ role: 'user', content: 'Hello!' });
683
+ await memory.add({ role: 'assistant', content: 'Hi there!' });
684
+
685
+ // Get context for AI
686
+ const context = await memory.getContext();
687
+ console.log(context.messages); // Recent messages
688
+ console.log(context.tokenCount); // Approximate tokens
689
+ ```
690
+
691
+ ### SummaryMemory
692
+
693
+ Automatically summarizes conversations when they exceed a threshold:
694
+
695
+ ```typescript
696
+ import { createMemory } from 'binario';
697
+
698
+ const memory = createMemory({
699
+ type: 'summary',
700
+ options: {
701
+ summarizeThreshold: 20, // Summarize after 20 messages
702
+ summaryMaxTokens: 500, // Max tokens for summary
703
+ },
704
+ });
705
+
706
+ // Add messages as usual
707
+ await memory.add({ role: 'user', content: 'Tell me about Paris' });
708
+ await memory.add({ role: 'assistant', content: 'Paris is the capital of France...' });
709
+
710
+ // Get context includes summary
711
+ const context = await memory.getContext();
712
+ console.log(context.summary); // "User asked about Paris. Assistant explained..."
713
+ console.log(context.messages); // Recent messages after summary
714
+ ```
715
+
716
+ ### SummaryBufferMemory
717
+
718
+ Combines buffer memory with automatic summarization:
719
+
720
+ ```typescript
721
+ import { createMemory } from 'binario';
722
+
723
+ const memory = createMemory({
724
+ type: 'summary-buffer',
725
+ options: {
726
+ maxMessages: 10, // Keep 10 recent messages
727
+ summarizeThreshold: 20, // Summarize when total exceeds 20
728
+ summaryMaxTokens: 500,
729
+ },
730
+ });
731
+
732
+ // Best of both worlds
733
+ const context = await memory.getContext();
734
+ console.log(context.summary); // Summarized older context
735
+ console.log(context.messages); // Recent 10 messages
736
+ ```
737
+
738
+ ### VectorMemory
739
+
740
+ Semantic retrieval for relevant context:
741
+
742
+ ```typescript
743
+ import { createMemory } from 'binario';
744
+
745
+ const memory = createMemory({
746
+ type: 'vector',
747
+ options: {
748
+ topK: 5, // Retrieve top 5 relevant messages
749
+ minScore: 0.7, // Minimum similarity threshold
750
+ embeddings: embeddingsProvider, // Your embeddings provider
751
+ },
752
+ });
753
+
754
+ // Add messages (embeddings generated automatically)
755
+ await memory.add({ role: 'user', content: 'How do I deploy to Cloudflare?' });
756
+ await memory.add({ role: 'assistant', content: 'Use wrangler deploy command...' });
757
+
758
+ // Search retrieves semantically relevant messages
759
+ const results = await memory.search('cloudflare deployment');
760
+ // Returns messages about deployment, even if exact words don't match
761
+ ```
762
+
763
+ ### Storage Backends
764
+
765
+ Memory supports multiple storage backends:
766
+
767
+ ```typescript
768
+ import {
769
+ createMemory,
770
+ InMemoryStore,
771
+ LocalStorageStore,
772
+ CloudflareKVStore
773
+ } from 'binario';
774
+
775
+ // In-Memory (default, development)
776
+ const memoryDev = createMemory({
777
+ type: 'buffer',
778
+ store: new InMemoryStore(),
779
+ });
780
+
781
+ // LocalStorage (browser persistence)
782
+ const memoryBrowser = createMemory({
783
+ type: 'buffer',
784
+ store: new LocalStorageStore('my-chat-'),
785
+ });
786
+
787
+ // Cloudflare KV (production, distributed)
788
+ const memoryProd = createMemory({
789
+ type: 'buffer',
790
+ store: new CloudflareKVStore(env.CHAT_KV),
791
+ });
792
+ ```
793
+
794
+ ## 🔍 Embeddings API
795
+
796
+ Generate text embeddings for semantic search, similarity, and RAG applications.
797
+
798
+ ### CloudflareEmbeddings
799
+
800
+ Use Cloudflare Workers AI for embeddings:
801
+
802
+ ```typescript
803
+ import { CloudflareEmbeddings, createCloudflareEmbeddings } from 'binario';
804
+
805
+ // With Workers AI binding (recommended in Workers)
806
+ const embeddings = new CloudflareEmbeddings({
807
+ binding: env.AI,
808
+ model: 'bge-base-en-v1.5',
809
+ });
810
+
811
+ // With REST API (for external use)
812
+ const embeddings = createCloudflareEmbeddings({
813
+ accountId: process.env.CF_ACCOUNT_ID,
814
+ apiKey: process.env.CF_API_KEY,
815
+ model: 'bge-large-en-v1.5',
816
+ });
817
+ ```
818
+
819
+ ### Available Models
820
+
821
+ | Model | Dimensions | Use Case |
822
+ |-------|------------|----------|
823
+ | `bge-small-en-v1.5` | 384 | Fast, lightweight |
824
+ | `bge-base-en-v1.5` | 768 | Balanced (default) |
825
+ | `bge-large-en-v1.5` | 1024 | Highest quality |
826
+
827
+ ### Generate Embeddings
828
+
829
+ ```typescript
830
+ // Single embedding
831
+ const result = await embeddings.embed('Hello, world!');
832
+ console.log(result.embedding); // Float32Array(768)
833
+ console.log(result.model); // 'bge-base-en-v1.5'
834
+
835
+ // Batch embeddings (more efficient)
836
+ const batch = await embeddings.embedMany([
837
+ 'First document',
838
+ 'Second document',
839
+ 'Third document',
840
+ ]);
841
+ console.log(batch.embeddings.length); // 3
842
+ ```
843
+
844
+ ### Similarity Search
845
+
846
+ ```typescript
847
+ // Calculate cosine similarity between two embeddings
848
+ function cosineSimilarity(a: number[], b: number[]): number {
849
+ let dotProduct = 0;
850
+ let normA = 0;
851
+ let normB = 0;
852
+
853
+ for (let i = 0; i < a.length; i++) {
854
+ dotProduct += a[i] * b[i];
855
+ normA += a[i] * a[i];
856
+ normB += b[i] * b[i];
857
+ }
858
+
859
+ return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
860
+ }
861
+
862
+ // Find similar documents
863
+ const query = await embeddings.embed('machine learning');
864
+ const docs = await embeddings.embedMany([
865
+ 'artificial intelligence and neural networks',
866
+ 'cooking recipes for beginners',
867
+ 'deep learning models',
868
+ ]);
869
+
870
+ const similarities = docs.embeddings.map((emb, i) => ({
871
+ index: i,
872
+ score: cosineSimilarity(query.embedding, emb),
873
+ }));
874
+
875
+ similarities.sort((a, b) => b.score - a.score);
876
+ console.log(similarities);
877
+ // [{ index: 2, score: 0.89 }, { index: 0, score: 0.82 }, { index: 1, score: 0.12 }]
878
+ ```
879
+
880
+ ### RAG (Retrieval Augmented Generation)
881
+
882
+ ```typescript
883
+ import { Binario, CloudflareEmbeddings, createMemory } from 'binario';
884
+
885
+ // Setup
886
+ const client = new Binario('bsk_your_api_key');
887
+ const embeddings = new CloudflareEmbeddings({ binding: env.AI });
888
+
889
+ // Create vector memory for documents
890
+ const memory = createMemory({
891
+ type: 'vector',
892
+ options: {
893
+ topK: 3,
894
+ embeddings,
895
+ },
896
+ });
897
+
898
+ // Index your documents
899
+ const documents = [
900
+ 'Binario is an AI SDK for Cloudflare Workers',
901
+ 'It supports multiple AI providers including OpenAI and Anthropic',
902
+ 'The Memory System provides persistent conversation context',
903
+ 'Embeddings can be generated using Cloudflare Workers AI',
904
+ ];
905
+
906
+ for (const doc of documents) {
907
+ await memory.add({ role: 'system', content: doc });
908
+ }
909
+
910
+ // Query with RAG
911
+ async function queryWithRAG(question: string) {
912
+ // Retrieve relevant context
913
+ const results = await memory.search(question);
914
+ const context = results.map(r => r.content).join('\n');
915
+
916
+ // Generate answer with context
917
+ const response = await client.chat([
918
+ { role: 'system', content: `Answer based on this context:\n${context}` },
919
+ { role: 'user', content: question },
920
+ ]);
921
+
922
+ return response.content;
923
+ }
924
+
925
+ const answer = await queryWithRAG('What AI providers does Binario support?');
926
+ // "Binario supports multiple AI providers including OpenAI and Anthropic."
927
+ ```
928
+
929
+ ## 🤖 Agent Framework
930
+
931
+ Create powerful AI agents with tool calling:
932
+
933
+ ```typescript
934
+ import { Binario, defineTool } from 'binario';
935
+ import { z } from 'zod';
936
+
937
+ const client = new Binario('bsk_your_api_key');
938
+
939
+ // Define tools with Zod schemas
940
+ const calculatorTool = defineTool({
941
+ name: 'calculator',
942
+ description: 'Perform mathematical calculations',
943
+ parameters: z.object({
944
+ operation: z.enum(['add', 'subtract', 'multiply', 'divide']),
945
+ a: z.number().describe('First number'),
946
+ b: z.number().describe('Second number'),
947
+ }),
948
+ execute: async ({ operation, a, b }) => {
949
+ switch (operation) {
950
+ case 'add': return { result: a + b };
951
+ case 'subtract': return { result: a - b };
952
+ case 'multiply': return { result: a * b };
953
+ case 'divide': return { result: a / b };
954
+ }
955
+ },
956
+ });
957
+
958
+ const searchTool = defineTool({
959
+ name: 'web_search',
960
+ description: 'Search the web for information',
961
+ parameters: z.object({
962
+ query: z.string().describe('Search query'),
963
+ limit: z.number().optional().default(5),
964
+ }),
965
+ execute: async ({ query, limit }) => {
966
+ // Your search implementation
967
+ return { results: ['Result 1', 'Result 2'] };
968
+ },
969
+ });
970
+
971
+ // Create agent with tools
972
+ const agent = client.agent({
973
+ systemPrompt: 'You are a helpful assistant with access to tools.',
974
+ tools: [calculatorTool, searchTool],
975
+ maxIterations: 10,
976
+ });
977
+
978
+ // Run the agent
979
+ const result = await agent.run('What is 25 * 4, then search for that number');
980
+
981
+ console.log(result.output);
982
+ console.log('Steps taken:', result.steps.length);
983
+ console.log('Tokens used:', result.usage.totalTokens);
984
+ ```
985
+
986
+ ## ☁️ Cloudflare Workers
987
+
988
+ Utilities for building AI-powered Workers:
989
+
990
+ ```typescript
991
+ import {
992
+ runWithTools,
993
+ tool,
994
+ calculateNeurons,
995
+ getRecommendedModel,
996
+ CLOUDFLARE_MODELS,
997
+ } from 'binario/cloudflare';
998
+
999
+ export default {
1000
+ async fetch(request: Request, env: Env): Promise<Response> {
1001
+ // Get recommended model based on task
1002
+ const model = getRecommendedModel('chat', true); // true = prefer free tier
1003
+
1004
+ // Define tools using the simple helper
1005
+ const weatherTool = tool('get_weather', 'Get weather info', {
1006
+ location: { type: 'string', description: 'City name' },
1007
+ });
1008
+
1009
+ // Run with tool support
1010
+ const result = await runWithTools(
1011
+ env.AI,
1012
+ model,
1013
+ [{ role: 'user', content: 'What is the weather in Tokyo?' }],
1014
+ [weatherTool],
1015
+ {
1016
+ onToolCall: async (name, args) => {
1017
+ if (name === 'get_weather') {
1018
+ return { temperature: 18, condition: 'cloudy' };
1019
+ }
1020
+ },
1021
+ }
1022
+ );
1023
+
1024
+ // Calculate neuron usage for billing
1025
+ const neurons = calculateNeurons(model, result.usage);
1026
+
1027
+ return Response.json({
1028
+ response: result.content,
1029
+ model,
1030
+ neurons,
1031
+ });
1032
+ },
1033
+ };
1034
+ ```
1035
+
1036
+ ### Available Cloudflare Models
1037
+
1038
+ ```typescript
1039
+ import { CLOUDFLARE_MODELS, NEURON_COSTS } from 'binario/cloudflare';
1040
+
1041
+ // All available models
1042
+ console.log(CLOUDFLARE_MODELS);
1043
+ // ['@cf/meta/llama-3.3-70b-instruct-fp8-fast', '@cf/meta/llama-3.2-3b-instruct', ...]
1044
+
1045
+ // Check neuron costs
1046
+ console.log(NEURON_COSTS['@cf/meta/llama-3.3-70b-instruct-fp8-fast']);
1047
+ // { input: 0.0001, output: 0.0003 }
1048
+ ```
1049
+
1050
+ ## 📊 Structured Outputs
1051
+
1052
+ Get type-safe structured data from AI:
1053
+
1054
+ ```typescript
1055
+ import { Binario, createSchema, z } from 'binario';
1056
+
1057
+ const client = new Binario('bsk_your_api_key');
1058
+
1059
+ // Define output schema
1060
+ const ProductSchema = createSchema('Product', z.object({
1061
+ name: z.string().describe('Product name'),
1062
+ price: z.number().describe('Price in USD'),
1063
+ category: z.enum(['electronics', 'clothing', 'food']),
1064
+ inStock: z.boolean(),
1065
+ }));
1066
+
1067
+ // Get structured output
1068
+ const product = await client.structured(
1069
+ 'Extract product info: iPhone 15 Pro, $999, electronics, available',
1070
+ ProductSchema
1071
+ );
1072
+
1073
+ console.log(product.name); // "iPhone 15 Pro"
1074
+ console.log(product.price); // 999
1075
+ console.log(product.category); // "electronics"
1076
+ console.log(product.inStock); // true
1077
+ ```
1078
+
1079
+ ## 🔌 Supported Providers
1080
+
1081
+ | Provider | Status | Models | Free Tier |
1082
+ |----------|--------|--------|-----------|
1083
+ | Cloudflare Workers AI | Full | Llama 3.2/3.3, Mistral, Qwen, DeepSeek | ✅ 10K neurons/day |
1084
+ | OpenRouter | ✅ Full | 100+ models | ✅ Free models available |
1085
+ | OpenAI | ✅ Full | GPT-4, GPT-4o, GPT-3.5 | ❌ |
1086
+ | Anthropic | ✅ Full | Claude 3.5, Claude 3 | ❌ |
1087
+ | Google | ✅ Full | Gemini Pro, Gemini Flash | ✅ Free tier |
1088
+ | Mistral | ✅ Full | Mistral Large, Medium, Small | ❌ |
1089
+
1090
+ ## 💰 Pricing
1091
+
1092
+ | Plan | Requests/Month | Tokens/Month | Price |
1093
+ |------|---------------|--------------|-------|
1094
+ | Free | 1,000 | 50,000 | $0 |
1095
+ | Pro | 50,000 | 500,000 | $19/mo |
1096
+ | Team | 200,000 | 2,000,000 | $79/mo |
1097
+ | Enterprise | Unlimited | Unlimited | Custom |
1098
+
1099
+ ## 🔑 Getting Your API Key
1100
+
1101
+ 1. Sign up at [binario.dev](https://binario.dev)
1102
+ 2. Go to Dashboard API Keys
1103
+ 3. Create a new key starting with `bsk_`
1104
+ 4. Use it in your application
1105
+
1106
+ ## 🛠️ Error Handling
1107
+
1108
+ ```typescript
1109
+ import { Binario, BinarioRateLimitError, BinarioPaymentError } from 'binario';
1110
+
1111
+ const client = new Binario('bsk_your_api_key');
1112
+
1113
+ try {
1114
+ const response = await client.chat('Hello');
1115
+ } catch (error) {
1116
+ if (error instanceof BinarioRateLimitError) {
1117
+ console.log('Rate limited. Retry after:', error.retryAfter);
1118
+ } else if (error instanceof BinarioPaymentError) {
1119
+ console.log('Upgrade required:', error.message);
1120
+ } else {
1121
+ throw error;
1122
+ }
1123
+ }
1124
+ ```
1125
+
1126
+ ## 📚 API Reference
1127
+
1128
+ ### Binario Class
1129
+
1130
+ ```typescript
1131
+ new Binario(apiKey: string)
1132
+ new Binario(options: BinarioOptions)
1133
+
1134
+ interface BinarioOptions {
1135
+ apiKey: string;
1136
+ baseUrl?: string; // Custom API endpoint
1137
+ timeout?: number; // Request timeout in ms
1138
+ retries?: number; // Number of retries
1139
+ }
1140
+ ```
1141
+
1142
+ ### Methods
1143
+
1144
+ | Method | Description |
1145
+ |--------|-------------|
1146
+ | `chat(message, options?)` | Send a chat message |
1147
+ | `stream(message, options?)` | Stream a response |
1148
+ | `structured(message, schema)` | Get structured output |
1149
+ | `agent(config)` | Create an agent |
1150
+ | `usage()` | Get usage statistics |
1151
+
1152
+ ## 🧪 Testing
1153
+
1154
+ ```bash
1155
+ # Run tests
1156
+ npm test
1157
+
1158
+ # Run with coverage
1159
+ npm run test:coverage
1160
+
1161
+ # Watch mode
1162
+ npm run test:watch
1163
+ ```
1164
+
1165
+ ## 📄 License
1166
+
1167
+ MIT © Binario Team
1168
+
1169
+ ## 🔗 Links
1170
+
1171
+ - [Documentation](https://binario.dev/docs)
1172
+ - [API Reference](https://binario.dev/docs/api)
1173
+ - [Examples](https://github.com/binario-ai/binario/tree/main/examples)
1174
+ - [Discord Community](https://discord.gg/binario)
1175
+ - [Twitter](https://twitter.com/binario_ai)