ai-world-sdk 1.5.11 → 1.5.13

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 (156) hide show
  1. package/dist/cli/commands/config-cmd.js +1 -1
  2. package/dist/cli/config.js +3 -2
  3. package/dist/config.d.ts +3 -3
  4. package/dist/config.js +11 -5
  5. package/dist/llm.js +3 -3
  6. package/dist/vite-plugin.js +3 -1
  7. package/package.json +3 -2
  8. package/skills/ai-world-sdk/SKILL.md +1 -0
  9. package/skills/ai-world-sdk/docs/cli-usage.md +7 -4
  10. package/pacakges/ai-sdk-provider/.changeset/README.md +0 -34
  11. package/pacakges/ai-sdk-provider/.changeset/config.json +0 -13
  12. package/pacakges/ai-sdk-provider/.github/PULL_REQUEST_TEMPLATE.md +0 -16
  13. package/pacakges/ai-sdk-provider/.github/workflows/ci.yaml +0 -24
  14. package/pacakges/ai-sdk-provider/.github/workflows/publish-manual.yaml +0 -36
  15. package/pacakges/ai-sdk-provider/.github/workflows/publish.yaml +0 -107
  16. package/pacakges/ai-sdk-provider/.vscode/settings.json +0 -32
  17. package/pacakges/ai-sdk-provider/CHANGELOG.md +0 -631
  18. package/pacakges/ai-sdk-provider/CLAUDE.md +0 -79
  19. package/pacakges/ai-sdk-provider/CONTRIBUTING.md +0 -241
  20. package/pacakges/ai-sdk-provider/LICENSE +0 -201
  21. package/pacakges/ai-sdk-provider/README.md +0 -426
  22. package/pacakges/ai-sdk-provider/biome.json +0 -122
  23. package/pacakges/ai-sdk-provider/e2e/cache-control.test.ts +0 -74
  24. package/pacakges/ai-sdk-provider/e2e/embeddings/index.test.ts +0 -128
  25. package/pacakges/ai-sdk-provider/e2e/fixtures/pdfs/generate-pdfs.sh +0 -181
  26. package/pacakges/ai-sdk-provider/e2e/fixtures/pdfs/large.json +0 -7
  27. package/pacakges/ai-sdk-provider/e2e/fixtures/pdfs/large.pdf +41 -12894
  28. package/pacakges/ai-sdk-provider/e2e/gemini/reasoning-multiturn.test.ts +0 -221
  29. package/pacakges/ai-sdk-provider/e2e/issues/issue-160-toolcallid-uniqueness.test.ts +0 -88
  30. package/pacakges/ai-sdk-provider/e2e/issues/issue-166-finish-reason-null.test.ts +0 -129
  31. package/pacakges/ai-sdk-provider/e2e/issues/issue-171-cache-tool-key-ordering.test.ts +0 -70
  32. package/pacakges/ai-sdk-provider/e2e/issues/issue-181-tool-response-image.test.ts +0 -199
  33. package/pacakges/ai-sdk-provider/e2e/issues/issue-190-streamobject-flush-error.test.ts +0 -114
  34. package/pacakges/ai-sdk-provider/e2e/issues/issue-194-grok-invalid-json.test.ts +0 -93
  35. package/pacakges/ai-sdk-provider/e2e/issues/issue-196-anthropic-1h-cache-ttl.test.ts +0 -85
  36. package/pacakges/ai-sdk-provider/e2e/issues/issue-199-openai-pdf-processing.test.ts +0 -102
  37. package/pacakges/ai-sdk-provider/e2e/issues/issue-212-anthropic-web-search-online.test.ts +0 -128
  38. package/pacakges/ai-sdk-provider/e2e/issues/issue-234-prompt-caching.test.ts +0 -201
  39. package/pacakges/ai-sdk-provider/e2e/issues/issue-237-reasoning-linebreaks.test.ts +0 -103
  40. package/pacakges/ai-sdk-provider/e2e/issues/issue-248-gemini-web-search-empty-response.test.ts +0 -210
  41. package/pacakges/ai-sdk-provider/e2e/issues/issue-269-image-size-parameter.test.ts +0 -208
  42. package/pacakges/ai-sdk-provider/e2e/issues/issue-287-tool-calls-missing-arguments.test.ts +0 -87
  43. package/pacakges/ai-sdk-provider/e2e/issues/issue-341-cache-control-last-text-part.test.ts +0 -138
  44. package/pacakges/ai-sdk-provider/e2e/issues/issue-383-video-url-support.test.ts +0 -120
  45. package/pacakges/ai-sdk-provider/e2e/issues/issue-386-image-files-parameter.test.ts +0 -109
  46. package/pacakges/ai-sdk-provider/e2e/issues/issue-387-temperature-settings.test.ts +0 -113
  47. package/pacakges/ai-sdk-provider/e2e/issues/issue-389-system-cache-control.test.ts +0 -107
  48. package/pacakges/ai-sdk-provider/e2e/issues/issue-391-reasoning-effort-values.test.ts +0 -121
  49. package/pacakges/ai-sdk-provider/e2e/issues/issue-392-auto-router-plugin.test.ts +0 -84
  50. package/pacakges/ai-sdk-provider/e2e/issues/issue-394-reasoning-end-signature.test.ts +0 -157
  51. package/pacakges/ai-sdk-provider/e2e/issues/issue-407-token-usage-details.test.ts +0 -141
  52. package/pacakges/ai-sdk-provider/e2e/issues/issue-411-output-object-tools-conflict.test.ts +0 -75
  53. package/pacakges/ai-sdk-provider/e2e/issues/issue-412-mid-stream-termination.test.ts +0 -217
  54. package/pacakges/ai-sdk-provider/e2e/issues/issue-413-reasoning-metadata-bloat.test.ts +0 -292
  55. package/pacakges/ai-sdk-provider/e2e/issues/issue-413-tool-input-end-streaming.test.ts +0 -167
  56. package/pacakges/ai-sdk-provider/e2e/issues/issue-418-gemini-thought-signature.test.ts +0 -171
  57. package/pacakges/ai-sdk-provider/e2e/issues/issue-419-420-finish-reason-usage-fallback.test.ts +0 -87
  58. package/pacakges/ai-sdk-provider/e2e/issues/issue-419-usage-fallback.test.ts +0 -106
  59. package/pacakges/ai-sdk-provider/e2e/issues/issue-422-incomplete-error-information.test.ts +0 -46
  60. package/pacakges/ai-sdk-provider/e2e/issues/issue-423-signature-stripped.test.ts +0 -165
  61. package/pacakges/ai-sdk-provider/e2e/issues/issue-423-streaming-signature-loss.test.ts +0 -161
  62. package/pacakges/ai-sdk-provider/e2e/issues/issue-423-uimessage-roundtrip.test.ts +0 -111
  63. package/pacakges/ai-sdk-provider/e2e/issues/issue-424-anthropic-auto-cache.test.ts +0 -66
  64. package/pacakges/ai-sdk-provider/e2e/issues/issue-432-raw-response-body.test.ts +0 -52
  65. package/pacakges/ai-sdk-provider/e2e/issues/issue-438-gemini-reasoning-redacted.test.ts +0 -120
  66. package/pacakges/ai-sdk-provider/e2e/issues/issue-439-exact-payload.test.ts +0 -108
  67. package/pacakges/ai-sdk-provider/e2e/issues/issue-443-eager-input-streaming.test.ts +0 -204
  68. package/pacakges/ai-sdk-provider/e2e/issues/issue-453-signature-reopen.test.ts +0 -203
  69. package/pacakges/ai-sdk-provider/e2e/issues/issue-474-web-search-server-tool.test.ts +0 -102
  70. package/pacakges/ai-sdk-provider/e2e/issues/issue-483-response-format-strict-option.test.ts +0 -199
  71. package/pacakges/ai-sdk-provider/e2e/issues/issue-484-image-url-query-params.test.ts +0 -165
  72. package/pacakges/ai-sdk-provider/e2e/issues/issue-63-web-search-annotations.test.ts +0 -159
  73. package/pacakges/ai-sdk-provider/e2e/parallel-tool-calls.test.ts +0 -425
  74. package/pacakges/ai-sdk-provider/e2e/pdf-blob/index.test.ts +0 -139
  75. package/pacakges/ai-sdk-provider/e2e/pdf-url/index.test.ts +0 -60
  76. package/pacakges/ai-sdk-provider/e2e/reasoning-effort.test.ts +0 -139
  77. package/pacakges/ai-sdk-provider/e2e/reasoning-multiturn/index.test.ts +0 -69
  78. package/pacakges/ai-sdk-provider/e2e/tools-with-reasoning.test.ts +0 -76
  79. package/pacakges/ai-sdk-provider/e2e/tools.ts +0 -61
  80. package/pacakges/ai-sdk-provider/e2e/usage-accounting.test.ts +0 -55
  81. package/pacakges/ai-sdk-provider/e2e/utils.ts +0 -15
  82. package/pacakges/ai-sdk-provider/e2e/video-generation.test.ts +0 -43
  83. package/pacakges/ai-sdk-provider/e2e/web-search/index.test.ts +0 -50
  84. package/pacakges/ai-sdk-provider/example.env.e2e +0 -3
  85. package/pacakges/ai-sdk-provider/pnpm-lock.yaml +0 -3075
  86. package/pacakges/ai-sdk-provider/pnpm-workspace.yaml +0 -6
  87. package/pacakges/ai-sdk-provider/src/chat/convert-to-openrouter-chat-messages.test.ts +0 -3079
  88. package/pacakges/ai-sdk-provider/src/chat/convert-to-openrouter-chat-messages.ts +0 -618
  89. package/pacakges/ai-sdk-provider/src/chat/errors.test.ts +0 -97
  90. package/pacakges/ai-sdk-provider/src/chat/file-parser-schema.test.ts +0 -112
  91. package/pacakges/ai-sdk-provider/src/chat/file-url-utils.ts +0 -167
  92. package/pacakges/ai-sdk-provider/src/chat/get-tool-choice.ts +0 -42
  93. package/pacakges/ai-sdk-provider/src/chat/index.test.ts +0 -6093
  94. package/pacakges/ai-sdk-provider/src/chat/index.ts +0 -1300
  95. package/pacakges/ai-sdk-provider/src/chat/is-url.ts +0 -15
  96. package/pacakges/ai-sdk-provider/src/chat/large-pdf-response.test.ts +0 -108
  97. package/pacakges/ai-sdk-provider/src/chat/payload-comparison.test.ts +0 -154
  98. package/pacakges/ai-sdk-provider/src/chat/schemas.ts +0 -288
  99. package/pacakges/ai-sdk-provider/src/chat/signature-roundtrip.test.ts +0 -777
  100. package/pacakges/ai-sdk-provider/src/completion/convert-to-openrouter-completion-prompt.ts +0 -150
  101. package/pacakges/ai-sdk-provider/src/completion/index.test.ts +0 -958
  102. package/pacakges/ai-sdk-provider/src/completion/index.ts +0 -441
  103. package/pacakges/ai-sdk-provider/src/completion/schemas.ts +0 -67
  104. package/pacakges/ai-sdk-provider/src/embedding/index.test.ts +0 -262
  105. package/pacakges/ai-sdk-provider/src/embedding/index.ts +0 -113
  106. package/pacakges/ai-sdk-provider/src/embedding/schemas.ts +0 -26
  107. package/pacakges/ai-sdk-provider/src/facade.ts +0 -131
  108. package/pacakges/ai-sdk-provider/src/image/index.test.ts +0 -769
  109. package/pacakges/ai-sdk-provider/src/image/index.ts +0 -206
  110. package/pacakges/ai-sdk-provider/src/image/schemas.ts +0 -48
  111. package/pacakges/ai-sdk-provider/src/index.ts +0 -3
  112. package/pacakges/ai-sdk-provider/src/internal/index.ts +0 -10
  113. package/pacakges/ai-sdk-provider/src/provider.ts +0 -327
  114. package/pacakges/ai-sdk-provider/src/schemas/error-response.test.ts +0 -171
  115. package/pacakges/ai-sdk-provider/src/schemas/error-response.ts +0 -105
  116. package/pacakges/ai-sdk-provider/src/schemas/format.ts +0 -12
  117. package/pacakges/ai-sdk-provider/src/schemas/image.ts +0 -23
  118. package/pacakges/ai-sdk-provider/src/schemas/provider-metadata.ts +0 -91
  119. package/pacakges/ai-sdk-provider/src/schemas/reasoning-details.ts +0 -92
  120. package/pacakges/ai-sdk-provider/src/tests/provider-options.test.ts +0 -234
  121. package/pacakges/ai-sdk-provider/src/tests/stream-usage-accounting.test.ts +0 -409
  122. package/pacakges/ai-sdk-provider/src/tests/usage-accounting.test.ts +0 -555
  123. package/pacakges/ai-sdk-provider/src/tests/web-search-tool.test.ts +0 -319
  124. package/pacakges/ai-sdk-provider/src/tool/web-search.ts +0 -52
  125. package/pacakges/ai-sdk-provider/src/types/index.ts +0 -114
  126. package/pacakges/ai-sdk-provider/src/types/openrouter-api-types.ts +0 -83
  127. package/pacakges/ai-sdk-provider/src/types/openrouter-chat-completions-input.ts +0 -116
  128. package/pacakges/ai-sdk-provider/src/types/openrouter-chat-settings.ts +0 -233
  129. package/pacakges/ai-sdk-provider/src/types/openrouter-completion-settings.ts +0 -39
  130. package/pacakges/ai-sdk-provider/src/types/openrouter-embedding-settings.ts +0 -56
  131. package/pacakges/ai-sdk-provider/src/types/openrouter-image-settings.ts +0 -49
  132. package/pacakges/ai-sdk-provider/src/types/openrouter-video-settings.ts +0 -26
  133. package/pacakges/ai-sdk-provider/src/utils/compute-token-usage.test.ts +0 -186
  134. package/pacakges/ai-sdk-provider/src/utils/compute-token-usage.ts +0 -55
  135. package/pacakges/ai-sdk-provider/src/utils/deterministic-stringify.test.ts +0 -87
  136. package/pacakges/ai-sdk-provider/src/utils/deterministic-stringify.ts +0 -35
  137. package/pacakges/ai-sdk-provider/src/utils/map-finish-reason.ts +0 -43
  138. package/pacakges/ai-sdk-provider/src/utils/reasoning-details-duplicate-tracker.test.ts +0 -324
  139. package/pacakges/ai-sdk-provider/src/utils/reasoning-details-duplicate-tracker.ts +0 -70
  140. package/pacakges/ai-sdk-provider/src/utils/remove-undefined.ts +0 -12
  141. package/pacakges/ai-sdk-provider/src/utils/type-guards.ts +0 -6
  142. package/pacakges/ai-sdk-provider/src/utils/with-stream-error-handling.test.ts +0 -119
  143. package/pacakges/ai-sdk-provider/src/utils/with-stream-error-handling.ts +0 -25
  144. package/pacakges/ai-sdk-provider/src/utils/with-user-agent-suffix.test.ts +0 -133
  145. package/pacakges/ai-sdk-provider/src/utils/with-user-agent-suffix.ts +0 -78
  146. package/pacakges/ai-sdk-provider/src/version.ts +0 -4
  147. package/pacakges/ai-sdk-provider/src/video/index.test.ts +0 -515
  148. package/pacakges/ai-sdk-provider/src/video/index.ts +0 -275
  149. package/pacakges/ai-sdk-provider/src/video/schemas.ts +0 -36
  150. package/pacakges/ai-sdk-provider/tsconfig.json +0 -42
  151. package/pacakges/ai-sdk-provider/tsup.config.ts +0 -28
  152. package/pacakges/ai-sdk-provider/turbo.json +0 -8
  153. package/pacakges/ai-sdk-provider/vitest.e2e.config.ts +0 -21
  154. package/pacakges/ai-sdk-provider/vitest.edge.config.ts +0 -16
  155. package/pacakges/ai-sdk-provider/vitest.issues.config.ts +0 -28
  156. package/pacakges/ai-sdk-provider/vitest.node.config.ts +0 -16
