@anyr/ai-sdk-provider 0.1.4 → 0.1.7

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/dist/index.mjs CHANGED
@@ -1,10 +1,33 @@
1
+ import { NoSuchModelError, APICallError, UnsupportedFunctionalityError } from '@ai-sdk/provider';
1
2
  import { withoutTrailingSlash, parseProviderOptions, postJsonToApi, createJsonResponseHandler, createJsonErrorResponseHandler, combineHeaders, createEventSourceResponseHandler, loadApiKey, generateId } from '@ai-sdk/provider-utils';
2
3
  import { z } from 'zod';
3
- import { NoSuchModelError, UnsupportedFunctionalityError } from '@ai-sdk/provider';
4
4
  import { DEFAULT_BASE_URL, AnyRouter } from '@anyr/sdk';
5
5
 
6
- // src/anyrouter-chat-language-model.ts
7
- function convertToAnyRouterChatMessages(prompt) {
6
+ // src/app-attribution.ts
7
+ var APP_SOURCE = "anyr-ai-sdk-provider";
8
+ var APP_TITLE = "AnyRouter AI SDK Provider";
9
+ var APP_VERSION = "0.1.7";
10
+ var PROVIDER_ATTRIBUTION = {
11
+ source: APP_SOURCE,
12
+ title: APP_TITLE,
13
+ version: APP_VERSION
14
+ };
15
+ function buildAppAttributionHeaders(app) {
16
+ if (!app) return {};
17
+ const headers = {};
18
+ const put = (name, value) => {
19
+ const trimmed = value?.trim();
20
+ if (trimmed) headers[name] = trimmed;
21
+ };
22
+ put("X-AnyRouter-Source", app.source);
23
+ put("X-AnyRouter-Title", app.title);
24
+ put("X-AnyRouter-Version", app.version);
25
+ put("HTTP-Referer", app.url);
26
+ const categories = app.categories?.map((c) => c.trim()).filter(Boolean);
27
+ if (categories?.length) headers["X-AnyRouter-Categories"] = categories.join(",");
28
+ return headers;
29
+ }
30
+ function convertToAnyRouterChatMessages(prompt, fileCache) {
8
31
  const messages = [];
9
32
  for (const message of prompt) {
10
33
  switch (message.role) {
@@ -12,7 +35,7 @@ function convertToAnyRouterChatMessages(prompt) {
12
35
  messages.push({ role: "system", content: message.content });
13
36
  break;
14
37
  case "user":
15
- messages.push(convertUserMessage(message));
38
+ messages.push(convertUserMessage(message, fileCache));
16
39
  break;
17
40
  case "assistant":
18
41
  messages.push(convertAssistantMessage(message));
@@ -32,7 +55,7 @@ function convertToAnyRouterChatMessages(prompt) {
32
55
  }
33
56
  return messages;
34
57
  }
35
- function convertUserMessage(message) {
58
+ function convertUserMessage(message, fileCache) {
36
59
  if (message.content.length === 1 && message.content[0].type === "text") {
37
60
  return { role: "user", content: message.content[0].text };
38
61
  }
@@ -43,7 +66,7 @@ function convertUserMessage(message) {
43
66
  } else if (part.type === "file") {
44
67
  const filePart = part;
45
68
  const mediaType = filePart.mediaType;
46
- const url = toDataUrlOrString(filePart.data, mediaType);
69
+ const url = fileDataToString(filePart, mediaType, fileCache);
47
70
  if (mediaType.startsWith("image/")) {
48
71
  parts.push({ type: "image_url", image_url: { url } });
49
72
  } else {
@@ -123,13 +146,28 @@ function toolResultOutputToString(output) {
123
146
  return JSON.stringify(output);
124
147
  }
125
148
  }
126
- function toDataUrlOrString(data, mediaType) {
127
- if (data instanceof URL) return data.toString();
128
- if (typeof data === "string") {
129
- if (data.startsWith("http") || data.startsWith("data:")) return data;
130
- return `data:${mediaType};base64,${data}`;
149
+ function fileDataToString(filePart, mediaType, fileCache) {
150
+ const d = filePart.data;
151
+ switch (d.type) {
152
+ case "data": {
153
+ if (typeof d.data === "string") {
154
+ if (d.data.startsWith("data:")) return d.data;
155
+ return `data:${mediaType};base64,${d.data}`;
156
+ }
157
+ return `data:${mediaType};base64,${uint8ArrayToBase64(d.data)}`;
158
+ }
159
+ case "url":
160
+ return d.url.toString();
161
+ case "text":
162
+ return `data:${mediaType};base64,${btoa(d.text)}`;
163
+ case "reference": {
164
+ const entry = fileCache?.lookup(d.reference);
165
+ if (entry) return entry.url;
166
+ throw new UnsupportedFunctionalityError({
167
+ functionality: "Unresolved provider file reference \u2014 call provider.files().uploadFile() first to register the file in the session cache"
168
+ });
169
+ }
131
170
  }
132
- return `data:${mediaType};base64,${uint8ArrayToBase64(data)}`;
133
171
  }
134
172
  function uint8ArrayToBase64(bytes) {
135
173
  let binary = "";
@@ -146,7 +184,11 @@ var anyRouterProviderOptionsSchema = z.object({
146
184
  /** Session ID forwarded as `session_id` in the request body. */
147
185
  sessionId: z.string().optional(),
148
186
  /** Extra body fields merged in last (highest precedence). */
149
- extraBody: z.record(z.string(), z.unknown()).optional()
187
+ extraBody: z.record(z.string(), z.unknown()).optional(),
188
+ /** Cache this response for N seconds, forwarded as the `cf-aig-cache-ttl` header. */
189
+ cacheTtl: z.number().optional(),
190
+ /** Skip response caching for this call, forwarded as `cf-aig-skip-cache: true`. */
191
+ skipCache: z.boolean().optional()
150
192
  });
151
193
  var anyRouterErrorSchema = z.object({
152
194
  error: z.object({
@@ -180,7 +222,7 @@ var toolCallDeltaSchema = z.object({
180
222
  var messageSchema = z.object({
181
223
  content: z.string().nullish(),
182
224
  reasoning_content: z.string().nullish(),
183
- tool_calls: z.array(toolCallSchema).optional()
225
+ tool_calls: z.array(toolCallSchema).nullish()
184
226
  });
185
227
  var choiceSchema = z.object({
186
228
  message: messageSchema.optional(),
@@ -190,12 +232,12 @@ var generateResponseSchema = z.object({
190
232
  id: z.string().optional(),
191
233
  model: z.string().optional(),
192
234
  choices: z.array(choiceSchema).optional(),
193
- usage: completionUsageSchema.optional()
235
+ usage: completionUsageSchema.nullish()
194
236
  });
195
237
  var deltaSchema = z.object({
196
238
  content: z.string().nullish(),
197
239
  reasoning_content: z.string().nullish(),
198
- tool_calls: z.array(toolCallDeltaSchema).optional()
240
+ tool_calls: z.array(toolCallDeltaSchema).nullish()
199
241
  });
200
242
  var streamChoiceSchema = z.object({
201
243
  delta: deltaSchema.optional(),
@@ -205,7 +247,10 @@ var streamChunkSchema = z.object({
205
247
  id: z.string().optional(),
206
248
  model: z.string().optional(),
207
249
  choices: z.array(streamChoiceSchema).optional(),
208
- usage: completionUsageSchema.optional()
250
+ usage: completionUsageSchema.nullish(),
251
+ // A mid-stream failure arrives as a `data: {"error":{...}}` frame on a 200
252
+ // response, in the same envelope the gateway uses for non-2xx bodies.
253
+ error: anyRouterErrorSchema.shape.error
209
254
  });
210
255
  function mapFinishReason(raw) {
211
256
  switch (raw) {
@@ -219,6 +264,8 @@ function mapFinishReason(raw) {
219
264
  return { unified: "tool-calls", raw };
220
265
  case "content_filter":
221
266
  return { unified: "content-filter", raw };
267
+ case "error":
268
+ return { unified: "error", raw };
222
269
  default:
223
270
  return { unified: "other", raw: raw ?? void 0 };
224
271
  }
@@ -238,6 +285,11 @@ function buildUsage(raw) {
238
285
  }
239
286
  };
240
287
  }
288
+ function mapReasoningEffort(reasoning) {
289
+ if (!reasoning || reasoning === "provider-default") return void 0;
290
+ if (reasoning === "xhigh") return "high";
291
+ return reasoning;
292
+ }
241
293
  function emitResponseMetadata(chunk, state, fallbackModelId, controller) {
242
294
  if (state.metadataEmitted || !(chunk.id || chunk.model)) return;
243
295
  state.metadataEmitted = true;
@@ -290,7 +342,31 @@ function emitToolCallDeltas(toolCalls, acc, controller) {
290
342
  }
291
343
  }
292
344
  }
293
- function emitFinish(choice, chunk, state, acc, controller) {
345
+ function emitDelta(delta, state, acc, controller) {
346
+ if (typeof delta.reasoning_content === "string" && delta.reasoning_content.length > 0) {
347
+ emitReasoningDelta(delta.reasoning_content, state, controller);
348
+ }
349
+ if (typeof delta.content === "string" && delta.content.length > 0) {
350
+ emitTextDelta(delta.content, state, controller);
351
+ }
352
+ if (delta.tool_calls) {
353
+ emitToolCallDeltas(delta.tool_calls, acc, controller);
354
+ }
355
+ }
356
+ function errorFramePart(chunk, request) {
357
+ return {
358
+ type: "error",
359
+ error: new APICallError({
360
+ message: chunk.error?.message ?? "AnyRouter API error",
361
+ url: request.url,
362
+ requestBodyValues: request.body,
363
+ responseHeaders: request.responseHeaders,
364
+ responseBody: JSON.stringify(chunk),
365
+ data: chunk
366
+ })
367
+ };
368
+ }
369
+ function emitFinish(choice, usage, state, acc, controller) {
294
370
  closeReasoning(state, controller);
295
371
  if (state.activeTextId !== null) {
296
372
  controller.enqueue({ type: "text-end", id: state.activeTextId });
@@ -309,8 +385,8 @@ function emitFinish(choice, chunk, state, acc, controller) {
309
385
  }
310
386
  controller.enqueue({
311
387
  type: "finish",
312
- usage: buildUsage(chunk.usage),
313
- finishReason: mapFinishReason(choice.finish_reason)
388
+ usage: buildUsage(usage),
389
+ finishReason: mapFinishReason(choice?.finish_reason)
314
390
  });
315
391
  }
316
392
  function mapToolChoice(toolChoice) {
@@ -358,14 +434,15 @@ function buildTools(tools) {
358
434
  }));
359
435
  return fns.length > 0 ? fns : void 0;
360
436
  }
361
- function buildRequestBody(modelId, options, settings, stream, perCallOptions) {
362
- const messages = convertToAnyRouterChatMessages(options.prompt);
437
+ function buildRequestBody(modelId, options, settings, stream, perCallOptions, fileCache) {
438
+ const messages = convertToAnyRouterChatMessages(options.prompt, fileCache);
363
439
  const responseFormat = buildResponseFormat(options.responseFormat);
364
440
  const tools = buildTools(options.tools);
365
441
  const toolChoice = mapToolChoice(options.toolChoice);
366
442
  const provider = perCallOptions.provider ?? settings.provider;
367
443
  const sessionId = perCallOptions.sessionId ?? settings.sessionId;
368
444
  const extraBody = { ...settings.extraBody, ...perCallOptions.extraBody };
445
+ const reasoningEffort = mapReasoningEffort(options.reasoning);
369
446
  const body = {
370
447
  model: modelId,
371
448
  messages,
@@ -383,6 +460,7 @@ function buildRequestBody(modelId, options, settings, stream, perCallOptions) {
383
460
  tool_choice: toolChoice,
384
461
  provider: provider ?? void 0,
385
462
  session_id: sessionId ?? void 0,
463
+ reasoning_effort: reasoningEffort,
386
464
  ...extraBody
387
465
  };
388
466
  for (const key of Object.keys(body)) {
@@ -390,8 +468,16 @@ function buildRequestBody(modelId, options, settings, stream, perCallOptions) {
390
468
  }
391
469
  return body;
392
470
  }
471
+ function buildCacheHeaders(settings, perCallOptions) {
472
+ const cacheTtl = perCallOptions.cacheTtl ?? settings.cacheTtl;
473
+ const skipCache = perCallOptions.skipCache ?? settings.skipCache;
474
+ const headers = {};
475
+ if (cacheTtl !== void 0) headers["cf-aig-cache-ttl"] = String(cacheTtl);
476
+ if (skipCache === true) headers["cf-aig-skip-cache"] = "true";
477
+ return headers;
478
+ }
393
479
  var AnyRouterChatLanguageModel = class {
394
- specificationVersion = "v3";
480
+ specificationVersion = "v4";
395
481
  provider;
396
482
  modelId;
397
483
  supportedUrls = {};
@@ -401,7 +487,6 @@ var AnyRouterChatLanguageModel = class {
401
487
  this.provider = config.provider;
402
488
  this.config = config;
403
489
  }
404
- // ─── doGenerate ─────────────────────────────────────────────────────────
405
490
  async doGenerate(options) {
406
491
  const perCallOptions = await parseProviderOptions({
407
492
  provider: "anyrouter",
@@ -413,11 +498,16 @@ var AnyRouterChatLanguageModel = class {
413
498
  options,
414
499
  this.config.settings,
415
500
  false,
416
- perCallOptions
501
+ perCallOptions,
502
+ this.config.fileCache
417
503
  );
418
504
  const { value: response, responseHeaders } = await postJsonToApi({
419
505
  url: `${this.config.baseURL}/chat/completions`,
420
- headers: combineHeaders(this.config.headers(), options.headers),
506
+ headers: combineHeaders(
507
+ this.config.headers(),
508
+ buildCacheHeaders(this.config.settings, perCallOptions),
509
+ options.headers
510
+ ),
421
511
  body,
422
512
  failedResponseHandler: createJsonErrorResponseHandler({
423
513
  errorSchema: anyRouterErrorSchema,
@@ -462,17 +552,28 @@ var AnyRouterChatLanguageModel = class {
462
552
  }
463
553
  };
464
554
  }
465
- // ─── doStream ───────────────────────────────────────────────────────────
466
555
  async doStream(options) {
467
556
  const perCallOptions = await parseProviderOptions({
468
557
  provider: "anyrouter",
469
558
  providerOptions: options.providerOptions,
470
559
  schema: anyRouterProviderOptionsSchema
471
560
  }) ?? {};
472
- const body = buildRequestBody(this.modelId, options, this.config.settings, true, perCallOptions);
561
+ const body = buildRequestBody(
562
+ this.modelId,
563
+ options,
564
+ this.config.settings,
565
+ true,
566
+ perCallOptions,
567
+ this.config.fileCache
568
+ );
569
+ const url = `${this.config.baseURL}/chat/completions`;
473
570
  const { value: stream, responseHeaders } = await postJsonToApi({
474
- url: `${this.config.baseURL}/chat/completions`,
475
- headers: combineHeaders(this.config.headers(), options.headers),
571
+ url,
572
+ headers: combineHeaders(
573
+ this.config.headers(),
574
+ buildCacheHeaders(this.config.settings, perCallOptions),
575
+ options.headers
576
+ ),
476
577
  body,
477
578
  failedResponseHandler: createJsonErrorResponseHandler({
478
579
  errorSchema: anyRouterErrorSchema,
@@ -490,6 +591,8 @@ var AnyRouterChatLanguageModel = class {
490
591
  metadataEmitted: false
491
592
  };
492
593
  const selfModelId = this.modelId;
594
+ let streamUsage;
595
+ let finishChoice;
493
596
  const transformStream = new TransformStream({
494
597
  start(controller) {
495
598
  controller.enqueue({ type: "stream-start", warnings: [] });
@@ -500,29 +603,21 @@ var AnyRouterChatLanguageModel = class {
500
603
  return;
501
604
  }
502
605
  const chunk = chunkResult.value;
606
+ if (chunk.error) {
607
+ controller.enqueue(errorFramePart(chunk, { url, body, responseHeaders }));
608
+ finishChoice = { finish_reason: "error" };
609
+ return;
610
+ }
503
611
  const choice = chunk.choices?.[0];
612
+ if (chunk.usage) streamUsage = chunk.usage;
504
613
  emitResponseMetadata(chunk, state, selfModelId, controller);
505
- const delta = choice?.delta;
506
- if (delta) {
507
- if (typeof delta.reasoning_content === "string" && delta.reasoning_content.length > 0) {
508
- emitReasoningDelta(delta.reasoning_content, state, controller);
509
- }
510
- if (typeof delta.content === "string" && delta.content.length > 0) {
511
- emitTextDelta(delta.content, state, controller);
512
- }
513
- if (delta.tool_calls) {
514
- emitToolCallDeltas(delta.tool_calls, toolCallAccumulator, controller);
515
- }
516
- }
614
+ if (choice?.delta) emitDelta(choice.delta, state, toolCallAccumulator, controller);
517
615
  if (choice?.finish_reason) {
518
- emitFinish(choice, chunk, state, toolCallAccumulator, controller);
616
+ finishChoice = choice;
519
617
  }
520
618
  },
521
619
  flush(controller) {
522
- closeReasoning(state, controller);
523
- if (state.activeTextId !== null) {
524
- controller.enqueue({ type: "text-end", id: state.activeTextId });
525
- }
620
+ emitFinish(finishChoice, streamUsage, state, toolCallAccumulator, controller);
526
621
  }
527
622
  });
528
623
  return {
@@ -550,7 +645,7 @@ var embeddingResponseSchema = z.object({
550
645
  }).optional()
551
646
  });
552
647
  var AnyRouterEmbeddingModel = class {
553
- specificationVersion = "v3";
648
+ specificationVersion = "v4";
554
649
  provider;
555
650
  modelId;
556
651
  /** No hard per-call limit imposed by the provider layer. */
@@ -588,100 +683,109 @@ var AnyRouterEmbeddingModel = class {
588
683
  };
589
684
  }
590
685
  };
591
- var anyRouterErrorSchema3 = z.object({
592
- error: z.object({
593
- code: z.string().optional(),
594
- message: z.string().optional()
595
- }).optional()
596
- });
597
- var imageGenerationResponseSchema = z.object({
598
- created: z.number().optional(),
599
- data: z.array(
600
- z.object({
601
- url: z.string().optional(),
602
- b64_json: z.string().optional(),
603
- revised_prompt: z.string().optional()
604
- })
605
- )
606
- });
607
- var AnyRouterImageModel = class {
608
- specificationVersion = "v3";
609
- provider;
610
- modelId;
686
+
687
+ // src/file-reference-cache.ts
688
+ var PROVIDER_KEY = "anyrouter";
689
+ var FileReferenceCache = class {
690
+ store = /* @__PURE__ */ new Map();
611
691
  /**
612
- * Most image generation APIs support only 1 image per call via the
613
- * standard `/images/generations` endpoint.
692
+ * Look up a cached entry via a `SharedV4ProviderReference`.
693
+ * Returns `undefined` when the reference was not created by this cache.
614
694
  */
615
- maxImagesPerCall = 1;
616
- config;
617
- constructor(modelId, config) {
618
- this.modelId = modelId;
619
- this.provider = config.provider;
620
- this.config = config;
695
+ lookup(reference) {
696
+ const hash = reference[PROVIDER_KEY];
697
+ return hash ? this.store.get(hash) : void 0;
621
698
  }
622
- async doGenerate(options) {
623
- if (options.mask) {
624
- throw new UnsupportedFunctionalityError({
625
- functionality: "mask (inpainting) for AnyRouter image generation"
626
- });
627
- }
628
- const warnings = [];
629
- if (options.n > 1) {
630
- warnings.push({
631
- type: "unsupported",
632
- feature: `n=${options.n} (AnyRouter image endpoint supports n=1 per call)`
633
- });
634
- }
635
- const body = {
636
- model: this.modelId,
637
- prompt: options.prompt ?? "",
638
- n: Math.min(options.n, 1),
639
- ...options.size ? { size: options.size } : {},
640
- ...options.seed !== void 0 ? { seed: options.seed } : {},
641
- response_format: "b64_json"
642
- };
643
- const { value: response, responseHeaders } = await postJsonToApi({
644
- url: `${this.config.baseURL}/images/generations`,
645
- headers: combineHeaders(this.config.headers(), options.headers),
646
- body,
647
- failedResponseHandler: createJsonErrorResponseHandler({
648
- errorSchema: anyRouterErrorSchema3,
649
- errorToMessage: (data) => data.error?.message ?? "AnyRouter images API error",
650
- isRetryable: (res) => res.status >= 500
651
- }),
652
- successfulResponseHandler: createJsonResponseHandler(imageGenerationResponseSchema),
653
- abortSignal: options.abortSignal,
654
- fetch: this.config.fetch
655
- });
656
- const images = [];
657
- for (const item of response.data) {
658
- if (item.b64_json) {
659
- images.push(item.b64_json);
660
- } else if (item.url) {
661
- images.push(item.url);
662
- }
699
+ /** Add an entry and return the corresponding provider reference. */
700
+ set(hash, entry) {
701
+ this.store.set(hash, entry);
702
+ return { [PROVIDER_KEY]: hash };
703
+ }
704
+ /** Returns true when the content hash is already cached. */
705
+ has(hash) {
706
+ return this.store.has(hash);
707
+ }
708
+ /**
709
+ * Build a `SharedV4ProviderReference` for the given hash without writing
710
+ * to the cache. Use this to construct the return value of `uploadFile`
711
+ * after confirming the hash is already stored.
712
+ */
713
+ referenceFor(hash) {
714
+ return { [PROVIDER_KEY]: hash };
715
+ }
716
+ };
717
+ async function hashFileData(data) {
718
+ let bytes;
719
+ if (data.type === "text") {
720
+ bytes = new TextEncoder().encode(data.text);
721
+ } else if (typeof data.data === "string") {
722
+ bytes = new TextEncoder().encode(data.data);
723
+ } else {
724
+ bytes = data.data;
725
+ }
726
+ const hashBuffer = await crypto.subtle.digest("SHA-256", Uint8Array.from(bytes));
727
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
728
+ return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
729
+ }
730
+ function fileDataVariantToUrl(data, mediaType) {
731
+ if (data.type === "text") {
732
+ return `data:${mediaType};base64,${btoa(data.text)}`;
733
+ }
734
+ if (typeof data.data === "string") {
735
+ if (data.data.startsWith("data:")) return data.data;
736
+ return `data:${mediaType};base64,${data.data}`;
737
+ }
738
+ let binary = "";
739
+ for (let i = 0; i < data.data.length; i++) {
740
+ binary += String.fromCharCode(data.data[i]);
741
+ }
742
+ return `data:${mediaType};base64,${btoa(binary)}`;
743
+ }
744
+
745
+ // src/anyrouter-files.ts
746
+ var AnyRouterFiles = class {
747
+ specificationVersion = "v4";
748
+ provider;
749
+ cache;
750
+ constructor(provider, cache) {
751
+ this.provider = provider;
752
+ this.cache = cache;
753
+ }
754
+ /**
755
+ * Register a file in the in-session cache and return a provider reference.
756
+ *
757
+ * Calling this multiple times with the same file content is idempotent —
758
+ * the hash check prevents redundant re-encoding.
759
+ */
760
+ async uploadFile(options) {
761
+ const hash = await hashFileData(options.data);
762
+ if (!this.cache.has(hash)) {
763
+ const url = fileDataVariantToUrl(options.data, options.mediaType);
764
+ this.cache.set(hash, { url, mediaType: options.mediaType });
663
765
  }
664
766
  return {
665
- images,
666
- warnings,
667
- response: {
668
- timestamp: /* @__PURE__ */ new Date(),
669
- modelId: this.modelId,
670
- headers: responseHeaders
671
- }
767
+ providerReference: this.cache.referenceFor(hash),
768
+ mediaType: options.mediaType,
769
+ filename: options.filename,
770
+ warnings: []
672
771
  };
673
772
  }
674
773
  };
675
774
  var PROVIDER_ID = "anyrouter";
676
775
  function createAnyRouter(options = {}) {
677
776
  const baseURL = withoutTrailingSlash(options.baseURL ?? DEFAULT_BASE_URL) ?? DEFAULT_BASE_URL;
777
+ const sharedFileCache = new FileReferenceCache();
678
778
  function getHeaders() {
779
+ const attribution = options.app ? buildAppAttributionHeaders(options.app) : {};
780
+ if (options.keyless) {
781
+ return combineHeaders(attribution, options.headers);
782
+ }
679
783
  const apiKey = loadApiKey({
680
784
  apiKey: options.apiKey,
681
785
  environmentVariableName: "ANYROUTER_API_KEY",
682
786
  description: "AnyRouter"
683
787
  });
684
- return combineHeaders({ Authorization: `Bearer ${apiKey}` }, options.headers);
788
+ return combineHeaders({ Authorization: `Bearer ${apiKey}`, ...attribution }, options.headers);
685
789
  }
686
790
  function chatModel(modelId) {
687
791
  return new AnyRouterChatLanguageModel(modelId, {
@@ -689,7 +793,8 @@ function createAnyRouter(options = {}) {
689
793
  baseURL,
690
794
  headers: getHeaders,
691
795
  fetch: options.fetch,
692
- settings: options
796
+ settings: options,
797
+ fileCache: sharedFileCache
693
798
  });
694
799
  }
695
800
  function embeddingModel(modelId) {
@@ -700,37 +805,30 @@ function createAnyRouter(options = {}) {
700
805
  fetch: options.fetch
701
806
  });
702
807
  }
703
- function imageModel(modelId) {
704
- return new AnyRouterImageModel(modelId, {
705
- provider: PROVIDER_ID,
706
- baseURL,
707
- headers: getHeaders,
708
- fetch: options.fetch
709
- });
710
- }
711
808
  const provider = (modelId) => chatModel(modelId);
712
809
  const providerObj = Object.assign(provider, {
713
- // ProviderV3 required fields
714
- specificationVersion: "v3",
715
- // ProviderV3 required methods
810
+ // ProviderV4 required fields
811
+ specificationVersion: "v4",
812
+ // ProviderV4 required methods
716
813
  languageModel(modelId) {
717
814
  return chatModel(modelId);
718
815
  },
719
816
  embeddingModel(modelId) {
720
817
  return embeddingModel(modelId);
721
818
  },
722
- imageModel(modelId) {
723
- return imageModel(modelId);
724
- },
725
- // ProviderV3 optional methods (deprecated textEmbeddingModel alias)
726
- textEmbeddingModel(modelId) {
727
- return embeddingModel(modelId);
728
- },
729
819
  // AnyRouter convenience alias
730
820
  chat(modelId) {
731
821
  return chatModel(modelId);
732
822
  },
733
- // Unsupported model types — throw NoSuchModelError per ProviderV3 contract
823
+ // ProviderV4 file-management interface
824
+ files() {
825
+ return new AnyRouterFiles(PROVIDER_ID, sharedFileCache);
826
+ },
827
+ // Unsupported optional model types — throw NoSuchModelError per ProviderV4 contract.
828
+ // Image/video generation is not an AnyRouter product (text + embeddings only).
829
+ imageModel(modelId) {
830
+ throw new NoSuchModelError({ modelId, modelType: "imageModel" });
831
+ },
734
832
  transcriptionModel(modelId) {
735
833
  throw new NoSuchModelError({ modelId, modelType: "transcriptionModel" });
736
834
  },
@@ -754,4 +852,4 @@ function createAnyRouter(options = {}) {
754
852
  }
755
853
  var anyrouter = createAnyRouter();
756
854
 
757
- export { AnyRouterChatLanguageModel, AnyRouterEmbeddingModel, AnyRouterImageModel, anyrouter, createAnyRouter };
855
+ export { AnyRouterChatLanguageModel, AnyRouterEmbeddingModel, AnyRouterFiles, FileReferenceCache, PROVIDER_ATTRIBUTION, anyrouter, buildAppAttributionHeaders, createAnyRouter };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anyr/ai-sdk-provider",
3
- "version": "0.1.4",
3
+ "version": "0.1.7",
4
4
  "description": "The AnyRouter provider for the Vercel AI SDK — call every AnyRouter model through `createAnyRouter`.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -31,7 +31,7 @@
31
31
  "build": "tsup",
32
32
  "dev": "tsup --watch",
33
33
  "clean": "rm -rf dist",
34
- "typecheck": "tsc --noEmit",
34
+ "typecheck": "tsgo --noEmit",
35
35
  "test": "vitest run",
36
36
  "prepublishOnly": "tsup"
37
37
  },
@@ -49,31 +49,35 @@
49
49
  "homepage": "https://anyrouter.dev",
50
50
  "repository": {
51
51
  "type": "git",
52
- "url": "git+https://github.com/duyet/anyrouter.git",
53
- "directory": "packages/ai-sdk-provider"
52
+ "url": "git+https://github.com/AnyRouterHQ/anyrouter-ai-sdk-provider.git"
54
53
  },
55
54
  "bugs": {
56
- "url": "https://github.com/duyet/anyrouter/issues"
55
+ "url": "https://github.com/AnyRouterHQ/anyrouter-ai-sdk-provider/issues"
57
56
  },
58
57
  "author": "Duyet Le",
58
+ "packageManager": "pnpm@12.16.1",
59
59
  "license": "MIT",
60
60
  "publishConfig": {
61
61
  "access": "public"
62
62
  },
63
63
  "dependencies": {
64
- "@anyr/sdk": "^0.1.1"
64
+ "@anyr/sdk": "^0.1.3"
65
65
  },
66
66
  "peerDependencies": {
67
- "@ai-sdk/provider": "^3.0.10 || ^4.0.0-beta",
68
- "@ai-sdk/provider-utils": "^4.0.0 || ^5.0.0-beta",
69
- "ai": "^6.0.0 || ^7.0.0-beta",
67
+ "@ai-sdk/provider": "^4.0.0",
68
+ "@ai-sdk/provider-utils": "^5.0.0",
69
+ "ai": "^7.0.0",
70
70
  "zod": "^3.25.0 || ^4.0.0"
71
71
  },
72
72
  "devDependencies": {
73
- "@ai-sdk/provider": "^3.0.10",
74
- "@ai-sdk/provider-utils": "^4.0.0",
73
+ "@ai-sdk/provider": "4.0.2",
74
+ "@ai-sdk/provider-utils": "5.0.5",
75
75
  "@types/node": "^24.0.0",
76
- "ai": "^6.0.159",
77
- "zod": "^4.4.3"
76
+ "@typescript/native-preview": "7.0.0-dev.20260707.2",
77
+ "ai": "7.0.15",
78
+ "tsup": "^8.5.1",
79
+ "typescript": "^6.0.3",
80
+ "vitest": "^5.1.0",
81
+ "zod": "4.6.7"
78
82
  }
79
83
  }