@providerprotocol/ai 0.0.34 → 0.0.36

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.
Files changed (136) hide show
  1. package/README.md +546 -3
  2. package/dist/anthropic/index.d.ts +2 -1
  3. package/dist/anthropic/index.js +151 -145
  4. package/dist/anthropic/index.js.map +1 -1
  5. package/dist/cerebras/index.d.ts +392 -0
  6. package/dist/cerebras/index.js +648 -0
  7. package/dist/cerebras/index.js.map +1 -0
  8. package/dist/chunk-2YXFLRQ6.js +49 -0
  9. package/dist/chunk-2YXFLRQ6.js.map +1 -0
  10. package/dist/chunk-4OGB7JZA.js +157 -0
  11. package/dist/chunk-4OGB7JZA.js.map +1 -0
  12. package/dist/chunk-4RX4VQCB.js +31 -0
  13. package/dist/chunk-4RX4VQCB.js.map +1 -0
  14. package/dist/chunk-5IWHCXKN.js +30 -0
  15. package/dist/chunk-5IWHCXKN.js.map +1 -0
  16. package/dist/{chunk-3C7O2RNO.js → chunk-A2IM7PGT.js} +6 -4
  17. package/dist/{chunk-3C7O2RNO.js.map → chunk-A2IM7PGT.js.map} +1 -1
  18. package/dist/{chunk-3D6XGGVG.js → chunk-ARVM24K2.js} +2 -2
  19. package/dist/{chunk-4J6OFUKX.js → chunk-AY55T37A.js} +70 -162
  20. package/dist/chunk-AY55T37A.js.map +1 -0
  21. package/dist/{chunk-ILR2D5PN.js → chunk-BRP5XJ6Q.js} +2 -86
  22. package/dist/chunk-BRP5XJ6Q.js.map +1 -0
  23. package/dist/chunk-C4JP64VW.js +298 -0
  24. package/dist/chunk-C4JP64VW.js.map +1 -0
  25. package/dist/chunk-COS4ON4G.js +111 -0
  26. package/dist/chunk-COS4ON4G.js.map +1 -0
  27. package/dist/chunk-CRP6Y7NF.js +31 -0
  28. package/dist/chunk-CRP6Y7NF.js.map +1 -0
  29. package/dist/chunk-EPB3GQNL.js +118 -0
  30. package/dist/chunk-EPB3GQNL.js.map +1 -0
  31. package/dist/chunk-ETBFOLQN.js +34 -0
  32. package/dist/chunk-ETBFOLQN.js.map +1 -0
  33. package/dist/chunk-I53CI6ZZ.js +142 -0
  34. package/dist/chunk-I53CI6ZZ.js.map +1 -0
  35. package/dist/chunk-IDZOVWP3.js +29 -0
  36. package/dist/chunk-IDZOVWP3.js.map +1 -0
  37. package/dist/chunk-JA3UZALR.js +88 -0
  38. package/dist/chunk-JA3UZALR.js.map +1 -0
  39. package/dist/{chunk-WAKD3OO5.js → chunk-N5DX5JW3.js} +31 -31
  40. package/dist/chunk-N5DX5JW3.js.map +1 -0
  41. package/dist/chunk-OIEWDFQU.js +97 -0
  42. package/dist/chunk-OIEWDFQU.js.map +1 -0
  43. package/dist/{chunk-TOJCZMVU.js → chunk-PMK5LZ5Z.js} +40 -40
  44. package/dist/chunk-PMK5LZ5Z.js.map +1 -0
  45. package/dist/{chunk-6S222DHN.js → chunk-RJGTRQ47.js} +20 -1
  46. package/dist/chunk-RJGTRQ47.js.map +1 -0
  47. package/dist/chunk-UFFJDYCE.js +94 -0
  48. package/dist/chunk-UFFJDYCE.js.map +1 -0
  49. package/dist/chunk-VGKZIGVI.js +222 -0
  50. package/dist/chunk-VGKZIGVI.js.map +1 -0
  51. package/dist/{chunk-KUPF5KHT.js → chunk-Y5H7C5J4.js} +2 -2
  52. package/dist/{embedding-D2BYIehX.d.ts → embedding-BXA72PlJ.d.ts} +1 -1
  53. package/dist/google/index.d.ts +2 -1
  54. package/dist/google/index.js +202 -199
  55. package/dist/google/index.js.map +1 -1
  56. package/dist/groq/index.d.ts +410 -0
  57. package/dist/groq/index.js +649 -0
  58. package/dist/groq/index.js.map +1 -0
  59. package/dist/http/index.d.ts +3 -2
  60. package/dist/http/index.js +5 -4
  61. package/dist/image-stream-CCgwB7ve.d.ts +11 -0
  62. package/dist/index.d.ts +8 -118
  63. package/dist/index.js +520 -769
  64. package/dist/index.js.map +1 -1
  65. package/dist/{llm-BQJZj3cD.d.ts → llm-ByUFPcFH.d.ts} +12 -1632
  66. package/dist/middleware/logging/index.d.ts +76 -0
  67. package/dist/middleware/logging/index.js +74 -0
  68. package/dist/middleware/logging/index.js.map +1 -0
  69. package/dist/middleware/parsed-object/index.d.ts +45 -0
  70. package/dist/middleware/parsed-object/index.js +73 -0
  71. package/dist/middleware/parsed-object/index.js.map +1 -0
  72. package/dist/middleware/pubsub/index.d.ts +97 -0
  73. package/dist/middleware/pubsub/index.js +160 -0
  74. package/dist/middleware/pubsub/index.js.map +1 -0
  75. package/dist/middleware/pubsub/server/express/index.d.ts +66 -0
  76. package/dist/middleware/pubsub/server/express/index.js +11 -0
  77. package/dist/middleware/pubsub/server/express/index.js.map +1 -0
  78. package/dist/middleware/pubsub/server/fastify/index.d.ts +67 -0
  79. package/dist/middleware/pubsub/server/fastify/index.js +11 -0
  80. package/dist/middleware/pubsub/server/fastify/index.js.map +1 -0
  81. package/dist/middleware/pubsub/server/h3/index.d.ts +70 -0
  82. package/dist/middleware/pubsub/server/h3/index.js +11 -0
  83. package/dist/middleware/pubsub/server/h3/index.js.map +1 -0
  84. package/dist/middleware/pubsub/server/index.d.ts +78 -0
  85. package/dist/middleware/pubsub/server/index.js +34 -0
  86. package/dist/middleware/pubsub/server/index.js.map +1 -0
  87. package/dist/middleware/pubsub/server/webapi/index.d.ts +63 -0
  88. package/dist/middleware/pubsub/server/webapi/index.js +11 -0
  89. package/dist/middleware/pubsub/server/webapi/index.js.map +1 -0
  90. package/dist/ollama/index.d.ts +2 -1
  91. package/dist/ollama/index.js +48 -45
  92. package/dist/ollama/index.js.map +1 -1
  93. package/dist/openai/index.d.ts +2 -1
  94. package/dist/openai/index.js +319 -313
  95. package/dist/openai/index.js.map +1 -1
  96. package/dist/openrouter/index.d.ts +2 -1
  97. package/dist/openrouter/index.js +381 -385
  98. package/dist/openrouter/index.js.map +1 -1
  99. package/dist/proxy/index.d.ts +10 -914
  100. package/dist/proxy/index.js +275 -1007
  101. package/dist/proxy/index.js.map +1 -1
  102. package/dist/proxy/server/express/index.d.ts +161 -0
  103. package/dist/proxy/server/express/index.js +24 -0
  104. package/dist/proxy/server/express/index.js.map +1 -0
  105. package/dist/proxy/server/fastify/index.d.ts +162 -0
  106. package/dist/proxy/server/fastify/index.js +24 -0
  107. package/dist/proxy/server/fastify/index.js.map +1 -0
  108. package/dist/proxy/server/h3/index.d.ts +189 -0
  109. package/dist/proxy/server/h3/index.js +28 -0
  110. package/dist/proxy/server/h3/index.js.map +1 -0
  111. package/dist/proxy/server/index.d.ts +151 -0
  112. package/dist/proxy/server/index.js +48 -0
  113. package/dist/proxy/server/index.js.map +1 -0
  114. package/dist/proxy/server/webapi/index.d.ts +278 -0
  115. package/dist/proxy/server/webapi/index.js +32 -0
  116. package/dist/proxy/server/webapi/index.js.map +1 -0
  117. package/dist/responses/index.d.ts +650 -0
  118. package/dist/responses/index.js +930 -0
  119. package/dist/responses/index.js.map +1 -0
  120. package/dist/{retry-8Ch-WWgX.d.ts → retry-BDMo4AVu.d.ts} +1 -1
  121. package/dist/stream-S7nwQRqM.d.ts +1643 -0
  122. package/dist/types-CE4B7pno.d.ts +96 -0
  123. package/dist/utils/index.d.ts +53 -0
  124. package/dist/utils/index.js +7 -0
  125. package/dist/utils/index.js.map +1 -0
  126. package/dist/xai/index.d.ts +2 -1
  127. package/dist/xai/index.js +310 -310
  128. package/dist/xai/index.js.map +1 -1
  129. package/package.json +82 -4
  130. package/dist/chunk-4J6OFUKX.js.map +0 -1
  131. package/dist/chunk-6S222DHN.js.map +0 -1
  132. package/dist/chunk-ILR2D5PN.js.map +0 -1
  133. package/dist/chunk-TOJCZMVU.js.map +0 -1
  134. package/dist/chunk-WAKD3OO5.js.map +0 -1
  135. /package/dist/{chunk-3D6XGGVG.js.map → chunk-ARVM24K2.js.map} +0 -0
  136. /package/dist/{chunk-KUPF5KHT.js.map → chunk-Y5H7C5J4.js.map} +0 -0