@@ -1,426 +0,0 @@
1
- # OpenRouter Provider for Vercel AI SDK
2
-
3
- The [OpenRouter](https://openrouter.ai/) provider for the [Vercel AI SDK](https://sdk.vercel.ai/docs) gives access to over 300 large language models on the OpenRouter chat and completion APIs.
4
-
5
- ## Setup for AI SDK v6
6
-
7
- ```bash
8
- # For pnpm
9
- pnpm add @openrouter/ai-sdk-provider
10
-
11
- # For npm
12
- npm install @openrouter/ai-sdk-provider
13
-
14
- # For yarn
15
- yarn add @openrouter/ai-sdk-provider
16
- ```
17
-
18
- ## (LEGACY) Setup for AI SDK v5
19
-
20
- ```bash
21
- # For pnpm
22
- pnpm add @openrouter/ai-sdk-provider@1.5.4
23
-
24
- # For npm
25
- npm install @openrouter/ai-sdk-provider@1.5.4
26
-
27
- # For yarn
28
- yarn add @openrouter/ai-sdk-provider@1.5.4
29
- ```
30
-
31
- ## Provider Instance
32
-
33
- You can import the default provider instance `openrouter` from `@openrouter/ai-sdk-provider`:
34
-
35
- ```ts
36
- import { openrouter } from '@openrouter/ai-sdk-provider';
37
- ```
38
-
39
- ## Example
40
-
41
- ```ts
42
- import { openrouter } from '@openrouter/ai-sdk-provider';
43
- import { generateText } from 'ai';
44
-
45
- const { text } = await generateText({
46
- model: openrouter('openai/gpt-4o'),
47
- prompt: 'Write a vegetarian lasagna recipe for 4 people.',
48
- });
49
- ```
50
-
51
- ## Supported models
52
-
53
- This list is not a definitive list of models supported by OpenRouter, as it constantly changes as we add new models (and deprecate old ones) to our system. You can find the latest list of models supported by OpenRouter [here](https://openrouter.ai/models).
54
-
55
- You can find the latest list of tool-supported models supported by OpenRouter [here](https://openrouter.ai/models?order=newest&supported_parameters=tools). (Note: This list may contain models that are not compatible with the AI SDK.)
56
-
57
- ## Embeddings
58
-
59
- OpenRouter supports embedding models for semantic search, RAG pipelines, and vector-native features.
60
-
61
- ### Basic Usage
62
-
63
- ```ts
64
- import { embed } from 'ai';
65
- import { openrouter } from '@openrouter/ai-sdk-provider';
66
-
67
- const { embedding } = await embed({
68
- model: openrouter.textEmbeddingModel('openai/text-embedding-3-small'),
69
- value: 'sunny day at the beach',
70
- });
71
-
72
- console.log(embedding); // Array of numbers representing the embedding
73
- ```
74
-
75
- ### Batch Embeddings
76
-
77
- ```ts
78
- import { embedMany } from 'ai';
79
- import { openrouter } from '@openrouter/ai-sdk-provider';
80
-
81
- const { embeddings } = await embedMany({
82
- model: openrouter.textEmbeddingModel('openai/text-embedding-3-small'),
83
- values: [
84
- 'sunny day at the beach',
85
- 'rainy day in the city',
86
- 'snowy mountain peak',
87
- ],
88
- });
89
-
90
- console.log(embeddings); // Array of embedding arrays
91
- ```
92
-
93
- ### Supported Embedding Models
94
-
95
- OpenRouter supports various embedding models including:
96
- - `openai/text-embedding-3-small`
97
- - `openai/text-embedding-3-large`
98
- - `openai/text-embedding-ada-002`
99
- - And more available on [OpenRouter](https://openrouter.ai/models?output_modalities=embeddings)
100
-
101
- ## Passing Extra Body to OpenRouter
102
-
103
- There are 3 ways to pass extra body to OpenRouter:
104
-
105
- 1. Via the `providerOptions.openrouter` property:
106
-
107
- ```typescript
108
- import { createOpenRouter } from '@openrouter/ai-sdk-provider';
109
- import { streamText } from 'ai';
110
-
111
- const openrouter = createOpenRouter({ apiKey: 'your-api-key' });
112
- const model = openrouter('anthropic/claude-3.7-sonnet:thinking');
113
- await streamText({
114
- model,
115
- messages: [{ role: 'user', content: 'Hello' }],
116
- providerOptions: {
117
- openrouter: {
118
- reasoning: {
119
- max_tokens: 10,
120
- },
121
- },
122
- },
123
- });
124
- ```
125
-
126
- 2. Via the `extraBody` property in the model settings:
127
-
128
- ```typescript
129
- import { createOpenRouter } from '@openrouter/ai-sdk-provider';
130
- import { streamText } from 'ai';
131
-
132
- const openrouter = createOpenRouter({ apiKey: 'your-api-key' });
133
- const model = openrouter('anthropic/claude-3.7-sonnet:thinking', {
134
- extraBody: {
135
- reasoning: {
136
- max_tokens: 10,
137
- },
138
- },
139
- });
140
- await streamText({
141
- model,
142
- messages: [{ role: 'user', content: 'Hello' }],
143
- });
144
- ```
145
-
146
- 3. Via the `extraBody` property in the model factory.
147
-
148
- ```typescript
149
- import { createOpenRouter } from '@openrouter/ai-sdk-provider';
150
- import { streamText } from 'ai';
151
-
152
- const openrouter = createOpenRouter({
153
- apiKey: 'your-api-key',
154
- extraBody: {
155
- reasoning: {
156
- max_tokens: 10,
157
- },
158
- },
159
- });
160
- const model = openrouter('anthropic/claude-3.7-sonnet:thinking');
161
- await streamText({
162
- model,
163
- messages: [{ role: 'user', content: 'Hello' }],
164
- });
165
- ```
166
-
167
- ## Anthropic Prompt Caching
168
-
169
- You can include Anthropic-specific options directly in your messages when using functions like `streamText`. The OpenRouter provider will automatically convert these messages to the correct format internally.
170
-
171
- ### Basic Usage
172
-
173
- ```typescript
174
- import { createOpenRouter } from '@openrouter/ai-sdk-provider';
175
- import { streamText } from 'ai';
176
-
177
- const openrouter = createOpenRouter({ apiKey: 'your-api-key' });
178
- const model = openrouter('anthropic/<supported-caching-model>');
179
-
180
- await streamText({
181
- model,
182
- messages: [
183
- {
184
- role: 'system',
185
- content:
186
- 'You are a podcast summary assistant. You are detail-oriented and critical about the content.',
187
- },
188
- {
189
- role: 'user',
190
- content: [
191
- {
192
- type: 'text',
193
- text: 'Given the text body below:',
194
- },
195
- {
196
- type: 'text',
197
- text: `<LARGE BODY OF TEXT>`,
198
- providerOptions: {
199
- openrouter: {
200
- cacheControl: { type: 'ephemeral' },
201
- },
202
- },
203
- },
204
- {
205
- type: 'text',
206
- text: 'List the speakers?',
207
- },
208
- ],
209
- },
210
- ],
211
- });
212
- ```
213
-
214
- ## Anthropic Beta Features
215
-
216
- You can enable Anthropic beta features by passing custom headers through the OpenRouter SDK.
217
-
218
- ### Fine-grained Tool Streaming
219
-
220
- [Fine-grained tool streaming](https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/fine-grained-tool-streaming) allows streaming tool parameters without buffering, reducing latency for large schemas. This is particularly useful when working with large nested JSON structures.
221
-
222
- **Important:** This is a beta feature from Anthropic. Make sure to evaluate responses before using in production.
223
-
224
- #### Basic Usage
225
-
226
- ```typescript
227
- import { createOpenRouter } from '@openrouter/ai-sdk-provider';
228
- import { streamObject } from 'ai';
229
-
230
- const provider = createOpenRouter({
231
- apiKey: process.env.OPENROUTER_API_KEY,
232
- headers: {
233
- 'anthropic-beta': 'fine-grained-tool-streaming-2025-05-14',
234
- },
235
- });
236
-
237
- const model = provider.chat('anthropic/claude-sonnet-4');
238
-
239
- const result = await streamObject({
240
- model,
241
- schema: yourLargeSchema,
242
- prompt: 'Generate a complex object...',
243
- });
244
-
245
- for await (const partialObject of result.partialObjectStream) {
246
- console.log(partialObject);
247
- }
248
- ```
249
-
250
- You can also pass the header at the request level:
251
-
252
- ```typescript
253
- import { createOpenRouter } from '@openrouter/ai-sdk-provider';
254
- import { generateText } from 'ai';
255
-
256
- const provider = createOpenRouter({
257
- apiKey: process.env.OPENROUTER_API_KEY,
258
- });
259
-
260
- const model = provider.chat('anthropic/claude-sonnet-4');
261
-
262
- await generateText({
263
- model,
264
- prompt: 'Hello',
265
- headers: {
266
- 'anthropic-beta': 'fine-grained-tool-streaming-2025-05-14',
267
- },
268
- });
269
- ```
270
-
271
- **Note:** Fine-grained tool streaming is specific to Anthropic models. When using models from other providers, the header will be ignored.
272
-
273
- #### Use Case: Large Component Generation
274
-
275
- This feature is particularly beneficial when streaming large, nested JSON structures like UI component trees:
276
-
277
- ```typescript
278
- import { createOpenRouter } from '@openrouter/ai-sdk-provider';
279
- import { streamObject } from 'ai';
280
- import { z } from 'zod';
281
-
282
- const componentSchema = z.object({
283
- type: z.string(),
284
- props: z.record(z.any()),
285
- children: z.array(z.lazy(() => componentSchema)).optional(),
286
- });
287
-
288
- const provider = createOpenRouter({
289
- apiKey: process.env.OPENROUTER_API_KEY,
290
- headers: {
291
- 'anthropic-beta': 'fine-grained-tool-streaming-2025-05-14',
292
- },
293
- });
294
-
295
- const model = provider.chat('anthropic/claude-sonnet-4');
296
-
297
- const result = await streamObject({
298
- model,
299
- schema: componentSchema,
300
- prompt: 'Create a responsive dashboard layout',
301
- });
302
-
303
- for await (const partialComponent of result.partialObjectStream) {
304
- console.log('Partial component:', partialComponent);
305
- }
306
- ```
307
-
308
- ## Use Cases
309
-
310
- ### Response Healing for Structured Outputs
311
-
312
- The provider supports the [Response Healing plugin](https://openrouter.ai/docs/guides/features/plugins/response-healing), which automatically validates and repairs malformed JSON responses from AI models. This is particularly useful when using `generateObject` or structured outputs, as it can fix common issues like missing brackets, trailing commas, markdown wrappers, and mixed text.
313
-
314
- ```typescript
315
- import { createOpenRouter } from '@openrouter/ai-sdk-provider';
316
- import { generateObject } from 'ai';
317
- import { z } from 'zod';
318
-
319
- const openrouter = createOpenRouter({ apiKey: 'your-api-key' });
320
- const model = openrouter('openai/gpt-4o', {
321
- plugins: [{ id: 'response-healing' }],
322
- });
323
-
324
- const { object } = await generateObject({
325
- model,
326
- schema: z.object({
327
- name: z.string(),
328
- age: z.number(),
329
- }),
330
- prompt: 'Generate a person with name and age.',
331
- });
332
-
333
- console.log(object); // { name: "John", age: 30 }
334
- ```
335
-
336
- Note that Response Healing only works with non-streaming requests. When the model returns imperfect JSON formatting, the plugin attempts to repair the response so you receive valid, parseable JSON.
337
-
338
- ### Debugging API Requests
339
-
340
- The provider supports a debug mode that echoes back the request body sent to the upstream provider. This is useful for troubleshooting and understanding how your requests are being processed. Note that debug mode only works with streaming requests.
341
-
342
- ```typescript
343
- import { createOpenRouter } from '@openrouter/ai-sdk-provider';
344
- import { streamText } from 'ai';
345
-
346
- const openrouter = createOpenRouter({ apiKey: 'your-api-key' });
347
- const model = openrouter('anthropic/claude-3.5-sonnet', {
348
- debug: {
349
- echo_upstream_body: true,
350
- },
351
- });
352
-
353
- const result = await streamText({
354
- model,
355
- prompt: 'Hello, how are you?',
356
- });
357
-
358
- // The debug data is available in the stream's first chunk
359
- // and in the final response's providerMetadata
360
- for await (const chunk of result.fullStream) {
361
- // Debug chunks have empty choices and contain debug.echo_upstream_body
362
- console.log(chunk);
363
- }
364
- ```
365
-
366
- The debug response will include the request body that was sent to the upstream provider, with sensitive data redacted (user IDs, base64 content, etc.). This helps you understand how OpenRouter transforms your request before sending it to the model provider.
367
-
368
- ### Usage Accounting
369
-
370
- The provider supports [OpenRouter usage accounting](https://openrouter.ai/docs/use-cases/usage-accounting), which allows you to track token usage details directly in your API responses, without making additional API calls.
371
-
372
- ```typescript
373
- // Enable usage accounting
374
- const model = openrouter('openai/gpt-3.5-turbo', {
375
- usage: {
376
- include: true,
377
- },
378
- });
379
-
380
- // Access usage accounting data
381
- const result = await generateText({
382
- model,
383
- prompt: 'Hello, how are you today?',
384
- });
385
-
386
- // Provider-specific usage details (available in providerMetadata)
387
- if (result.providerMetadata?.openrouter?.usage) {
388
- console.log('Cost:', result.providerMetadata.openrouter.usage.cost);
389
- console.log(
390
- 'Total Tokens:',
391
- result.providerMetadata.openrouter.usage.totalTokens,
392
- );
393
- }
394
- ```
395
-
396
- It also supports BYOK (Bring Your Own Key) [usage accounting](https://openrouter.ai/docs/docs/guides/usage-accounting#cost-breakdown), which allows you to track passthrough costs when you are using a provider's own API key in your OpenRouter account.
397
-
398
- ```typescript
399
- // Assuming you have set an OpenAI API key in https://openrouter.ai/settings/integrations
400
-
401
- // Enable usage accounting
402
- const model = openrouter('openai/gpt-3.5-turbo', {
403
- usage: {
404
- include: true,
405
- },
406
- });
407
-
408
- // Access usage accounting data
409
- const result = await generateText({
410
- model,
411
- prompt: 'Hello, how are you today?',
412
- });
413
-
414
- // Provider-specific BYOK usage details (available in providerMetadata)
415
- if (result.providerMetadata?.openrouter?.usage) {
416
- const costDetails = result.providerMetadata.openrouter.usage.costDetails;
417
- if (costDetails) {
418
- console.log('BYOK cost:', costDetails.upstreamInferenceCost);
419
- }
420
- console.log('OpenRouter credits cost:', result.providerMetadata.openrouter.usage.cost);
421
- console.log(
422
- 'Total Tokens:',
423
- result.providerMetadata.openrouter.usage.totalTokens,
424
- );
425
- }
426
- ```
@@ -1,122 +0,0 @@
1
- {
2
- "$schema": "https://biomejs.dev/schemas/2.3.7/schema.json",
3
- "files": {
4
- "ignoreUnknown": true,
5
- "includes": ["**", "!!**/reference"]
6
- },
7
- "vcs": {
8
- "enabled": true,
9
- "clientKind": "git",
10
- "useIgnoreFile": true
11
- },
12
- "assist": {
13
- "actions": {
14
- "source": {
15
- "organizeImports": {
16
- "level": "on",
17
- "options": {
18
- "groups": [
19
- { "type": true },
20
- ":BLANK_LINE:",
21
- { "type": false },
22
- ":BLANK_LINE:",
23
- ":ALIAS:"
24
- ]
25
- }
26
- }
27
- }
28
- }
29
- },
30
- "formatter": {
31
- "enabled": true,
32
- "indentStyle": "space",
33
- "indentWidth": 2,
34
- "lineWidth": 80
35
- },
36
- "linter": {
37
- "enabled": true,
38
- "rules": {
39
- "recommended": true,
40
- "a11y": {
41
- "useSemanticElements": "off"
42
- },
43
- "complexity": {
44
- "useLiteralKeys": "off",
45
- "noExtraBooleanCast": "off",
46
- "noForEach": "off",
47
- "noBannedTypes": "error",
48
- "noUselessSwitchCase": "off"
49
- },
50
- "style": {
51
- "noNonNullAssertion": "off",
52
- "useNodejsImportProtocol": "off",
53
- "useTemplate": "off",
54
- "useBlockStatements": "error",
55
- "noParameterAssign": "error",
56
- "useConst": "error",
57
- "useImportType": {
58
- "level": "on",
59
- "options": {
60
- "style": "separatedType"
61
- }
62
- }
63
- },
64
- "correctness": {
65
- "noUnsafeFinally": "error",
66
- "noUnusedImports": "error",
67
- "useExhaustiveDependencies": "off",
68
- "noUnknownFunction": "off",
69
- "noChildrenProp": "off",
70
- "noInnerDeclarations": "error"
71
- },
72
- "suspicious": {
73
- "noExplicitAny": "error",
74
- "noArrayIndexKey": "off",
75
- "noAssignInExpressions": "error",
76
- "noAsyncPromiseExecutor": "off",
77
- "noFallthroughSwitchClause": "error",
78
- "noConsole": "error",
79
- "noDoubleEquals": {
80
- "level": "error",
81
- "options": {
82
- "ignoreNull": true
83
- }
84
- },
85
- "noExtraNonNullAssertion": "error"
86
- },
87
- "performance": {
88
- "recommended": true,
89
- "noAccumulatingSpread": "error"
90
- },
91
- "security": {
92
- "recommended": true
93
- }
94
- }
95
- },
96
- "overrides": [
97
- {
98
- "includes": ["e2e/**/*.test.ts", "*.test.ts"],
99
- "linter": {
100
- "rules": {
101
- "suspicious": {
102
- "noConsole": "off",
103
- "noExplicitAny": "warn"
104
- }
105
- }
106
- }
107
- }
108
- ],
109
- "javascript": {
110
- "formatter": {
111
- "arrowParentheses": "always",
112
- "jsxQuoteStyle": "single",
113
- "attributePosition": "multiline",
114
- "quoteProperties": "asNeeded",
115
- "trailingCommas": "all",
116
- "semicolons": "always",
117
- "bracketSpacing": true,
118
- "bracketSameLine": false,
119
- "quoteStyle": "single"
120
- }
121
- }
122
- }
@@ -1,74 +0,0 @@
1
- import { streamText } from 'ai';
2
- import { it, vi } from 'vitest';
3
- import { createOpenRouter } from '@/src';
4
-
5
- vi.setConfig({
6
- testTimeout: 42_000,
7
- });
8
-
9
- it('should trigger cache read', async () => {
10
- // First call to warm the cache
11
- await callLLM();
12
- // Second call to test cache read
13
- const response = await callLLM();
14
- const providerMetadata = await response.providerMetadata;
15
- expect(providerMetadata?.openrouter).toMatchObject({
16
- usage: expect.objectContaining({
17
- promptTokens: expect.any(Number),
18
- completionTokens: expect.any(Number),
19
- promptTokensDetails: expect.objectContaining({
20
- cachedTokens: expect.any(Number),
21
- }),
22
- completionTokensDetails: expect.any(Object),
23
- totalTokens: expect.any(Number),
24
- cost: expect.any(Number),
25
- }),
26
- });
27
-
28
- const cachedTokens = Number(
29
- // @ts-expect-error
30
- providerMetadata?.openrouter?.usage?.promptTokensDetails?.cachedTokens,
31
- );
32
-
33
- expect(cachedTokens).toBeGreaterThan(0);
34
- });
35
-
36
- async function callLLM() {
37
- const openrouter = createOpenRouter({
38
- apiKey: process.env.OPENROUTER_API_KEY,
39
- baseUrl: `${process.env.OPENROUTER_API_BASE}/api/v1`,
40
- });
41
- const model = openrouter('anthropic/claude-3.7-sonnet', {
42
- usage: {
43
- include: true,
44
- },
45
- });
46
- const response = streamText({
47
- model,
48
- messages: [
49
- {
50
- role: 'user',
51
- content: [
52
- {
53
- type: 'text',
54
- text: 'a'.repeat(4200),
55
- providerOptions: {
56
- openrouter: {
57
- cache_control: {
58
- type: 'ephemeral',
59
- },
60
- },
61
- },
62
- },
63
- {
64
- type: 'text',
65
- text: 'How many "a" did I use in the previous message?',
66
- },
67
- ],
68
- },
69
- ],
70
- });
71
-
72
- await response.consumeStream();
73
- return response;
74
- }