@byte_fluffy/nexra-sdk 0.1.0-alpha.45 → 0.1.0-alpha.47

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.
@@ -419,21 +419,27 @@ var NEXRA_GENERATION_OPERATIONS = [
419
419
  "video.generate",
420
420
  "audio.generate",
421
421
  "image.upscale",
422
- "video.upscale"
422
+ "video.upscale",
423
+ "video.depth",
424
+ "video.segment"
423
425
  ];
424
426
  var NEXRA_MEDIA_OPERATIONS = [
425
427
  "image.generate",
426
428
  "video.generate",
427
429
  "audio.generate",
428
430
  "image.upscale",
429
- "video.upscale"
431
+ "video.upscale",
432
+ "video.depth",
433
+ "video.segment"
430
434
  ];
431
435
  var NEXRA_PUBLISHED_MEDIA_OPERATIONS = [
432
436
  "image.generate",
433
437
  "video.generate",
434
438
  "audio.generate",
435
439
  "image.upscale",
436
- "video.upscale"
440
+ "video.upscale",
441
+ "video.depth",
442
+ "video.segment"
437
443
  ];
438
444
  var NEXRA_MEDIA_FEATURES = [
439
445
  "text-to-image",
@@ -459,7 +465,9 @@ var NEXRA_MEDIA_FEATURES = [
459
465
  "voice-reference",
460
466
  "voice-design",
461
467
  "scale-factor",
462
- "target-resolution"
468
+ "target-resolution",
469
+ "video-depth",
470
+ "video-segment"
463
471
  ];
464
472
  var NEXRA_MEDIA_OPERATION_DEFINITIONS = Object.freeze([
465
473
  {
@@ -496,6 +504,20 @@ var NEXRA_MEDIA_OPERATION_DEFINITIONS = Object.freeze([
496
504
  outputKind: "video",
497
505
  features: ["scale-factor", "target-resolution"],
498
506
  parameterKeys: ["scale", "resolution", "output_format", "preserve_details"]
507
+ },
508
+ {
509
+ operation: "video.depth",
510
+ status: "active",
511
+ outputKind: "video",
512
+ features: ["video-depth"],
513
+ parameterKeys: ["resolution"]
514
+ },
515
+ {
516
+ operation: "video.segment",
517
+ status: "active",
518
+ outputKind: "video",
519
+ features: ["video-segment"],
520
+ parameterKeys: ["resolution"]
499
521
  }
500
522
  ]);
501
523
  var mediaSourceSchema = {
@@ -553,9 +575,20 @@ function inputSchema(contentItems, properties, contentBounds = {}) {
553
575
  };
554
576
  }
555
577
  var imagePart = mediaPartSchema("image", ["source", "reference", "first_frame", "last_frame", "mask", "control", "subject", "background"]);
556
- var videoImagePart = mediaPartSchema("image", ["source", "reference", "first_frame", "last_frame", "mask", "control", "subject", "background", "keyframe"]);
578
+ var videoImagePart = mediaPartSchema("image", ["source", "reference", "first_frame", "middle_frame", "last_frame", "mask", "control", "subject", "background", "keyframe"]);
557
579
  var videoPart = mediaPartSchema("video", ["source", "reference", "edit", "extend"]);
558
580
  var audioPart = mediaPartSchema("audio", ["source", "reference", "voice_reference"]);
581
+ var resourcePart = {
582
+ type: "object",
583
+ properties: {
584
+ type: { const: "resource" },
585
+ resource: { type: "string", enum: ["element", "voice"] },
586
+ source: { type: "string", minLength: 1 },
587
+ name: { type: "string", minLength: 1 }
588
+ },
589
+ required: ["type", "resource", "source", "name"],
590
+ additionalProperties: false
591
+ };
559
592
  var draftPart = {
560
593
  type: "object",
561
594
  properties: {
@@ -580,7 +613,7 @@ var NEXRA_MEDIA_INPUT_SCHEMAS = Object.freeze({
580
613
  }
581
614
  ),
582
615
  "video.generate": inputSchema(
583
- [textPartSchema(["prompt", "negative_prompt", "script"]), videoImagePart, videoPart, audioPart, draftPart],
616
+ [textPartSchema(["prompt", "negative_prompt", "script"]), videoImagePart, videoPart, audioPart, draftPart, resourcePart],
584
617
  {
585
618
  task_type: { type: "string", minLength: 1, "x-ui": { order: 8, control: "segmented" } },
586
619
  voice: { type: "string", minLength: 1, "x-ui": { order: 9, control: "resource", resource: "voice" } },
@@ -635,6 +668,16 @@ var NEXRA_MEDIA_INPUT_SCHEMAS = Object.freeze({
635
668
  preserve_details: { type: "boolean", "x-ui": { order: 13, control: "switch" } }
636
669
  },
637
670
  { minItems: 1, maxItems: 1 }
671
+ ),
672
+ "video.segment": inputSchema(
673
+ [textPartSchema(["prompt"]), mediaPartSchema("video", ["source"])],
674
+ { resolution: { type: "string", minLength: 1, "x-ui": { order: 10 } } },
675
+ { minItems: 2, maxItems: 2 }
676
+ ),
677
+ "video.depth": inputSchema(
678
+ [mediaPartSchema("video", ["source"])],
679
+ { resolution: { type: "string", minLength: 1, "x-ui": { order: 10 } } },
680
+ { minItems: 1, maxItems: 1 }
638
681
  )
639
682
  });
640
683
  function nexraMediaInputSchema(operation) {
@@ -649,6 +692,7 @@ function isNexraMediaInput(value) {
649
692
  return Array.isArray(content) && content.length > 0 && content.every((part) => {
650
693
  if (!part || typeof part !== "object" || Array.isArray(part)) return false;
651
694
  if (part.type === "text") return typeof part.text === "string" && part.text.length > 0;
695
+ if (part.type === "resource") return ["element", "voice"].includes(String(part.resource)) && typeof part.source === "string" && part.source.length > 0 && typeof part.name === "string" && part.name.length > 0;
652
696
  if (part.type === "draft_task") {
653
697
  const reference = part.draft_task;
654
698
  return Boolean(reference && typeof reference === "object" && !Array.isArray(reference) && typeof reference.id === "string" && reference.id.length > 0);
@@ -664,6 +708,8 @@ function nexraMediaOperationForMode(mode) {
664
708
  if (["text-to-speech", "text-to-music", "text-to-sfx"].includes(mode)) return "audio.generate";
665
709
  if (mode === "image-upscale") return "image.upscale";
666
710
  if (mode === "video-upscale") return "video.upscale";
711
+ if (mode === "video-depth") return "video.depth";
712
+ if (mode === "video-segment") return "video.segment";
667
713
  return void 0;
668
714
  }
669
715
  function nexraMediaInputSchemaForMode(mode) {
@@ -705,10 +751,11 @@ function nexraMediaInputSchemaForMode(mode) {
705
751
  variant.required = [...required];
706
752
  }
707
753
  }
708
- const requiredMedia = mode === "image-to-image" || mode === "image-to-video" || mode === "avatar-video" ? "image" : void 0;
754
+ const requiredMedia = ["video-depth", "video-segment"].includes(mode) ? "video" : mode === "image-to-image" || mode === "image-to-video" || mode === "avatar-video" ? "image" : void 0;
709
755
  const requiresReferenceMedia = mode === "multimodal-to-video";
756
+ const hasTextPart = items.oneOf.some((variant) => variant.properties.type.const === "text");
710
757
  content.allOf = [
711
- ...mode === "avatar-video" ? [] : [{
758
+ ...mode === "avatar-video" || !hasTextPart ? [] : [{
712
759
  contains: { type: "object", properties: { type: { const: "text" } }, required: ["type"] },
713
760
  minContains: 1
714
761
  }],
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- export { A as AssetImportRequest, a as AssetInput, b as AssetReference, c as AssetUploadOptions, M as MEDIA_KINDS, d as MediaAsset, e as MediaAssetStatus, f as MediaKind, N as NexraImageLayer, g as NexraImageLayerDecompositionOutput } from './media-CwGmG5qB.js';
2
- import { H as HttpTransport, u as ModelSearchParams, T as TaskModelSummary, v as TaskModel, w as ModelSchema, x as ModelResourceList, y as NexraClientOptions } from './media-geometry-KwQh1O8Y.js';
3
- export { e as CreateNexraDisplayQuoteBatchRequest, C as CreateNexraQuoteRequest, F as FetchLike, M as MediaGeometryField, k as MediaGeometryProjection, z as ModelCapabilitySummary, A as ModelDateVersion, B as ModelEndpointSummary, D as ModelModality, E as ModelResourceOption, l as NexraBillingCurrency, g as NexraCatalogRevision, f as NexraDisplayQuoteBatch, G as NexraDisplayQuoteBatchEntry, n as NexraModelOperation, h as NexraModelSpec, j as NexraModelSpecFilter, d as NexraQuote, o as NexraSalePrice, c as NexraSalePriceList, p as NexraSettlement, U as UnifiedMediaGeometry, q as applyMediaGeometry, r as decodeMediaGeometry, s as encodeMediaGeometry, t as projectMediaGeometry } from './media-geometry-KwQh1O8Y.js';
1
+ export { A as AssetImportRequest, a as AssetInput, b as AssetReference, c as AssetUploadOptions, M as MEDIA_KINDS, d as MediaAsset, e as MediaAssetStatus, f as MediaKind, N as NexraImageLayer, g as NexraImageLayerDecompositionOutput } from './media-Co8S2qEM.js';
2
+ import { H as HttpTransport, u as ModelSearchParams, T as TaskModelSummary, v as TaskModel, w as ModelSchema, x as ModelResourceList, y as NexraClientOptions } from './media-geometry-BS4DZh4B.js';
3
+ export { e as CreateNexraDisplayQuoteBatchRequest, C as CreateNexraQuoteRequest, F as FetchLike, M as MediaGeometryField, k as MediaGeometryProjection, z as ModelCapabilitySummary, A as ModelDateVersion, B as ModelEndpointSummary, D as ModelModality, E as ModelResourceOption, l as NexraBillingCurrency, g as NexraCatalogRevision, f as NexraDisplayQuoteBatch, G as NexraDisplayQuoteBatchEntry, n as NexraModelOperation, h as NexraModelSpec, j as NexraModelSpecFilter, d as NexraQuote, o as NexraSalePrice, c as NexraSalePriceList, p as NexraSettlement, U as UnifiedMediaGeometry, q as applyMediaGeometry, r as decodeMediaGeometry, s as encodeMediaGeometry, t as projectMediaGeometry } from './media-geometry-BS4DZh4B.js';
4
4
  import { C as CursorPage, J as JsonValue } from './json-Cz0MkWQn.js';
5
5
  export { a as JsonObject, b as JsonPrimitive } from './json-Cz0MkWQn.js';
6
6
  import { N as NexraError, P as PublicErrorFields } from './errors-DJZuAKoO.js';
7
7
  export { A as ApiErrorPayload, a as PublicError, b as PublicErrorContext, e as extractUpstreamErrorMessage } from './errors-DJZuAKoO.js';
8
- import { V as Voice, C as CreateVoiceRequest, a as VoiceCreation, A as AssetsClient, T as TasksClient, R as RunTaskOptions, b as RunResult, c as TaskResult } from './voices-B09HqQJJ.js';
9
- export { d as CreateTaskOptions, e as CreateTaskRequest, f as RequestDetails, g as TASK_STATUSES, h as TaskCost, i as TaskError, j as TaskEvent, k as TaskEventType, l as TaskListParams, m as TaskPage, n as TaskProgress, o as TaskReceipt, p as TaskStatus, q as TaskTiming, r as TaskUsage, s as TaskWebhookConfig, t as TerminalTaskStatus, u as VerifyWebhookOptions, W as WaitTaskOptions, v as WatchTaskOptions, w as isTerminalTaskStatus, x as verifyWebhook } from './voices-B09HqQJJ.js';
8
+ import { V as Voice, C as CreateVoiceRequest, a as VoiceCreation, A as AssetsClient, T as TasksClient, R as RunTaskOptions, b as RunResult, c as TaskResult } from './voices-Bzt4nV1r.js';
9
+ export { d as CreateTaskOptions, e as CreateTaskRequest, f as RequestDetails, g as TASK_STATUSES, h as TaskCost, i as TaskError, j as TaskEvent, k as TaskEventType, l as TaskListParams, m as TaskPage, n as TaskProgress, o as TaskReceipt, p as TaskStatus, q as TaskTiming, r as TaskUsage, s as TaskWebhookConfig, t as TerminalTaskStatus, u as VerifyWebhookOptions, W as WaitTaskOptions, v as WatchTaskOptions, w as isTerminalTaskStatus, x as verifyWebhook } from './voices-Bzt4nV1r.js';
10
10
  import { CatalogClient } from './catalog.js';
11
11
  export { formatModelDisplayName, getModelSpec, listModelSpecs } from './catalog.js';
12
12
  export { ceilDecimal, multiplyDecimal } from './decimal.js';
package/dist/index.js CHANGED
@@ -20,14 +20,14 @@ import {
20
20
  projectMediaGeometry,
21
21
  queryString,
22
22
  sleep
23
- } from "./chunk-OX5GFYVN.js";
23
+ } from "./chunk-7MNUV5BJ.js";
24
24
  import {
25
25
  MEDIA_KINDS,
26
26
  TASK_STATUSES,
27
27
  createTaskRequest,
28
28
  extractUpstreamErrorMessage,
29
29
  isTerminalTaskStatus
30
- } from "./chunk-FEACXUHZ.js";
30
+ } from "./chunk-LXR3MEF3.js";
31
31
 
32
32
  // src/assets.ts
33
33
  var AssetsClient = class {
@@ -1,7 +1,7 @@
1
1
  import { APICallError, LanguageModelV4 } from '@ai-sdk/provider';
2
2
  import { NexraLanguageProtocol } from './catalog.js';
3
3
  export { NexraLanguageModelBinding } from './catalog.js';
4
- import { F as FetchLike } from './media-geometry-KwQh1O8Y.js';
4
+ import { F as FetchLike } from './media-geometry-BS4DZh4B.js';
5
5
  import { N as NexraError } from './errors-DJZuAKoO.js';
6
6
  import './json-Cz0MkWQn.js';
7
7
 
package/dist/language.js CHANGED
@@ -6,18 +6,17 @@ import {
6
6
  jsonBody,
7
7
  parseServerSentEvents,
8
8
  resolveNexraLanguageReasoning
9
- } from "./chunk-OX5GFYVN.js";
9
+ } from "./chunk-7MNUV5BJ.js";
10
10
  import {
11
11
  isPublicErrorCode,
12
12
  publicErrorMessage,
13
13
  resolvePublicErrorLocale
14
- } from "./chunk-FEACXUHZ.js";
14
+ } from "./chunk-LXR3MEF3.js";
15
15
 
16
16
  // src/language/index.ts
17
17
  import { createAnthropic } from "@ai-sdk/anthropic";
18
18
  import { getModelCapabilities as getAnthropicModelCapabilities } from "@ai-sdk/anthropic/internal";
19
19
  import { createGoogleGenerativeAI } from "@ai-sdk/google";
20
- import { createOpenAI } from "@ai-sdk/openai";
21
20
  import { mapReasoningToProviderBudget } from "@ai-sdk/provider-utils";
22
21
 
23
22
  // src/language/chat-model.ts
@@ -72,6 +71,30 @@ function nativeOptions(part) {
72
71
  const value = part.providerOptions?.nexra;
73
72
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
74
73
  }
74
+ function nativeMediaUrlPatterns(binding, kind) {
75
+ const field = kind === "audio" ? "input_audio" : `${kind}_url`;
76
+ const messages2 = asObject(asObject(binding.endpoint.inputSchema?.properties).messages);
77
+ const content = asObject(asObject(asObject(messages2.items).properties).content);
78
+ const patterns = /* @__PURE__ */ new Set();
79
+ const visit = (value) => {
80
+ if (Array.isArray(value)) {
81
+ value.forEach(visit);
82
+ return;
83
+ }
84
+ const node = asObject(value);
85
+ const properties = asObject(node.properties);
86
+ if (asObject(properties.type).const === field) {
87
+ const url = asObject(asObject(asObject(properties[field]).properties).url);
88
+ if (typeof url.pattern === "string") patterns.add(url.pattern);
89
+ }
90
+ for (const child of Object.values(node)) if (child && typeof child === "object") visit(child);
91
+ };
92
+ visit(content);
93
+ return patterns.size ? [...patterns].map((pattern) => new RegExp(pattern)) : void 0;
94
+ }
95
+ function chatSupportedUrls(binding) {
96
+ return Object.fromEntries(binding.spec.capabilities.inputModalities.filter((kind) => ["image", "audio", "video"].includes(kind)).map((kind) => [`${kind}/*`, nativeMediaUrlPatterns(binding, kind) ?? [/^https?:\/\//]]));
97
+ }
75
98
  function filePart(part, binding) {
76
99
  const kind = part.mediaType.split("/")[0];
77
100
  if (["image", "audio", "video"].includes(kind) && !binding.spec.capabilities.inputModalities.includes(kind)) {
@@ -83,6 +106,10 @@ function filePart(part, binding) {
83
106
  throw new UnsupportedFunctionalityError({ functionality: "file reference without a Nexra reference" });
84
107
  }
85
108
  const url = part.data.type === "url" ? part.data.url.toString() : void 0;
109
+ const patterns = nativeMediaUrlPatterns(binding, kind);
110
+ if (url && patterns && !patterns.some((pattern) => pattern.test(url))) {
111
+ throw new UnsupportedFunctionalityError({ functionality: `native media URL for ${binding.spec.id}; provide bytes or a matching data URL` });
112
+ }
86
113
  const data = part.data.type === "data" ? convertToBase64(part.data.data) : void 0;
87
114
  if (kind === "image" || kind === "video") {
88
115
  const field = kind === "image" ? "image_url" : "video_url";
@@ -380,7 +407,7 @@ function createChatLanguageModel(binding, transport) {
380
407
  specificationVersion: "v4",
381
408
  provider: "nexra.chat",
382
409
  modelId: binding.spec.id,
383
- supportedUrls: Object.fromEntries(binding.spec.capabilities.inputModalities.filter((kind) => ["image", "audio", "video"].includes(kind)).map((kind) => [`${kind}/*`, [/^https?:\/\//]])),
410
+ supportedUrls: chatSupportedUrls(binding),
384
411
  async doGenerate(options) {
385
412
  const body = chatRequest(binding, options, false);
386
413
  const response = await transport.response("/chat/completions", { method: "POST", ...jsonBody(body), headers: combineHeaders(options), signal: options.abortSignal }, { retryable: false });
@@ -528,6 +555,188 @@ function combineHeaders(options) {
528
555
  return headers;
529
556
  }
530
557
 
558
+ // src/language/responses-model.ts
559
+ import { createOpenAI } from "@ai-sdk/openai";
560
+ function object3(value) {
561
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
562
+ }
563
+ function isUnpositionedCitation(value) {
564
+ const node = object3(value);
565
+ return node.type === "url_citation" && typeof node.url === "string" && !Object.hasOwn(node, "start_index") && !Object.hasOwn(node, "end_index");
566
+ }
567
+ function project(value) {
568
+ if (Array.isArray(value)) return value.map(project);
569
+ if (!value || typeof value !== "object") return value;
570
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [
571
+ key,
572
+ key === "annotations" && Array.isArray(item) ? item.filter((annotation) => !isUnpositionedCitation(annotation)).map(project) : project(item)
573
+ ]));
574
+ }
575
+ function citations(value) {
576
+ if (Array.isArray(value)) return value.flatMap(citations);
577
+ const node = object3(value);
578
+ if (isUnpositionedCitation(node)) return [node];
579
+ return Object.values(node).flatMap((item) => item && typeof item === "object" ? citations(item) : []);
580
+ }
581
+ function nativeSearchBody(value, call) {
582
+ const extension = call.providerOptions?.nexra?.web_search;
583
+ if (extension === void 0) return value;
584
+ if (!extension || typeof extension !== "object" || Array.isArray(extension)) throw new Error("Nexra web_search options must be a native tool object");
585
+ const body = object3(value);
586
+ if (!Array.isArray(body.tools) || !body.tools.some((tool) => object3(tool).type === "web_search")) {
587
+ throw new Error("Nexra web_search options require an enabled web_search tool");
588
+ }
589
+ return { ...body, tools: body.tools.map((tool) => object3(tool).type === "web_search" ? { ...object3(tool), ...extension, type: "web_search" } : tool) };
590
+ }
591
+ function nativeSearchRequest(init, call) {
592
+ return typeof init?.body === "string" ? { ...init, body: JSON.stringify(nativeSearchBody(JSON.parse(init.body), call)) } : init;
593
+ }
594
+ function createResponsesLanguageModel(options) {
595
+ const factory = (fetch) => createOpenAI({
596
+ apiKey: options.apiKey,
597
+ headers: options.headers,
598
+ name: "nexra.openai",
599
+ baseURL: options.baseUrl,
600
+ fetch
601
+ }).responses(options.modelId);
602
+ const base = factory(options.fetch);
603
+ return {
604
+ specificationVersion: "v4",
605
+ provider: base.provider,
606
+ modelId: base.modelId,
607
+ supportedUrls: base.supportedUrls,
608
+ async doGenerate(call) {
609
+ let original;
610
+ const fetch = async (input, init) => {
611
+ const response = await options.fetch(input, nativeSearchRequest(init, call));
612
+ if (!response.ok || !response.headers.get("content-type")?.includes("application/json")) return response;
613
+ const text = await response.text();
614
+ try {
615
+ original = JSON.parse(text);
616
+ } catch {
617
+ return new Response(text, response);
618
+ }
619
+ return new Response(JSON.stringify(project(original)), response);
620
+ };
621
+ const result = await factory(fetch).doGenerate(call);
622
+ const seen = /* @__PURE__ */ new Set();
623
+ const sources = sourceParts(original, seen);
624
+ return {
625
+ ...result,
626
+ content: [...result.content, ...sources],
627
+ request: result.request ? { ...result.request, body: nativeSearchBody(result.request.body, call) } : void 0,
628
+ response: { ...result.response, ...original === void 0 ? {} : { body: original } }
629
+ };
630
+ },
631
+ async doStream(call) {
632
+ const entries = /* @__PURE__ */ new Map();
633
+ let before = [];
634
+ const canceled = new AbortController();
635
+ const fetch = async (input, init) => {
636
+ const response = await options.fetch(input, nativeSearchRequest(init, call));
637
+ if (!response.ok || !response.headers.get("content-type")?.includes("text/event-stream")) return response;
638
+ const signal = init?.signal ? AbortSignal.any([init.signal, canceled.signal]) : canceled.signal;
639
+ const iterator = parseServerSentEvents(response, { signal });
640
+ const encoder = new TextEncoder();
641
+ const body = new ReadableStream({
642
+ async pull(controller) {
643
+ try {
644
+ while (true) {
645
+ const next = await iterator.next();
646
+ if (next.done) {
647
+ controller.close();
648
+ return;
649
+ }
650
+ const frame = next.value;
651
+ let native;
652
+ try {
653
+ native = JSON.parse(frame.data);
654
+ } catch {
655
+ controller.enqueue(encoder.encode(`${frame.event ? `event: ${frame.event}
656
+ ` : ""}data: ${frame.data}
657
+
658
+ `));
659
+ return;
660
+ }
661
+ if (object3(native).type === "response.output_text.annotation.added" && isUnpositionedCitation(object3(native).annotation)) {
662
+ before.push(native);
663
+ continue;
664
+ }
665
+ const projected = project(native);
666
+ const key = JSON.stringify(projected);
667
+ const queue = entries.get(key) ?? [];
668
+ queue.push({ original: native, before });
669
+ before = [];
670
+ entries.set(key, queue);
671
+ controller.enqueue(encoder.encode(`${frame.id ? `id: ${frame.id}
672
+ ` : ""}${frame.event ? `event: ${frame.event}
673
+ ` : ""}${frame.retry !== void 0 ? `retry: ${frame.retry}
674
+ ` : ""}data: ${key}
675
+
676
+ `));
677
+ return;
678
+ }
679
+ } catch (error) {
680
+ controller.error(error);
681
+ await iterator.return(void 0);
682
+ }
683
+ },
684
+ async cancel(reason) {
685
+ canceled.abort(reason);
686
+ await iterator.return(void 0);
687
+ }
688
+ });
689
+ return new Response(body, response);
690
+ };
691
+ const result = await factory(fetch).doStream({ ...call, includeRawChunks: true });
692
+ const seen = /* @__PURE__ */ new Set();
693
+ return {
694
+ ...result,
695
+ request: result.request ? { ...result.request, body: nativeSearchBody(result.request.body, call) } : void 0,
696
+ stream: result.stream.pipeThrough(new TransformStream({
697
+ transform(part, controller) {
698
+ if (part.type !== "raw") {
699
+ controller.enqueue(part);
700
+ return;
701
+ }
702
+ const key = JSON.stringify(part.rawValue);
703
+ const queue = entries.get(key);
704
+ const entry = queue?.shift();
705
+ if (queue?.length === 0) entries.delete(key);
706
+ const native = entry?.original ?? part.rawValue;
707
+ for (const frame of [...entry?.before ?? [], native]) {
708
+ for (const source of sourceParts(frame, seen)) controller.enqueue(source);
709
+ if (call.includeRawChunks) controller.enqueue({ type: "raw", rawValue: frame });
710
+ }
711
+ },
712
+ flush(controller) {
713
+ for (const frame of before) {
714
+ for (const source of sourceParts(frame, seen)) controller.enqueue(source);
715
+ if (call.includeRawChunks) controller.enqueue({ type: "raw", rawValue: frame });
716
+ }
717
+ entries.clear();
718
+ before = [];
719
+ }
720
+ }))
721
+ };
722
+ }
723
+ };
724
+ }
725
+ function sourceParts(value, seen) {
726
+ return citations(value).flatMap((annotation) => {
727
+ const key = JSON.stringify([annotation.url, annotation.title]);
728
+ if (seen.has(key)) return [];
729
+ seen.add(key);
730
+ return [{
731
+ type: "source",
732
+ sourceType: "url",
733
+ id: `native-source-${seen.size}`,
734
+ url: annotation.url,
735
+ ...typeof annotation.title === "string" ? { title: annotation.title } : {}
736
+ }];
737
+ });
738
+ }
739
+
531
740
  // src/language/index.ts
532
741
  function createNexraLanguageModel(modelId, options) {
533
742
  const binding = getLanguageModelBinding(modelId, options);
@@ -553,30 +762,30 @@ function createNexraLanguageModel(modelId, options) {
553
762
  input,
554
763
  typeof init?.body === "string" ? { ...init, body: JSON.stringify(explicitResponsesMessages(JSON.parse(init.body))) } : init
555
764
  );
556
- model = createOpenAI({ ...common, name: "nexra.openai", baseURL: `${root}/v1`, fetch: responsesFetch }).responses(binding.spec.id);
765
+ model = createResponsesLanguageModel({ modelId: binding.spec.id, apiKey, headers: common.headers, baseUrl: `${root}/v1`, fetch: responsesFetch });
557
766
  } else {
558
767
  model = createAnthropic({ ...common, name: "nexra.anthropic", baseURL: `${root}/v1` })(binding.spec.id);
559
768
  }
560
769
  return withNativeContract(model, binding);
561
770
  }
562
- function object3(value) {
771
+ function object4(value) {
563
772
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
564
773
  }
565
774
  function explicitResponsesMessages(value) {
566
- const body = object3(value);
775
+ const body = object4(value);
567
776
  if (!Array.isArray(body.input)) return value;
568
777
  return { ...body, input: body.input.map((value2) => {
569
- const item = object3(value2);
778
+ const item = object4(value2);
570
779
  return item.type === void 0 && ["system", "developer", "user", "assistant"].includes(String(item.role)) && (typeof item.content === "string" || Array.isArray(item.content)) ? { ...item, type: "message" } : value2;
571
780
  }) };
572
781
  }
573
782
  function googleNativeBody(binding, value) {
574
- const body = object3(value);
575
- const config = object3(body.generationConfig);
576
- const thinking = object3(config.thinkingConfig);
577
- const fields = object3(binding.endpoint.inputSchema?.properties);
578
- const nativeThinking = object3(object3(object3(object3(fields.generationConfig).properties).thinkingConfig).properties);
579
- const values = object3(nativeThinking.thinkingLevel).enum;
783
+ const body = object4(value);
784
+ const config = object4(body.generationConfig);
785
+ const thinking = object4(config.thinkingConfig);
786
+ const fields = object4(binding.endpoint.inputSchema?.properties);
787
+ const nativeThinking = object4(object4(object4(object4(fields.generationConfig).properties).thinkingConfig).properties);
788
+ const values = object4(nativeThinking.thinkingLevel).enum;
580
789
  const level = typeof thinking.thinkingLevel === "string" && Array.isArray(values) ? values.find((value2) => typeof value2 === "string" && value2.toLowerCase() === String(thinking.thinkingLevel).toLowerCase()) : void 0;
581
790
  return level === void 0 || level === thinking.thinkingLevel ? value : { ...body, generationConfig: { ...config, thinkingConfig: { ...thinking, thinkingLevel: level } } };
582
791
  }
@@ -584,25 +793,29 @@ function nativeRequest(binding, request, stream = false) {
584
793
  if (!request) return request;
585
794
  return binding.endpoint.protocol === "openai-responses" ? {
586
795
  ...request,
587
- body: explicitResponsesMessages(stream ? { ...object3(request.body), stream: true } : request.body)
796
+ body: explicitResponsesMessages(stream ? { ...object4(request.body), stream: true } : request.body)
588
797
  } : binding.endpoint.protocol === "gemini-generate-content" ? { ...request, body: googleNativeBody(binding, request.body) } : request;
589
798
  }
590
799
  function prepare(options, binding, stream) {
591
800
  binding = getLanguageModelBinding(binding.spec.id, { protocol: binding.endpoint.protocol, stream });
592
801
  options = prepareLanguageReasoning(options, binding);
593
- const properties = object3(binding.endpoint.inputSchema?.properties);
594
- const tokenField = object3(binding.endpoint.protocol === "gemini-generate-content" ? object3(object3(properties.generationConfig).properties).maxOutputTokens : properties.max_output_tokens ?? properties.max_tokens);
802
+ const properties = object4(binding.endpoint.inputSchema?.properties);
803
+ const choices2 = object4(properties.tool_choice).enum;
804
+ if (options.toolChoice && Array.isArray(choices2) && !choices2.includes(options.toolChoice.type)) {
805
+ throw new Error(`Nexra tool choice is outside the native contract for ${binding.spec.id}: ${options.toolChoice.type}`);
806
+ }
807
+ const tokenField = object4(binding.endpoint.protocol === "gemini-generate-content" ? object4(object4(properties.generationConfig).properties).maxOutputTokens : properties.max_output_tokens ?? properties.max_tokens);
595
808
  if (options.maxOutputTokens !== void 0 && (!Number.isInteger(options.maxOutputTokens) || typeof tokenField.minimum === "number" && options.maxOutputTokens < tokenField.minimum || binding.maxOutputTokens !== void 0 && options.maxOutputTokens > binding.maxOutputTokens)) throw new Error(`Nexra output token limit is outside the native contract for ${binding.spec.id}`);
596
809
  if (options.tools?.length && !binding.endpoint.capabilities.includes("tool_call")) throw new Error(`Nexra model does not support tools: ${binding.spec.id}`);
597
810
  const providerOptions = { ...options.providerOptions };
598
811
  if (binding.endpoint.protocol === "openai-responses") {
599
- const current = object3(providerOptions.openai);
812
+ const current = object4(providerOptions.openai);
600
813
  providerOptions.openai = {
601
814
  store: false,
602
815
  forceReasoning: binding.endpoint.capabilities.includes("reasoning"),
603
816
  ...current
604
817
  };
605
- const reasoning = object3(providerOptions.openai);
818
+ const reasoning = object4(providerOptions.openai);
606
819
  if (reasoning.forceReasoning === true && (options.temperature !== void 0 || options.topP !== void 0)) {
607
820
  throw new Error(`Nexra Responses adapter cannot preserve explicit sampling parameters with reasoning for ${binding.spec.id}`);
608
821
  }
@@ -612,8 +825,8 @@ function prepare(options, binding, stream) {
612
825
  }
613
826
  if (binding.endpoint.protocol === "anthropic-messages") {
614
827
  const capabilities = getAnthropicModelCapabilities(binding.spec.id);
615
- const native = { ...object3(providerOptions.anthropic), ...object3(providerOptions.nexra) };
616
- let thinking = object3(native.thinking);
828
+ const native = { ...object4(providerOptions.anthropic), ...object4(providerOptions.nexra) };
829
+ let thinking = object4(native.thinking);
617
830
  if (!native.thinking && native.effort == null && options.reasoning && options.reasoning !== "provider-default") {
618
831
  thinking = options.reasoning === "none" ? { type: "disabled" } : capabilities.supportsAdaptiveThinking ? { type: "adaptive" } : { type: "enabled", budgetTokens: mapReasoningToProviderBudget({
619
832
  reasoning: options.reasoning,
@@ -634,20 +847,20 @@ function prepare(options, binding, stream) {
634
847
  options = { ...options, maxOutputTokens: visible };
635
848
  }
636
849
  if (stream && binding.endpoint.protocol === "gemini-generate-content" && binding.endpoint.capabilities.includes("reasoning")) {
637
- const google = object3(providerOptions.google);
638
- providerOptions.google = { ...google, thinkingConfig: { includeThoughts: true, ...object3(google.thinkingConfig) } };
850
+ const google = object4(providerOptions.google);
851
+ providerOptions.google = { ...google, thinkingConfig: { includeThoughts: true, ...object4(google.thinkingConfig) } };
639
852
  }
640
853
  return { ...options, providerOptions };
641
854
  }
642
855
  function nativeUsage(protocol, value) {
643
- const payload = object3(value);
644
- const raw = protocol === "gemini-generate-content" ? payload.usageMetadata : protocol === "anthropic-messages" ? object3(payload.message).usage ?? payload.usage : object3(payload.response).usage ?? payload.usage;
856
+ const payload = object4(value);
857
+ const raw = protocol === "gemini-generate-content" ? payload.usageMetadata : protocol === "anthropic-messages" ? object4(payload.message).usage ?? payload.usage : object4(payload.response).usage ?? payload.usage;
645
858
  return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : void 0;
646
859
  }
647
860
  function mergeRecords(previous, next) {
648
861
  const merged = { ...previous, ...next };
649
862
  for (const [key, value] of Object.entries(next)) {
650
- if (value && typeof value === "object" && !Array.isArray(value)) merged[key] = { ...object3(previous?.[key]), ...object3(value) };
863
+ if (value && typeof value === "object" && !Array.isArray(value)) merged[key] = { ...object4(previous?.[key]), ...object4(value) };
651
864
  }
652
865
  return merged;
653
866
  }
@@ -681,8 +894,8 @@ function withNativeContract(model, binding) {
681
894
  stream: result.stream.pipeThrough(new TransformStream({
682
895
  transform(part, controller) {
683
896
  if (part.type === "raw") {
684
- const payload = object3(part.rawValue);
685
- terminal ||= binding.endpoint.protocol === "anthropic-messages" ? payload.type === "message_stop" : binding.endpoint.protocol === "openai-responses" ? ["response.completed", "response.incomplete", "response.failed"].includes(String(payload.type)) : Array.isArray(payload.candidates) && payload.candidates.some((candidate) => typeof object3(candidate).finishReason === "string");
897
+ const payload = object4(part.rawValue);
898
+ terminal ||= binding.endpoint.protocol === "anthropic-messages" ? payload.type === "message_stop" : binding.endpoint.protocol === "openai-responses" ? ["response.completed", "response.incomplete", "response.failed"].includes(String(payload.type)) : Array.isArray(payload.candidates) && payload.candidates.some((candidate) => typeof object4(candidate).finishReason === "string");
686
899
  const next = nativeUsage(binding.endpoint.protocol, part.rawValue);
687
900
  if (next) raw = mergeRecords(raw, next);
688
901
  if (options.includeRawChunks) controller.enqueue(part);