package/README.md CHANGED
@@ -26,9 +26,12 @@ console.log(turn.response.text);
26
26
  | Google | `@providerprotocol/ai/google` | ✓ | ✓ | ✓ |
27
27
  | xAI | `@providerprotocol/ai/xai` | ✓ | | ✓ |
28
28
  | Ollama | `@providerprotocol/ai/ollama` | ✓ | ✓ | |
29
- | OpenRouter | `@providerprotocol/ai/openrouter` | ✓ | ✓ | |
29
+ | OpenRouter | `@providerprotocol/ai/openrouter` | ✓ | ✓ | |
30
+ | Groq | `@providerprotocol/ai/groq` | ✓ | | |
31
+ | Cerebras | `@providerprotocol/ai/cerebras` | ✓ | | |
32
+ | OpenResponses | `@providerprotocol/ai/responses` | ✓ | | |
30
33
 
31
- API keys are loaded automatically from environment variables (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, etc.).
34
+ API keys are loaded automatically from environment variables (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GROQ_API_KEY`, `CEREBRAS_API_KEY`, etc.).
32
35
 
33
36
  ## LLM
34
37
 
@@ -44,6 +47,12 @@ for await (const event of stream) {
44
47
  const turn = await stream.turn;
45
48
  ```
46
49
 
50
+ Stream results are PromiseLike, so you can also await the stream directly to auto-drain:
51
+
52
+ ```typescript
53
+ const turn = await claude.stream('Count to 5');
54
+ ```
55
+
47
56
  **Stream Control:**
48
57
 
49
58
  ```typescript
@@ -63,6 +72,7 @@ for await (const event of stream) {
63
72
  |-------|-------------|
64
73
  | `text_delta` | Incremental text output |
65
74
  | `reasoning_delta` | Incremental reasoning/thinking output |
75
+ | `object_delta` | Incremental structured output JSON |
66
76
  | `tool_call_delta` | Tool call arguments being streamed |
67
77
  | `tool_execution_start` | Tool execution has started |
68
78
  | `tool_execution_end` | Tool execution has completed |
@@ -123,12 +133,36 @@ console.log(turn.data); // { name: 'John', age: 30 }
123
133
  ### Multimodal Input
124
134
 
125
135
  ```typescript
126
- import { Image } from '@providerprotocol/ai';
136
+ import { Image, Document, Audio, Video } from '@providerprotocol/ai';
127
137
 
138
+ // Images
128
139
  const img = await Image.fromPath('./photo.png');
129
140
  const turn = await claude.generate([img, 'What is in this image?']);
141
+
142
+ // Documents (PDF, text)
143
+ const doc = await Document.fromPath('./report.pdf', 'Annual Report');
144
+ const docTurn = await claude.generate([doc.toBlock(), 'Summarize this document']);
145
+
146
+ // Audio (Google, OpenRouter)
147
+ const audio = await Audio.fromPath('./recording.mp3');
148
+ const audioTurn = await gemini.generate([audio.toBlock(), 'Transcribe this audio']);
149
+
150
+ // Video (Google, OpenRouter)
151
+ const video = await Video.fromPath('./clip.mp4');
152
+ const videoTurn = await gemini.generate([video.toBlock(), 'Describe this video']);
130
153
  ```
131
154
 
155
+ **Multimodal Support by Provider:**
156
+
157
+ | Provider | Image | Document | Audio | Video |
158
+ |----------|:-----:|:--------:|:-----:|:-----:|
159
+ | Anthropic | ✓ | PDF, Text | | |
160
+ | OpenAI | ✓ | PDF, Text | | |
161
+ | Google | ✓ | PDF, Text | ✓ | ✓ |
162
+ | OpenRouter | ✓ | PDF, Text | ✓ | ✓ |
163
+ | xAI | ✓ | | | |
164
+ | Groq | ✓ | | | |
165
+
132
166
  ## Anthropic Beta Features
133
167
 
134
168
  Anthropic provides beta features through the `betas` export. Enable them at the model level:
@@ -168,21 +202,164 @@ const thinker = llm({
168
202
  | `interleavedThinking` | Claude can think between tool calls |
169
203
  | `devFullThinking` | Developer mode for full thinking visibility |
170
204
  | `effort` | Control response thoroughness vs efficiency (Opus 4.5) |
205
+ | `computerUseLegacy` | Computer use for Claude 3.x models |
171
206
  | `computerUse` | Mouse, keyboard, screenshot control (Claude 4) |
207
+ | `computerUseOpus` | Computer use with extra commands (Opus 4.5) |
172
208
  | `codeExecution` | Python/Bash sandbox execution |
173
209
  | `tokenEfficientTools` | Up to 70% token reduction for tool calls |
174
210
  | `fineGrainedToolStreaming` | Stream tool args without buffering |
211
+ | `maxTokens35Sonnet` | 8,192 output tokens for Claude 3.5 Sonnet |
175
212
  | `output128k` | 128K token output length |
176
213
  | `context1m` | 1 million token context window (Sonnet 4) |
177
214
  | `promptCaching` | Reduced latency and costs via caching |
178
215
  | `extendedCacheTtl` | 1-hour cache TTL (vs 5-minute default) |
216
+ | `contextManagement` | Automatic tool call clearing for context |
217
+ | `modelContextWindowExceeded` | Handle exceeded context windows |
179
218
  | `advancedToolUse` | Tool Search, Programmatic Tool Calling |
180
219
  | `mcpClient` | Connect to remote MCP servers |
220
+ | `mcpClientLatest` | Updated MCP client |
181
221
  | `filesApi` | Upload and manage files |
182
222
  | `pdfs` | PDF document support |
223
+ | `tokenCounting` | Token counting endpoint |
183
224
  | `messageBatches` | Async batch processing at 50% cost |
184
225
  | `skills` | Agent Skills (PowerPoint, Excel, Word, PDF) |
185
226
 
227
+ ## Anthropic Built-in Tools
228
+
229
+ Use Anthropic's built-in tools directly with the `tools` export:
230
+
231
+ ```typescript
232
+ import { anthropic, betas, tools } from '@providerprotocol/ai/anthropic';
233
+ import { llm } from '@providerprotocol/ai';
234
+
235
+ // Web search with optional user location
236
+ const model = llm({
237
+ model: anthropic('claude-sonnet-4-20250514'),
238
+ params: {
239
+ tools: [tools.webSearch({ max_results: 5 })],
240
+ },
241
+ });
242
+
243
+ // Computer use (requires beta)
244
+ const computerModel = llm({
245
+ model: anthropic('claude-sonnet-4-20250514', {
246
+ betas: [betas.computerUse],
247
+ }),
248
+ params: {
249
+ tools: [tools.computer({ display_width: 1920, display_height: 1080, display_number: 1 })],
250
+ },
251
+ });
252
+
253
+ // Code execution (requires beta)
254
+ const codeModel = llm({
255
+ model: anthropic('claude-sonnet-4-20250514', {
256
+ betas: [betas.codeExecution],
257
+ }),
258
+ params: {
259
+ tools: [tools.codeExecution()],
260
+ },
261
+ });
262
+ ```
263
+
264
+ **Available Built-in Tools:**
265
+
266
+ | Tool | Description |
267
+ |------|-------------|
268
+ | `tools.webSearch()` | Search the web with optional max results and location |
269
+ | `tools.computer()` | Mouse, keyboard, and screenshot control |
270
+ | `tools.textEditor()` | Edit text files programmatically |
271
+ | `tools.bash()` | Execute bash commands |
272
+ | `tools.codeExecution()` | Run code in a sandboxed environment |
273
+ | `tools.toolSearch()` | Search through available tools |
274
+
275
+ ## Reasoning / Extended Thinking
276
+
277
+ Access model reasoning and extended thinking across providers with a unified API.
278
+
279
+ ### Anthropic
280
+
281
+ ```typescript
282
+ import { llm } from '@providerprotocol/ai';
283
+ import { anthropic } from '@providerprotocol/ai/anthropic';
284
+
285
+ const claude = llm({
286
+ model: anthropic('claude-sonnet-4-20250514'),
287
+ params: {
288
+ max_tokens: 16000,
289
+ thinking: {
290
+ type: 'enabled',
291
+ budget_tokens: 5000,
292
+ },
293
+ },
294
+ });
295
+
296
+ const turn = await claude.generate('Solve this complex problem...');
297
+ console.log(turn.response.reasoning); // Reasoning blocks
298
+ ```
299
+
300
+ ### OpenAI
301
+
302
+ ```typescript
303
+ import { llm } from '@providerprotocol/ai';
304
+ import { openai } from '@providerprotocol/ai/openai';
305
+
306
+ const gpt = llm({
307
+ model: openai('o3-mini'),
308
+ params: {
309
+ max_output_tokens: 4000,
310
+ reasoning: {
311
+ effort: 'medium',
312
+ summary: 'detailed',
313
+ },
314
+ },
315
+ });
316
+ ```
317
+
318
+ ### Google Gemini
319
+
320
+ ```typescript
321
+ import { llm } from '@providerprotocol/ai';
322
+ import { google } from '@providerprotocol/ai/google';
323
+
324
+ const gemini = llm({
325
+ model: google('gemini-2.5-flash'),
326
+ params: {
327
+ maxOutputTokens: 4000,
328
+ thinkingConfig: {
329
+ thinkingBudget: -1, // Dynamic
330
+ includeThoughts: true,
331
+ },
332
+ },
333
+ });
334
+ ```
335
+
336
+ ### Cerebras
337
+
338
+ ```typescript
339
+ import { llm } from '@providerprotocol/ai';
340
+ import { cerebras } from '@providerprotocol/ai/cerebras';
341
+
342
+ const model = llm({
343
+ model: cerebras('gpt-oss-120b'),
344
+ params: {
345
+ reasoning_effort: 'high',
346
+ reasoning_format: 'parsed',
347
+ },
348
+ });
349
+ ```
350
+
351
+ ### Streaming Reasoning
352
+
353
+ All providers emit `ReasoningDelta` events during streaming:
354
+
355
+ ```typescript
356
+ for await (const event of stream) {
357
+ if (event.type === 'reasoning_delta') {
358
+ process.stdout.write(event.delta.text);
359
+ }
360
+ }
361
+ ```
362
+
186
363
  ## Embeddings
187
364
 
188
365
  ```typescript
@@ -414,6 +591,161 @@ localStorage.setItem('conversation', JSON.stringify(json));
414
591
  const restored = Thread.fromJSON(JSON.parse(localStorage.getItem('conversation')));
415
592
  ```
416
593
 
594
+ ## Middleware
595
+
596
+ Compose request/response/stream transformations with the middleware system. Middleware is imported from dedicated entry points.
597
+
598
+ ### Parsed Object Middleware
599
+
600
+ Automatically parse streaming JSON from structured output and tool call events:
601
+
602
+ ```typescript
603
+ import { llm } from '@providerprotocol/ai';
604
+ import { anthropic } from '@providerprotocol/ai/anthropic';
605
+ import { parsedObjectMiddleware } from '@providerprotocol/ai/middleware/parsed-object';
606
+
607
+ const model = llm({
608
+ model: anthropic('claude-sonnet-4-20250514'),
609
+ structure: {
610
+ type: 'object',
611
+ properties: {
612
+ city: { type: 'string' },
613
+ country: { type: 'string' },
614
+ population: { type: 'number' },
615
+ },
616
+ required: ['city', 'country', 'population'],
617
+ },
618
+ middleware: [parsedObjectMiddleware()],
619
+ });
620
+
621
+ for await (const event of model.stream('What is the capital of France?')) {
622
+ if (event.type === 'object_delta') {
623
+ // Access incrementally parsed structured data
624
+ console.log(event.delta.parsed);
625
+ // { city: "Par" } -> { city: "Paris" } -> { city: "Paris", country: "Fr" } -> ...
626
+ }
627
+ }
628
+ ```
629
+
630
+ ### Logging Middleware
631
+
632
+ Add visibility into request lifecycle:
633
+
634
+ ```typescript
635
+ import { llm } from '@providerprotocol/ai';
636
+ import { anthropic } from '@providerprotocol/ai/anthropic';
637
+ import { loggingMiddleware } from '@providerprotocol/ai/middleware/logging';
638
+
639
+ const model = llm({
640
+ model: anthropic('claude-sonnet-4-20250514'),
641
+ middleware: [loggingMiddleware({ level: 'debug' })],
642
+ });
643
+
644
+ // Logs: [PP] [anthropic] Starting llm request (streaming)
645
+ // Logs: [PP] [anthropic] Completed in 1234ms
646
+ const result = await model.generate('Hello');
647
+ ```
648
+
649
+ ### Pub-Sub Middleware (Stream Resumption)
650
+
651
+ Enable reconnecting clients to catch up on missed events during active generation. The middleware buffers events, publishes them to subscribers, and removes streams on completion/abort/error.
652
+ If a stream never reaches those hooks (for example, a process crash), the adapter may retain the entry. Custom adapters should invoke `onComplete` when `remove()` runs so subscriber streams can terminate.
653
+ Streams are created lazily on first `append()` or `subscribe()` call.
654
+
655
+ ```typescript
656
+ import { llm } from '@providerprotocol/ai';
657
+ import { anthropic } from '@providerprotocol/ai/anthropic';
658
+ import { pubsubMiddleware, memoryAdapter } from '@providerprotocol/ai/middleware/pubsub';
659
+ import { webapi } from '@providerprotocol/ai/middleware/pubsub/server';
660
+
661
+ // Create a shared adapter instance
662
+ const adapter = memoryAdapter({ maxStreams: 1000 });
663
+
664
+ // Server route handling both new requests and reconnections
665
+ Bun.serve({
666
+ port: 3000,
667
+ async fetch(req) {
668
+ const { messages, streamId } = await req.json();
669
+ const exists = await adapter.exists(streamId);
670
+
671
+ if (!exists) {
672
+ // Start background generation (fire and forget)
673
+ // Stream is created lazily on first append()
674
+ const model = llm({
675
+ model: anthropic('claude-sonnet-4-20250514'),
676
+ middleware: [pubsubMiddleware({ adapter, streamId })],
677
+ });
678
+ model.stream(messages).then(turn => { /* save to DB */ });
679
+ }
680
+
681
+ // Both new and reconnect: subscribe to events
682
+ return new Response(webapi.createSubscriberStream(streamId, adapter), {
683
+ headers: { 'Content-Type': 'text/event-stream' },
684
+ });
685
+ },
686
+ });
687
+ ```
688
+
689
+ **Framework Adapters:**
690
+
691
+ ```typescript
692
+ // Express
693
+ import { express } from '@providerprotocol/ai/middleware/pubsub/server';
694
+ app.post('/api/ai/reconnect', (req, res) => {
695
+ const { streamId } = req.body;
696
+ express.streamSubscriber(streamId, adapter, res);
697
+ });
698
+
699
+ // Fastify
700
+ import { fastify } from '@providerprotocol/ai/middleware/pubsub/server';
701
+ app.post('/api/ai/reconnect', (request, reply) => {
702
+ const { streamId } = request.body;
703
+ return fastify.streamSubscriber(streamId, adapter, reply);
704
+ });
705
+
706
+ // H3/Nuxt
707
+ import { h3 } from '@providerprotocol/ai/middleware/pubsub/server';
708
+ export default defineEventHandler(async (event) => {
709
+ const { streamId } = await readBody(event);
710
+ return h3.streamSubscriber(streamId, adapter, event);
711
+ });
712
+ ```
713
+
714
+ **Custom Adapters:**
715
+
716
+ Implement `PubSubAdapter` for custom backends (Redis, etc.):
717
+
718
+ ```typescript
719
+ import type { PubSubAdapter } from '@providerprotocol/ai/middleware/pubsub';
720
+
721
+ const redisAdapter: PubSubAdapter = {
722
+ async exists(streamId) { /* check if stream exists */ },
723
+ async append(streamId, event) { /* append event, create lazily */ },
724
+ async getEvents(streamId) { /* return events or [] */ },
725
+ subscribe(streamId, onEvent, onComplete) { /* subscribe to live events */ },
726
+ publish(streamId, event) { /* broadcast to subscribers */ },
727
+ async remove(streamId) { /* notify onComplete then delete */ },
728
+ };
729
+ ```
730
+
731
+ ### Combining Middleware
732
+
733
+ ```typescript
734
+ import { llm } from '@providerprotocol/ai';
735
+ import { anthropic } from '@providerprotocol/ai/anthropic';
736
+ import { loggingMiddleware } from '@providerprotocol/ai/middleware/logging';
737
+ import { parsedObjectMiddleware } from '@providerprotocol/ai/middleware/parsed-object';
738
+
739
+ const model = llm({
740
+ model: anthropic('claude-sonnet-4-20250514'),
741
+ structure: mySchema,
742
+ middleware: [
743
+ loggingMiddleware({ level: 'info' }),
744
+ parsedObjectMiddleware(),
745
+ ],
746
+ });
747
+ ```
748
+
417
749
  ## Error Handling
418
750
 
419
751
  All errors are normalized to `UPPError` with consistent error codes:
@@ -561,6 +893,74 @@ export default defineEventHandler(async (event) => {
561
893
  - Request/response logging, content filtering
562
894
  - Double-layer retry: client retries to proxy, server retries to AI provider
563
895
 
896
+ ## OpenAI API Modes
897
+
898
+ OpenAI supports two API endpoints. The Responses API is the default and recommended approach:
899
+
900
+ ```typescript
901
+ import { openai } from '@providerprotocol/ai/openai';
902
+
903
+ // Responses API (default, recommended)
904
+ openai('gpt-4o')
905
+
906
+ // Chat Completions API (legacy)
907
+ openai('gpt-4o', { api: 'completions' })
908
+ ```
909
+
910
+ The Responses API supports built-in tools and stateful conversations. Use completions for backward compatibility.
911
+
912
+ ## OpenAI Built-in Tools
913
+
914
+ With the Responses API, use OpenAI's built-in tools directly:
915
+
916
+ ```typescript
917
+ import { llm } from '@providerprotocol/ai';
918
+ import { openai, tools } from '@providerprotocol/ai/openai';
919
+
920
+ // Web search
921
+ const model = llm({
922
+ model: openai('gpt-4o'),
923
+ params: {
924
+ tools: [tools.webSearch()],
925
+ },
926
+ });
927
+
928
+ // File search with vector stores
929
+ const researchModel = llm({
930
+ model: openai('gpt-4o'),
931
+ params: {
932
+ tools: [tools.fileSearch({ vector_store_ids: ['vs_abc123'] })],
933
+ },
934
+ });
935
+
936
+ // Code interpreter
937
+ const codeModel = llm({
938
+ model: openai('gpt-4o'),
939
+ params: {
940
+ tools: [tools.codeInterpreter()],
941
+ },
942
+ });
943
+
944
+ // Image generation
945
+ const creativeModel = llm({
946
+ model: openai('gpt-4o'),
947
+ params: {
948
+ tools: [tools.imageGeneration()],
949
+ },
950
+ });
951
+ ```
952
+
953
+ **Available Built-in Tools:**
954
+
955
+ | Tool | Description |
956
+ |------|-------------|
957
+ | `tools.webSearch()` | Search the web with optional user location |
958
+ | `tools.fileSearch()` | Search uploaded files in vector stores |
959
+ | `tools.codeInterpreter()` | Execute code in a sandboxed environment |
960
+ | `tools.computer()` | Computer use with display configuration |
961
+ | `tools.imageGeneration()` | Generate images via DALL-E |
962
+ | `tools.mcp()` | Connect to MCP servers |
963
+
564
964
  ## xAI API Modes
565
965
 
566
966
  xAI supports multiple API compatibility modes:
@@ -578,6 +978,119 @@ xai('grok-3-fast', { api: 'responses' })
578
978
  xai('grok-3-fast', { api: 'messages' })
579
979
  ```
580
980
 
981
+ ## Groq
982
+
983
+ Fast inference with Llama, Gemma, and Mixtral models:
984
+
985
+ ```typescript
986
+ import { llm } from '@providerprotocol/ai';
987
+ import { groq } from '@providerprotocol/ai/groq';
988
+
989
+ const model = llm({
990
+ model: groq('llama-3.3-70b-versatile'),
991
+ params: { max_tokens: 1000 },
992
+ });
993
+
994
+ const turn = await model.generate('Hello!');
995
+ ```
996
+
997
+ **With web search:**
998
+
999
+ ```typescript
1000
+ const searchModel = llm({
1001
+ model: groq('llama-3.3-70b-versatile'),
1002
+ params: {
1003
+ search_settings: { mode: 'auto' },
1004
+ },
1005
+ });
1006
+ ```
1007
+
1008
+ **With RAG documents:**
1009
+
1010
+ ```typescript
1011
+ const ragModel = llm({
1012
+ model: groq('llama-3.3-70b-versatile'),
1013
+ params: {
1014
+ documents: [
1015
+ { title: 'Doc 1', content: 'Document content here...' },
1016
+ { title: 'Doc 2', content: 'More content...' },
1017
+ ],
1018
+ citation_options: { include: true },
1019
+ },
1020
+ });
1021
+ ```
1022
+
1023
+ **Capabilities:** Streaming, tool calling, structured output, image input (Llama 4 preview), web search, RAG with citations.
1024
+
1025
+ **Environment:** `GROQ_API_KEY`
1026
+
1027
+ ## Cerebras
1028
+
1029
+ Ultra-fast inference with Llama, Qwen, and GPT-OSS models:
1030
+
1031
+ ```typescript
1032
+ import { llm } from '@providerprotocol/ai';
1033
+ import { cerebras } from '@providerprotocol/ai/cerebras';
1034
+
1035
+ const model = llm({
1036
+ model: cerebras('llama-3.3-70b'),
1037
+ params: { max_completion_tokens: 1000 },
1038
+ });
1039
+
1040
+ const turn = await model.generate('Hello!');
1041
+ ```
1042
+
1043
+ **With reasoning (GPT-OSS):**
1044
+
1045
+ ```typescript
1046
+ const model = llm({
1047
+ model: cerebras('gpt-oss-120b'),
1048
+ params: {
1049
+ reasoning_effort: 'high',
1050
+ reasoning_format: 'parsed',
1051
+ },
1052
+ });
1053
+ ```
1054
+
1055
+ **Capabilities:** Streaming, tool calling, structured output, reasoning parameters.
1056
+
1057
+ **Environment:** `CEREBRAS_API_KEY`
1058
+
1059
+ ## OpenResponses Provider
1060
+
1061
+ Connect to any server implementing the [OpenResponses specification](https://www.openresponses.org):
1062
+
1063
+ ```typescript
1064
+ import { llm } from '@providerprotocol/ai';
1065
+ import { responses } from '@providerprotocol/ai/responses';
1066
+
1067
+ // Using with OpenAI
1068
+ const model = llm({
1069
+ model: responses('gpt-5.2', {
1070
+ host: 'https://api.openai.com/v1',
1071
+ apiKeyEnv: 'OPENAI_API_KEY',
1072
+ }),
1073
+ params: { max_output_tokens: 1000 },
1074
+ });
1075
+
1076
+ // Using with OpenRouter
1077
+ const routerModel = llm({
1078
+ model: responses('openai/gpt-4o', {
1079
+ host: 'https://openrouter.ai/api/v1',
1080
+ apiKeyEnv: 'OPENROUTER_API_KEY',
1081
+ }),
1082
+ });
1083
+
1084
+ // Using with self-hosted server
1085
+ const localModel = llm({
1086
+ model: responses('llama-3.3-70b', {
1087
+ host: 'http://localhost:8080/v1',
1088
+ }),
1089
+ });
1090
+ ```
1091
+
1092
+ **Capabilities:** Full multimodal support, streaming, tool calling, structured output, reasoning summaries.
1093
+
581
1094
  ## Alternative Import Style
582
1095
 
583
1096
  Use the `ai` namespace for a grouped import style:
@@ -607,6 +1120,14 @@ import type {
607
1120
  StreamEvent,
608
1121
  StreamResult,
609
1122
 
1123
+ // Content blocks
1124
+ TextBlock,
1125
+ ImageBlock,
1126
+ ReasoningBlock,
1127
+ DocumentBlock,
1128
+ AudioBlock,
1129
+ VideoBlock,
1130
+
610
1131
  // Modality results
611
1132
  EmbeddingResult,
612
1133
  ImageResult,
@@ -620,9 +1141,31 @@ import type {
620
1141
  KeyStrategy,
621
1142
  RetryStrategy,
622
1143
  LLMCapabilities,
1144
+
1145
+ // Middleware
1146
+ Middleware,
1147
+ MiddlewareContext,
1148
+ StreamContext,
623
1149
  } from '@providerprotocol/ai';
624
1150
  ```
625
1151
 
1152
+ **Type-Safe Enums:**
1153
+
1154
+ ```typescript
1155
+ import {
1156
+ StreamEventType,
1157
+ ErrorCode,
1158
+ ContentBlockType,
1159
+ MessageRole,
1160
+ ModalityType,
1161
+ } from '@providerprotocol/ai';
1162
+
1163
+ // Use instead of magic strings
1164
+ if (event.type === StreamEventType.TextDelta) { ... }
1165
+ if (error.code === ErrorCode.RateLimited) { ... }
1166
+ if (block.type === ContentBlockType.Text) { ... }
1167
+ ```
1168
+
626
1169
  ### Custom Providers
627
1170
 
628
1171
  Build custom providers with `createProvider`:
@@ -1,4 +1,5 @@
1
- import { P as Provider } from '../llm-BQJZj3cD.js';
1
+ import { d as Provider } from '../llm-ByUFPcFH.js';
2
+ import '../stream-S7nwQRqM.js';
2
3
 
3
4
  /**
4
5
  * @fileoverview Anthropic API type definitions.