@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.
- package/README.md +86 -0
- package/dist/catalog.d.ts +2 -2
- package/dist/catalog.js +2 -2
- package/dist/{chunk-OX5GFYVN.js → chunk-7MNUV5BJ.js} +12897 -7330
- package/dist/{chunk-FEACXUHZ.js → chunk-LXR3MEF3.js} +55 -8
- package/dist/index.d.ts +5 -5
- package/dist/index.js +2 -2
- package/dist/language.d.ts +1 -1
- package/dist/language.js +241 -28
- package/dist/{media-CwGmG5qB.d.ts → media-Co8S2qEM.d.ts} +36 -7
- package/dist/{media-geometry-KwQh1O8Y.d.ts → media-geometry-BS4DZh4B.d.ts} +2 -0
- package/dist/media.d.ts +1 -1
- package/dist/media.js +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/{voices-B09HqQJJ.d.ts → voices-Bzt4nV1r.d.ts} +4 -2
- package/package.json +1 -1
|
@@ -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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
30
|
+
} from "./chunk-LXR3MEF3.js";
|
|
31
31
|
|
|
32
32
|
// src/assets.ts
|
|
33
33
|
var AssetsClient = class {
|
package/dist/language.d.ts
CHANGED
|
@@ -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-
|
|
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-
|
|
9
|
+
} from "./chunk-7MNUV5BJ.js";
|
|
10
10
|
import {
|
|
11
11
|
isPublicErrorCode,
|
|
12
12
|
publicErrorMessage,
|
|
13
13
|
resolvePublicErrorLocale
|
|
14
|
-
} from "./chunk-
|
|
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:
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
575
|
-
const config =
|
|
576
|
-
const thinking =
|
|
577
|
-
const fields =
|
|
578
|
-
const nativeThinking =
|
|
579
|
-
const values =
|
|
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 ? { ...
|
|
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 =
|
|
594
|
-
const
|
|
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 =
|
|
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 =
|
|
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 = { ...
|
|
616
|
-
let 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 =
|
|
638
|
-
providerOptions.google = { ...google, thinkingConfig: { includeThoughts: true, ...
|
|
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 =
|
|
644
|
-
const raw = protocol === "gemini-generate-content" ? payload.usageMetadata : protocol === "anthropic-messages" ?
|
|
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] = { ...
|
|
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 =
|
|
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
|
|
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);
|