krutrim-ai-sdk 0.1.0

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.cjs ADDED
@@ -0,0 +1,1594 @@
1
+ 'use strict';
2
+
3
+ var providerUtils = require('@ai-sdk/provider-utils');
4
+ var zod = require('zod');
5
+ var provider = require('@ai-sdk/provider');
6
+
7
+ // src/provider.ts
8
+ var krutrimErrorDataSchema = zod.z.object({
9
+ error: zod.z.union([
10
+ zod.z.string(),
11
+ zod.z.object({
12
+ message: zod.z.string().optional(),
13
+ type: zod.z.string().optional(),
14
+ code: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
15
+ param: zod.z.string().nullable().optional()
16
+ })
17
+ ]).optional(),
18
+ message: zod.z.string().optional(),
19
+ status: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
20
+ detail: zod.z.object({
21
+ info: zod.z.string().optional()
22
+ }).passthrough().optional(),
23
+ // OpenAI-compatible sometimes nests differently
24
+ code: zod.z.union([zod.z.string(), zod.z.number()]).optional()
25
+ });
26
+ function extractRawMessage(data) {
27
+ if (typeof data.error === "string" && data.error.length > 0) {
28
+ return data.error;
29
+ }
30
+ if (data.error && typeof data.error === "object" && typeof data.error.message === "string" && data.error.message.length > 0) {
31
+ return data.error.message;
32
+ }
33
+ if (typeof data.message === "string" && data.message.length > 0) {
34
+ return data.message;
35
+ }
36
+ if (data.detail?.info) {
37
+ return data.detail.info;
38
+ }
39
+ return "Unknown Krutrim API error";
40
+ }
41
+ function enhanceKrutrimErrorMessage(rawMessage, statusCode) {
42
+ const lower = rawMessage.toLowerCase();
43
+ const tips = [];
44
+ if (statusCode === 401 || lower.includes("unauthorized") || lower.includes("invalid api key") || lower.includes("authentication") || lower.includes("api key")) {
45
+ tips.push(
46
+ "Check KRUTRIM_API_KEY or KRUTRIM_CLOUD_API_KEY (console: https://cloud.olakrutrim.com).",
47
+ "Keys can be regenerated under Key Management \u2192 Model API Keys."
48
+ );
49
+ }
50
+ if (statusCode === 403 || lower.includes("forbidden") || lower.includes("region")) {
51
+ tips.push(
52
+ "This model or endpoint may be restricted to supported regions / account tiers.",
53
+ "Confirm your Krutrim Cloud account has access in the console."
54
+ );
55
+ }
56
+ if (statusCode === 429 || lower.includes("rate limit") || lower.includes("too many requests") || lower.includes("quota")) {
57
+ tips.push(
58
+ "Rate limit or quota exceeded. Back off and retry with exponential delay.",
59
+ "Billing is typically INR-based on Krutrim Cloud \u2014 top up credits under Usage & Transactions if balance is low."
60
+ );
61
+ }
62
+ if (lower.includes("insufficient") || lower.includes("credit") || lower.includes("balance") || lower.includes("payment") || lower.includes("billing")) {
63
+ tips.push(
64
+ "Krutrim Cloud usage is billed in INR. Add credits at https://cloud.olakrutrim.com (Usage & Transactions)."
65
+ );
66
+ }
67
+ if (lower.includes("model") && (lower.includes("not found") || lower.includes("invalid") || lower.includes("does not exist") || lower.includes("unknown"))) {
68
+ tips.push(
69
+ "Copy the exact model string from the Model Catalogue (case-sensitive).",
70
+ 'Try aliases like "krutrim-2" \u2192 "Krutrim-2", or pass the catalogue ID directly.'
71
+ );
72
+ }
73
+ if (statusCode === 404) {
74
+ tips.push(
75
+ "Verify baseURL is https://cloud.olakrutrim.com/v1 for chat/embeddings.",
76
+ "Language Labs (Bhashik) uses https://cloud.olakrutrim.com/api/v1/..."
77
+ );
78
+ }
79
+ if (statusCode != null && statusCode >= 500) {
80
+ tips.push(
81
+ "Krutrim API returned a server error. Retry shortly; check status in the console if it persists."
82
+ );
83
+ }
84
+ if (tips.length === 0) {
85
+ return rawMessage;
86
+ }
87
+ return `${rawMessage}
88
+
89
+ \u{1F4A1} Krutrim tips:
90
+ ${tips.map((t) => ` \u2022 ${t}`).join("\n")}`;
91
+ }
92
+ var krutrimFailedResponseHandler = providerUtils.createJsonErrorResponseHandler({
93
+ errorSchema: krutrimErrorDataSchema,
94
+ errorToMessage: (data) => enhanceKrutrimErrorMessage(extractRawMessage(data))
95
+ });
96
+
97
+ // src/bhashik/language-detection.ts
98
+ var lidResponseSchema = zod.z.object({
99
+ status: zod.z.string().nullish(),
100
+ data: zod.z.array(
101
+ zod.z.object({
102
+ label: zod.z.string().nullish(),
103
+ value: zod.z.string().nullish()
104
+ })
105
+ ).nullish()
106
+ });
107
+ function extractUserText(options) {
108
+ const prompt = options.prompt;
109
+ if (typeof prompt === "string") {
110
+ return prompt;
111
+ }
112
+ if (!Array.isArray(prompt)) {
113
+ return "";
114
+ }
115
+ const parts = [];
116
+ for (const message of prompt) {
117
+ if (message.role === "user") {
118
+ for (const part of message.content) {
119
+ if (part.type === "text") {
120
+ parts.push(part.text);
121
+ }
122
+ }
123
+ }
124
+ }
125
+ return parts.join("\n");
126
+ }
127
+ var KrutrimLanguageDetectionModel = class {
128
+ constructor(config) {
129
+ this.specificationVersion = "v3";
130
+ this.modelId = "bhashik-language-detection";
131
+ this.config = config;
132
+ this.provider = config.provider;
133
+ }
134
+ get supportedUrls() {
135
+ return {};
136
+ }
137
+ async doGenerate(options) {
138
+ const query = extractUserText(options);
139
+ if (!query.trim()) {
140
+ throw new Error(
141
+ "Language detection requires a non-empty user prompt or message."
142
+ );
143
+ }
144
+ const {
145
+ responseHeaders,
146
+ value: response,
147
+ rawValue
148
+ } = await providerUtils.postJsonToApi({
149
+ url: this.config.languageLabsUrl("/languagelabs/language-detection"),
150
+ headers: providerUtils.combineHeaders(this.config.headers(), options.headers),
151
+ body: { query },
152
+ failedResponseHandler: krutrimFailedResponseHandler,
153
+ successfulResponseHandler: providerUtils.createJsonResponseHandler(lidResponseSchema),
154
+ abortSignal: options.abortSignal,
155
+ fetch: this.config.fetch
156
+ });
157
+ const primary = response.data?.[0];
158
+ const text = primary?.value ?? primary?.label ?? response.data?.map((d) => d.value ?? d.label).filter(Boolean).join(", ") ?? "unknown";
159
+ const content = [{ type: "text", text }];
160
+ return {
161
+ content,
162
+ finishReason: { unified: "stop", raw: "stop" },
163
+ usage: {
164
+ inputTokens: {
165
+ total: void 0,
166
+ noCache: void 0,
167
+ cacheRead: void 0,
168
+ cacheWrite: void 0
169
+ },
170
+ outputTokens: {
171
+ total: void 0,
172
+ text: void 0,
173
+ reasoning: void 0
174
+ }
175
+ },
176
+ providerMetadata: {
177
+ krutrim: {
178
+ detections: response.data ?? []
179
+ }
180
+ },
181
+ warnings: [
182
+ {
183
+ type: "other",
184
+ message: "languageDetection only analyzes prompt / user messages (not system or assistant)."
185
+ }
186
+ ],
187
+ request: { body: { query } },
188
+ response: {
189
+ headers: responseHeaders,
190
+ body: rawValue,
191
+ modelId: this.modelId,
192
+ timestamp: /* @__PURE__ */ new Date()
193
+ }
194
+ };
195
+ }
196
+ async doStream(options) {
197
+ const result = await this.doGenerate(options);
198
+ const text = result.content.find((c) => c.type === "text")?.type === "text" ? result.content.find((c) => c.type === "text").text : "";
199
+ const stream = new ReadableStream({
200
+ start(controller) {
201
+ controller.enqueue({ type: "stream-start", warnings: result.warnings });
202
+ controller.enqueue({ type: "text-start", id: "text-0" });
203
+ controller.enqueue({ type: "text-delta", id: "text-0", delta: text });
204
+ controller.enqueue({ type: "text-end", id: "text-0" });
205
+ controller.enqueue({
206
+ type: "finish",
207
+ finishReason: result.finishReason,
208
+ usage: result.usage,
209
+ providerMetadata: result.providerMetadata
210
+ });
211
+ controller.close();
212
+ }
213
+ });
214
+ return {
215
+ stream,
216
+ request: result.request,
217
+ response: result.response
218
+ };
219
+ }
220
+ };
221
+
222
+ // src/indic/languages.ts
223
+ var INDIC_LANGUAGES = [
224
+ {
225
+ code: "hi-IN",
226
+ bhashik: "hin",
227
+ name: "Hindi",
228
+ nativeName: "\u0939\u093F\u0928\u094D\u0926\u0940",
229
+ script: "Deva"
230
+ },
231
+ {
232
+ code: "bn-IN",
233
+ bhashik: "ben",
234
+ name: "Bengali",
235
+ nativeName: "\u09AC\u09BE\u0982\u09B2\u09BE",
236
+ script: "Beng"
237
+ },
238
+ {
239
+ code: "ta-IN",
240
+ bhashik: "tam",
241
+ name: "Tamil",
242
+ nativeName: "\u0BA4\u0BAE\u0BBF\u0BB4\u0BCD",
243
+ script: "Taml"
244
+ },
245
+ {
246
+ code: "te-IN",
247
+ bhashik: "tel",
248
+ name: "Telugu",
249
+ nativeName: "\u0C24\u0C46\u0C32\u0C41\u0C17\u0C41",
250
+ script: "Telu"
251
+ },
252
+ {
253
+ code: "mr-IN",
254
+ bhashik: "mar",
255
+ name: "Marathi",
256
+ nativeName: "\u092E\u0930\u093E\u0920\u0940",
257
+ script: "Deva"
258
+ },
259
+ {
260
+ code: "gu-IN",
261
+ bhashik: "guj",
262
+ name: "Gujarati",
263
+ nativeName: "\u0A97\u0AC1\u0A9C\u0AB0\u0ABE\u0AA4\u0AC0",
264
+ script: "Gujr"
265
+ },
266
+ {
267
+ code: "kn-IN",
268
+ bhashik: "kan",
269
+ name: "Kannada",
270
+ nativeName: "\u0C95\u0CA8\u0CCD\u0CA8\u0CA1",
271
+ script: "Knda"
272
+ },
273
+ {
274
+ code: "ml-IN",
275
+ bhashik: "mal",
276
+ name: "Malayalam",
277
+ nativeName: "\u0D2E\u0D32\u0D2F\u0D3E\u0D33\u0D02",
278
+ script: "Mlym"
279
+ },
280
+ {
281
+ code: "pa-IN",
282
+ bhashik: "pan",
283
+ name: "Punjabi",
284
+ nativeName: "\u0A2A\u0A70\u0A1C\u0A3E\u0A2C\u0A40",
285
+ script: "Guru"
286
+ },
287
+ {
288
+ code: "or-IN",
289
+ bhashik: null,
290
+ name: "Odia",
291
+ nativeName: "\u0B13\u0B21\u0B3C\u0B3F\u0B06",
292
+ script: "Orya",
293
+ notes: "Not all Bhashik endpoints list Odia yet."
294
+ },
295
+ {
296
+ code: "as-IN",
297
+ bhashik: null,
298
+ name: "Assamese",
299
+ nativeName: "\u0985\u09B8\u09AE\u09C0\u09AF\u09BC\u09BE",
300
+ script: "Beng"
301
+ },
302
+ {
303
+ code: "ur-IN",
304
+ bhashik: null,
305
+ name: "Urdu",
306
+ nativeName: "\u0627\u0631\u062F\u0648",
307
+ script: "Arab"
308
+ },
309
+ {
310
+ code: "en-IN",
311
+ bhashik: "eng",
312
+ name: "English (India)",
313
+ nativeName: "English",
314
+ script: "Latn"
315
+ },
316
+ {
317
+ code: "sa-IN",
318
+ bhashik: null,
319
+ name: "Sanskrit",
320
+ nativeName: "\u0938\u0902\u0938\u094D\u0915\u0943\u0924\u092E\u094D",
321
+ script: "Deva"
322
+ },
323
+ {
324
+ code: "ne-IN",
325
+ bhashik: null,
326
+ name: "Nepali",
327
+ nativeName: "\u0928\u0947\u092A\u093E\u0932\u0940",
328
+ script: "Deva"
329
+ }
330
+ ];
331
+ function toBhashikLanguageCode(code) {
332
+ const entry = INDIC_LANGUAGES.find(
333
+ (l) => l.code === code || l.bhashik === code
334
+ );
335
+ return entry?.bhashik ?? null;
336
+ }
337
+ function toTranslationLanguageCode(code) {
338
+ const entry = INDIC_LANGUAGES.find(
339
+ (l) => l.code === code || l.bhashik === code
340
+ );
341
+ if (!entry?.bhashik) {
342
+ if (code.includes("_")) return code;
343
+ throw new Error(
344
+ `No Bhashik/translation mapping for language "${code}". Use a supported code or pass an explicit tag like "hin_Deva".`
345
+ );
346
+ }
347
+ return `${entry.bhashik}_${entry.script}`;
348
+ }
349
+
350
+ // src/bhashik/speech-model.ts
351
+ var ttsResponseSchema = zod.z.object({
352
+ status: zod.z.string().nullish(),
353
+ data: zod.z.object({
354
+ audio_file: zod.z.string().nullish(),
355
+ // Some deployments may return base64 directly
356
+ audio: zod.z.string().nullish(),
357
+ audio_base64: zod.z.string().nullish()
358
+ }).nullish()
359
+ });
360
+ var KrutrimSpeechModel = class {
361
+ constructor(language, settings = {}, config) {
362
+ this.specificationVersion = "v3";
363
+ this.modelId = "Krutrim-TTS";
364
+ const mapped = toBhashikLanguageCode(language);
365
+ if (!mapped) {
366
+ if (["eng", "guj", "ben", "hin", "kan", "mal", "mar", "tam", "tel"].includes(
367
+ language
368
+ )) {
369
+ this.languageCode = language;
370
+ } else {
371
+ throw new Error(
372
+ `Unsupported TTS language "${language}". Use hi-IN, ta-IN, eng, hin, etc.`
373
+ );
374
+ }
375
+ } else {
376
+ this.languageCode = mapped;
377
+ }
378
+ this.settings = settings;
379
+ this.config = config;
380
+ }
381
+ get provider() {
382
+ return this.config.provider;
383
+ }
384
+ async doGenerate({
385
+ text,
386
+ headers,
387
+ abortSignal
388
+ }) {
389
+ const {
390
+ responseHeaders,
391
+ value: response,
392
+ rawValue
393
+ } = await providerUtils.postJsonToApi({
394
+ url: this.config.languageLabsUrl("/languagelabs/tts"),
395
+ headers: providerUtils.combineHeaders(this.config.headers(), headers),
396
+ body: {
397
+ input_text: text,
398
+ input_language: this.languageCode,
399
+ input_speaker: this.settings.speaker ?? "female"
400
+ },
401
+ failedResponseHandler: krutrimFailedResponseHandler,
402
+ successfulResponseHandler: providerUtils.createJsonResponseHandler(ttsResponseSchema),
403
+ abortSignal,
404
+ fetch: this.config.fetch
405
+ });
406
+ let audioData = response.data?.audio_base64 ?? response.data?.audio ?? void 0;
407
+ const audioUrl = response.data?.audio_file;
408
+ if (!audioData && audioUrl) {
409
+ const fetchFn = this.config.fetch ?? globalThis.fetch;
410
+ const audioResponse = await fetchFn(audioUrl, {
411
+ headers: this.config.headers(),
412
+ signal: abortSignal
413
+ });
414
+ if (!audioResponse.ok) {
415
+ throw new Error(
416
+ `Failed to download TTS audio from ${audioUrl}: ${audioResponse.status}`
417
+ );
418
+ }
419
+ const buffer = new Uint8Array(await audioResponse.arrayBuffer());
420
+ audioData = buffer;
421
+ }
422
+ if (!audioData) {
423
+ throw new Error(
424
+ "Krutrim TTS response did not include audio data or a downloadable audio_file URL."
425
+ );
426
+ }
427
+ return {
428
+ audio: audioData,
429
+ warnings: [],
430
+ response: {
431
+ headers: responseHeaders,
432
+ body: rawValue,
433
+ timestamp: /* @__PURE__ */ new Date(),
434
+ modelId: this.modelId
435
+ }
436
+ };
437
+ }
438
+ };
439
+ var sttResponseSchema = zod.z.object({
440
+ status: zod.z.string().nullish(),
441
+ data: zod.z.object({
442
+ text: zod.z.union([zod.z.array(zod.z.string()), zod.z.string()]).nullish()
443
+ }).nullish()
444
+ });
445
+ var KrutrimTranscriptionModel = class {
446
+ constructor(language, config) {
447
+ this.specificationVersion = "v3";
448
+ this.modelId = "Krutrim-Dhwani";
449
+ const mapped = toBhashikLanguageCode(language);
450
+ if (!mapped) {
451
+ if (["eng", "guj", "ben", "hin", "kan", "mal", "mar", "tam", "tel"].includes(
452
+ language
453
+ )) {
454
+ this.languageCode = language;
455
+ } else {
456
+ throw new Error(
457
+ `Unsupported STT language "${language}". Use hi-IN, ta-IN, eng, hin, etc.`
458
+ );
459
+ }
460
+ } else {
461
+ this.languageCode = mapped;
462
+ }
463
+ this.config = config;
464
+ }
465
+ get provider() {
466
+ return this.config.provider;
467
+ }
468
+ async doGenerate({
469
+ audio,
470
+ mediaType,
471
+ headers,
472
+ abortSignal
473
+ }) {
474
+ const formData = new FormData();
475
+ let blob;
476
+ if (typeof audio === "string") {
477
+ const binary = Buffer.from(audio, "base64");
478
+ blob = new Blob([binary], { type: mediaType ?? "audio/wav" });
479
+ } else {
480
+ blob = new Blob([audio], {
481
+ type: mediaType ?? "audio/wav"
482
+ });
483
+ }
484
+ formData.append("file", blob, "audio.wav");
485
+ formData.append("lang_code", this.languageCode);
486
+ const baseHeaders = { ...this.config.headers(), ...headers };
487
+ delete baseHeaders["Content-Type"];
488
+ delete baseHeaders["content-type"];
489
+ const {
490
+ responseHeaders,
491
+ value: response,
492
+ rawValue
493
+ } = await providerUtils.postToApi({
494
+ url: this.config.languageLabsUrl("/languagelabs/transcribe/upload"),
495
+ headers: providerUtils.combineHeaders(baseHeaders, void 0),
496
+ body: {
497
+ content: formData,
498
+ values: formData
499
+ },
500
+ failedResponseHandler: krutrimFailedResponseHandler,
501
+ successfulResponseHandler: providerUtils.createJsonResponseHandler(sttResponseSchema),
502
+ abortSignal,
503
+ fetch: this.config.fetch
504
+ });
505
+ const textField = response.data?.text;
506
+ const text = Array.isArray(textField) ? textField.join(" ") : textField ?? "";
507
+ return {
508
+ text,
509
+ segments: [],
510
+ language: this.languageCode,
511
+ durationInSeconds: void 0,
512
+ warnings: [],
513
+ response: {
514
+ headers: responseHeaders,
515
+ body: rawValue,
516
+ timestamp: /* @__PURE__ */ new Date(),
517
+ modelId: this.modelId
518
+ }
519
+ };
520
+ }
521
+ };
522
+ var translationResponseSchema = zod.z.object({
523
+ status: zod.z.string().nullish(),
524
+ data: zod.z.object({
525
+ translated_text: zod.z.string().nullish()
526
+ }).nullish()
527
+ });
528
+ function extractUserText2(options) {
529
+ const prompt = options.prompt;
530
+ if (!Array.isArray(prompt)) {
531
+ return "";
532
+ }
533
+ const parts = [];
534
+ for (const message of prompt) {
535
+ if (message.role === "user") {
536
+ for (const part of message.content) {
537
+ if (part.type === "text") {
538
+ parts.push(part.text);
539
+ }
540
+ }
541
+ }
542
+ }
543
+ return parts.join("\n");
544
+ }
545
+ var KrutrimTranslationModel = class {
546
+ constructor(settings, config) {
547
+ this.specificationVersion = "v3";
548
+ this.settings = settings;
549
+ this.config = config;
550
+ this.provider = config.provider;
551
+ this.modelId = settings.model ?? "krutrim-translate-v1.0";
552
+ }
553
+ get supportedUrls() {
554
+ return {};
555
+ }
556
+ async doGenerate(options) {
557
+ const text = extractUserText2(options);
558
+ if (!text.trim()) {
559
+ throw new Error("Translation requires a non-empty user prompt or message.");
560
+ }
561
+ const src = toTranslationLanguageCode(this.settings.from);
562
+ const tgt = toTranslationLanguageCode(this.settings.to);
563
+ const body = {
564
+ text,
565
+ src_language: src,
566
+ tgt_language: tgt,
567
+ model: this.modelId
568
+ };
569
+ const {
570
+ responseHeaders,
571
+ value: response,
572
+ rawValue
573
+ } = await providerUtils.postJsonToApi({
574
+ url: this.config.languageLabsUrl("/languagelabs/translation"),
575
+ headers: providerUtils.combineHeaders(this.config.headers(), options.headers),
576
+ body,
577
+ failedResponseHandler: krutrimFailedResponseHandler,
578
+ successfulResponseHandler: providerUtils.createJsonResponseHandler(
579
+ translationResponseSchema
580
+ ),
581
+ abortSignal: options.abortSignal,
582
+ fetch: this.config.fetch
583
+ });
584
+ const translated = response.data?.translated_text ?? "";
585
+ const content = [
586
+ { type: "text", text: translated }
587
+ ];
588
+ return {
589
+ content,
590
+ finishReason: { unified: "stop", raw: "stop" },
591
+ usage: {
592
+ inputTokens: {
593
+ total: void 0,
594
+ noCache: void 0,
595
+ cacheRead: void 0,
596
+ cacheWrite: void 0
597
+ },
598
+ outputTokens: {
599
+ total: void 0,
600
+ text: void 0,
601
+ reasoning: void 0
602
+ }
603
+ },
604
+ providerMetadata: {
605
+ krutrim: {
606
+ src_language: src,
607
+ tgt_language: tgt,
608
+ model: this.modelId
609
+ }
610
+ },
611
+ warnings: [
612
+ {
613
+ type: "other",
614
+ message: "translation only processes prompt / user messages (not system or assistant)."
615
+ }
616
+ ],
617
+ request: { body },
618
+ response: {
619
+ headers: responseHeaders,
620
+ body: rawValue,
621
+ modelId: this.modelId,
622
+ timestamp: /* @__PURE__ */ new Date()
623
+ }
624
+ };
625
+ }
626
+ async doStream(options) {
627
+ const result = await this.doGenerate(options);
628
+ const textPart = result.content.find((c) => c.type === "text");
629
+ const text = textPart && textPart.type === "text" ? textPart.text : "";
630
+ const stream = new ReadableStream({
631
+ start(controller) {
632
+ controller.enqueue({ type: "stream-start", warnings: result.warnings });
633
+ controller.enqueue({ type: "text-start", id: "text-0" });
634
+ controller.enqueue({ type: "text-delta", id: "text-0", delta: text });
635
+ controller.enqueue({ type: "text-end", id: "text-0" });
636
+ controller.enqueue({
637
+ type: "finish",
638
+ finishReason: result.finishReason,
639
+ usage: result.usage,
640
+ providerMetadata: result.providerMetadata
641
+ });
642
+ controller.close();
643
+ }
644
+ });
645
+ return {
646
+ stream,
647
+ request: result.request,
648
+ response: result.response
649
+ };
650
+ }
651
+ };
652
+
653
+ // src/models.ts
654
+ var KRUTRIM_CHAT_MODELS = {
655
+ /** Krutrim's flagship Indic-capable model (v1). */
656
+ krutrim1: "Krutrim-1",
657
+ /** Krutrim's next-generation text model. */
658
+ krutrim2: "Krutrim-2",
659
+ /** Lowercase alias accepted by many OpenAI-compatible samples. */
660
+ krutrim1Lower: "krutrim-1",
661
+ krutrim2Lower: "krutrim-2",
662
+ // Open models commonly hosted on Krutrim Cloud
663
+ llama33_70b: "Llama-3.3-70B-Instruct",
664
+ llama32_11b_vision: "Llama-3.2-11B-Vision-Instruct",
665
+ llama4_maverick: "Llama-4-Maverick-17B-128E-Instruct",
666
+ llama3_8b: "Meta-Llama-3-8B-Instruct",
667
+ mistral7b: "Mistral-7B-v0.2",
668
+ mistral7bInstruct: "Mistral-7B-Instruct",
669
+ qwen3_32b: "Qwen3-32B",
670
+ qwen3_30b: "Qwen3-30B-A3B",
671
+ phi4_reasoning: "Phi-4-reasoning-plus",
672
+ deepseekR1: "DeepSeek-R1",
673
+ deepseekR1_70b: "DeepSeek-R1-Distill-Llama-70B",
674
+ deepseekR1_8b: "DeepSeek-R1-Distill-Llama-8B",
675
+ gemma3_27b: "gemma-3-27b-it",
676
+ spectreV2: "Krutrim-spectre-v2"
677
+ };
678
+ var KRUTRIM_EMBEDDING_MODELS = {
679
+ /** Krutrim embedding model. */
680
+ vyakyarth: "Vyakyarth",
681
+ /** Alternative Krutrim embedding model. */
682
+ bhasantarit: "Bhasantarit"
683
+ };
684
+ var KRUTRIM_SPEECH_MODELS = {
685
+ /** Krutrim Speech-to-Text. */
686
+ dhwani: "Krutrim-Dhwani",
687
+ /** Krutrim Text-to-Speech. */
688
+ tts: "Krutrim-TTS"
689
+ };
690
+ var KRUTRIM_VISION_MODELS = {
691
+ chitrapathak: "chitrapathak",
692
+ llama32_11b_vision: "Llama-3.2-11B-Vision-Instruct",
693
+ llama4_maverick: "Llama-4-Maverick-17B-128E-Instruct",
694
+ gemma3_27b: "gemma-3-27b-it"
695
+ };
696
+ var MODEL_ALIASES = {
697
+ // Native Krutrim
698
+ krutrim: "Krutrim-2",
699
+ "krutrim-1": "Krutrim-1",
700
+ "krutrim-2": "Krutrim-2",
701
+ krutrim1: "Krutrim-1",
702
+ krutrim2: "Krutrim-2",
703
+ "Krutrim-1": "Krutrim-1",
704
+ "Krutrim-2": "Krutrim-2",
705
+ // Speech
706
+ dhwani: "Krutrim-Dhwani",
707
+ "krutrim-dhwani": "Krutrim-Dhwani",
708
+ "Krutrim-Dhwani": "Krutrim-Dhwani",
709
+ tts: "Krutrim-TTS",
710
+ "krutrim-tts": "Krutrim-TTS",
711
+ "Krutrim-TTS": "Krutrim-TTS",
712
+ // Embeddings
713
+ vyakyarth: "Vyakyarth",
714
+ Vyakyarth: "Vyakyarth",
715
+ bhasantarit: "Bhasantarit",
716
+ Bhasantarit: "Bhasantarit",
717
+ // Common open-model shortcuts
718
+ "llama-3.3-70b": "Llama-3.3-70B-Instruct",
719
+ "llama3.3-70b": "Llama-3.3-70B-Instruct",
720
+ "llama-3.2-11b-vision": "Llama-3.2-11B-Vision-Instruct",
721
+ "mistral-7b": "Mistral-7B-v0.2",
722
+ "deepseek-r1": "DeepSeek-R1",
723
+ "qwen3-32b": "Qwen3-32B",
724
+ "phi-4": "Phi-4-reasoning-plus"
725
+ };
726
+ function resolveModelId(modelId) {
727
+ return MODEL_ALIASES[modelId] ?? MODEL_ALIASES[modelId.toLowerCase()] ?? modelId;
728
+ }
729
+ function convertToChatMessages(prompt) {
730
+ const messages = [];
731
+ for (const message of prompt) {
732
+ switch (message.role) {
733
+ case "system": {
734
+ messages.push({ role: "system", content: message.content });
735
+ break;
736
+ }
737
+ case "user": {
738
+ if (message.content.length === 1 && message.content[0].type === "text") {
739
+ messages.push({
740
+ role: "user",
741
+ content: message.content[0].text
742
+ });
743
+ break;
744
+ }
745
+ messages.push({
746
+ role: "user",
747
+ content: message.content.map((part) => {
748
+ switch (part.type) {
749
+ case "text": {
750
+ return { type: "text", text: part.text };
751
+ }
752
+ case "file": {
753
+ let imageData;
754
+ if (typeof part.data === "string") {
755
+ if (part.data.startsWith("http://") || part.data.startsWith("https://") || part.data.startsWith("data:")) {
756
+ imageData = part.data;
757
+ } else {
758
+ imageData = `data:${part.mediaType};base64,${part.data}`;
759
+ }
760
+ } else if (part.data instanceof URL) {
761
+ imageData = part.data.toString();
762
+ } else {
763
+ imageData = `data:${part.mediaType};base64,${providerUtils.convertUint8ArrayToBase64(part.data)}`;
764
+ }
765
+ return {
766
+ type: "image_url",
767
+ image_url: { url: imageData }
768
+ };
769
+ }
770
+ default: {
771
+ const _exhaustive = part;
772
+ throw new provider.UnsupportedFunctionalityError({
773
+ functionality: `Unsupported content part type: ${JSON.stringify(_exhaustive)}`
774
+ });
775
+ }
776
+ }
777
+ })
778
+ });
779
+ break;
780
+ }
781
+ case "assistant": {
782
+ let text = "";
783
+ const toolCalls = [];
784
+ for (const part of message.content) {
785
+ switch (part.type) {
786
+ case "text": {
787
+ text += part.text;
788
+ break;
789
+ }
790
+ case "tool-call": {
791
+ toolCalls.push({
792
+ id: part.toolCallId,
793
+ type: "function",
794
+ function: {
795
+ name: part.toolName,
796
+ arguments: typeof part.input === "string" ? part.input : JSON.stringify(part.input)
797
+ }
798
+ });
799
+ break;
800
+ }
801
+ }
802
+ }
803
+ messages.push({
804
+ role: "assistant",
805
+ content: text || null,
806
+ tool_calls: toolCalls.length > 0 ? toolCalls : void 0
807
+ });
808
+ break;
809
+ }
810
+ case "tool": {
811
+ for (const part of message.content) {
812
+ if (part.type === "tool-result") {
813
+ messages.push({
814
+ role: "tool",
815
+ tool_call_id: part.toolCallId,
816
+ content: JSON.stringify(part.output)
817
+ });
818
+ }
819
+ }
820
+ break;
821
+ }
822
+ default: {
823
+ const _exhaustive = message;
824
+ throw new Error(`Unsupported role: ${JSON.stringify(_exhaustive)}`);
825
+ }
826
+ }
827
+ }
828
+ return messages;
829
+ }
830
+ function prepareTools({
831
+ tools,
832
+ toolChoice
833
+ }) {
834
+ const finalTools = tools?.length ? tools : void 0;
835
+ const toolWarnings = [];
836
+ if (finalTools == null) {
837
+ return { tools: void 0, tool_choice: void 0, toolWarnings };
838
+ }
839
+ const krutrimTools = [];
840
+ for (const tool of finalTools) {
841
+ if (tool.type === "provider") {
842
+ toolWarnings.push({ type: "unsupported", feature: tool.name });
843
+ } else {
844
+ krutrimTools.push({
845
+ type: "function",
846
+ function: {
847
+ name: tool.name,
848
+ description: tool.description,
849
+ parameters: tool.inputSchema
850
+ }
851
+ });
852
+ }
853
+ }
854
+ if (toolChoice == null) {
855
+ return { tools: krutrimTools, tool_choice: void 0, toolWarnings };
856
+ }
857
+ const type = toolChoice.type;
858
+ switch (type) {
859
+ case "auto":
860
+ case "none":
861
+ case "required":
862
+ return { tools: krutrimTools, tool_choice: type, toolWarnings };
863
+ case "tool":
864
+ return {
865
+ tools: krutrimTools,
866
+ tool_choice: {
867
+ type: "function",
868
+ function: { name: toolChoice.toolName }
869
+ },
870
+ toolWarnings
871
+ };
872
+ default: {
873
+ const _exhaustive = type;
874
+ throw new provider.UnsupportedFunctionalityError({
875
+ functionality: `Unsupported tool choice type: ${_exhaustive}`
876
+ });
877
+ }
878
+ }
879
+ }
880
+ var chatSettingsSchema = zod.z.object({
881
+ n: zod.z.number().min(1).max(128).nullish(),
882
+ user: zod.z.string().nullish(),
883
+ reasoningEffort: zod.z.enum(["low", "medium", "high"]).nullish(),
884
+ // snake_case passthrough for raw API fields if set via providerOptions
885
+ reasoning_effort: zod.z.enum(["low", "medium", "high"]).nullish()
886
+ });
887
+ var chatResponseSchema = zod.z.object({
888
+ id: zod.z.string().nullish(),
889
+ created: zod.z.number().nullish(),
890
+ model: zod.z.string().nullish(),
891
+ object: zod.z.string().nullish(),
892
+ system_fingerprint: zod.z.string().nullish(),
893
+ choices: zod.z.array(
894
+ zod.z.object({
895
+ index: zod.z.number(),
896
+ finish_reason: zod.z.string().nullish(),
897
+ logprobs: zod.z.object({}).nullish(),
898
+ message: zod.z.object({
899
+ content: zod.z.string().nullish(),
900
+ reasoning_content: zod.z.string().nullish(),
901
+ refusal: zod.z.string().nullish(),
902
+ role: zod.z.string().nullish(),
903
+ tool_calls: zod.z.array(
904
+ zod.z.object({
905
+ id: zod.z.string().nullish(),
906
+ type: zod.z.literal("function"),
907
+ function: zod.z.object({
908
+ name: zod.z.string(),
909
+ arguments: zod.z.string()
910
+ })
911
+ })
912
+ ).nullish()
913
+ })
914
+ })
915
+ ),
916
+ usage: zod.z.object({
917
+ completion_tokens: zod.z.number().nullish(),
918
+ prompt_tokens: zod.z.number().nullish(),
919
+ total_tokens: zod.z.number().nullish()
920
+ }).nullish()
921
+ });
922
+ var chatChunkSchema = zod.z.union([
923
+ zod.z.object({
924
+ id: zod.z.string().nullish(),
925
+ created: zod.z.number().nullish(),
926
+ model: zod.z.string().nullish(),
927
+ choices: zod.z.array(
928
+ zod.z.object({
929
+ delta: zod.z.object({
930
+ content: zod.z.string().nullish(),
931
+ reasoning: zod.z.string().nullish(),
932
+ reasoning_content: zod.z.string().nullish(),
933
+ role: zod.z.string().nullish(),
934
+ tool_calls: zod.z.array(
935
+ zod.z.object({
936
+ index: zod.z.number(),
937
+ id: zod.z.string().nullish(),
938
+ type: zod.z.literal("function").optional(),
939
+ function: zod.z.object({
940
+ name: zod.z.string().nullish(),
941
+ arguments: zod.z.string().nullish()
942
+ })
943
+ })
944
+ ).nullish()
945
+ }).nullish(),
946
+ finish_reason: zod.z.string().nullable().optional(),
947
+ index: zod.z.number()
948
+ })
949
+ ),
950
+ usage: zod.z.object({
951
+ prompt_tokens: zod.z.number().nullish(),
952
+ completion_tokens: zod.z.number().nullish(),
953
+ total_tokens: zod.z.number().nullish()
954
+ }).nullish()
955
+ }),
956
+ krutrimErrorDataSchema
957
+ ]);
958
+
959
+ // src/chat/utils.ts
960
+ function mapFinishReason(finishReason) {
961
+ switch (finishReason) {
962
+ case "stop":
963
+ return "stop";
964
+ case "length":
965
+ return "length";
966
+ case "content_filter":
967
+ return "content-filter";
968
+ case "function_call":
969
+ case "tool_calls":
970
+ return "tool-calls";
971
+ default:
972
+ return "other";
973
+ }
974
+ }
975
+ function getResponseMetadata({
976
+ id,
977
+ model,
978
+ created
979
+ }) {
980
+ return {
981
+ id: id ?? void 0,
982
+ modelId: model ?? void 0,
983
+ timestamp: created != null ? new Date(created * 1e3) : void 0
984
+ };
985
+ }
986
+
987
+ // src/chat/language-model.ts
988
+ var KrutrimChatLanguageModel = class {
989
+ constructor(modelId, settings, config) {
990
+ this.specificationVersion = "v3";
991
+ this.modelId = modelId;
992
+ this.resolvedModelId = resolveModelId(String(modelId));
993
+ this.settings = settings;
994
+ this.config = config;
995
+ }
996
+ get provider() {
997
+ return this.config.provider;
998
+ }
999
+ get supportedUrls() {
1000
+ return {
1001
+ "image/*": [/^https?:\/\/.+/i]
1002
+ };
1003
+ }
1004
+ async getArgs(options) {
1005
+ const {
1006
+ prompt,
1007
+ maxOutputTokens,
1008
+ temperature,
1009
+ topP,
1010
+ topK,
1011
+ frequencyPenalty,
1012
+ presencePenalty,
1013
+ stopSequences,
1014
+ responseFormat,
1015
+ seed,
1016
+ tools,
1017
+ toolChoice,
1018
+ providerOptions,
1019
+ stream
1020
+ } = options;
1021
+ const warnings = [];
1022
+ if (topK != null) {
1023
+ warnings.push({ type: "unsupported", feature: "topK" });
1024
+ }
1025
+ const krutrimOptions = await providerUtils.parseProviderOptions({
1026
+ provider: "krutrim",
1027
+ providerOptions: {
1028
+ krutrim: {
1029
+ ...providerOptions?.krutrim,
1030
+ ...this.settings
1031
+ }
1032
+ },
1033
+ schema: chatSettingsSchema
1034
+ });
1035
+ const reasoningEffort = krutrimOptions?.reasoningEffort ?? krutrimOptions?.reasoning_effort;
1036
+ const baseArgs = {
1037
+ model: this.resolvedModelId,
1038
+ messages: convertToChatMessages(prompt),
1039
+ max_tokens: maxOutputTokens,
1040
+ temperature,
1041
+ top_p: topP,
1042
+ frequency_penalty: frequencyPenalty,
1043
+ presence_penalty: presencePenalty,
1044
+ stop: stopSequences,
1045
+ seed,
1046
+ n: krutrimOptions?.n ?? void 0,
1047
+ user: krutrimOptions?.user ?? void 0,
1048
+ response_format: stream === false && responseFormat?.type === "json" ? responseFormat.schema ? {
1049
+ type: "json_schema",
1050
+ json_schema: {
1051
+ name: responseFormat.name ?? "response",
1052
+ description: responseFormat.description,
1053
+ schema: responseFormat.schema,
1054
+ strict: true
1055
+ }
1056
+ } : { type: "json_object" } : void 0
1057
+ };
1058
+ if (reasoningEffort) {
1059
+ baseArgs.reasoning_effort = reasoningEffort;
1060
+ }
1061
+ let toolsArg = null;
1062
+ if (tools && tools.length > 0) {
1063
+ toolsArg = prepareTools({ tools, toolChoice });
1064
+ }
1065
+ if (responseFormat?.type === "json" && responseFormat.schema) ;
1066
+ return {
1067
+ args: {
1068
+ ...baseArgs,
1069
+ ...toolsArg ? {
1070
+ tools: toolsArg.tools,
1071
+ tool_choice: toolsArg.tool_choice
1072
+ } : {}
1073
+ },
1074
+ warnings: [...warnings, ...toolsArg?.toolWarnings ?? []]
1075
+ };
1076
+ }
1077
+ async doGenerate(options) {
1078
+ const { args, warnings } = await this.getArgs({
1079
+ ...options,
1080
+ stream: false
1081
+ });
1082
+ const {
1083
+ responseHeaders,
1084
+ value: response,
1085
+ rawValue: rawResponse
1086
+ } = await providerUtils.postJsonToApi({
1087
+ url: this.config.url({
1088
+ path: "/chat/completions",
1089
+ modelId: this.resolvedModelId
1090
+ }),
1091
+ headers: providerUtils.combineHeaders(this.config.headers(), options.headers),
1092
+ body: args,
1093
+ failedResponseHandler: krutrimFailedResponseHandler,
1094
+ successfulResponseHandler: providerUtils.createJsonResponseHandler(chatResponseSchema),
1095
+ abortSignal: options.abortSignal,
1096
+ fetch: this.config.fetch
1097
+ });
1098
+ const choice = response.choices[0];
1099
+ if (!choice) {
1100
+ throw new provider.InvalidResponseDataError({
1101
+ data: response,
1102
+ message: "No choices returned in Krutrim chat completion response"
1103
+ });
1104
+ }
1105
+ const content = [];
1106
+ if (choice.message.content) {
1107
+ content.push({ type: "text", text: choice.message.content });
1108
+ }
1109
+ if (choice.message.reasoning_content) {
1110
+ content.push({ type: "reasoning", text: choice.message.reasoning_content });
1111
+ }
1112
+ if (choice.message.tool_calls?.length) {
1113
+ for (const toolCall of choice.message.tool_calls) {
1114
+ content.push({
1115
+ type: "tool-call",
1116
+ toolCallId: toolCall.id ?? (this.config.generateId ?? providerUtils.generateId)(),
1117
+ toolName: toolCall.function.name,
1118
+ input: toolCall.function.arguments
1119
+ });
1120
+ }
1121
+ }
1122
+ return {
1123
+ content,
1124
+ finishReason: {
1125
+ unified: mapFinishReason(choice.finish_reason),
1126
+ raw: choice.finish_reason ?? void 0
1127
+ },
1128
+ usage: {
1129
+ inputTokens: {
1130
+ total: response.usage?.prompt_tokens ?? void 0,
1131
+ noCache: void 0,
1132
+ cacheRead: void 0,
1133
+ cacheWrite: void 0
1134
+ },
1135
+ outputTokens: {
1136
+ total: response.usage?.completion_tokens ?? void 0,
1137
+ text: void 0,
1138
+ reasoning: void 0
1139
+ }
1140
+ },
1141
+ providerMetadata: {
1142
+ krutrim: {
1143
+ system_fingerprint: response.system_fingerprint,
1144
+ resolvedModelId: this.resolvedModelId
1145
+ }
1146
+ },
1147
+ warnings,
1148
+ request: { body: args },
1149
+ response: {
1150
+ headers: responseHeaders,
1151
+ body: rawResponse,
1152
+ id: response.id ?? void 0,
1153
+ modelId: response.model ?? void 0,
1154
+ timestamp: response.created ? new Date(response.created * 1e3) : void 0
1155
+ }
1156
+ };
1157
+ }
1158
+ async doStream(options) {
1159
+ const { args, warnings } = await this.getArgs({ ...options, stream: true });
1160
+ const { responseHeaders, value: response } = await providerUtils.postJsonToApi({
1161
+ url: this.config.url({
1162
+ path: "/chat/completions",
1163
+ modelId: this.resolvedModelId
1164
+ }),
1165
+ headers: providerUtils.combineHeaders(this.config.headers(), options.headers),
1166
+ body: { ...args, stream: true },
1167
+ failedResponseHandler: krutrimFailedResponseHandler,
1168
+ successfulResponseHandler: providerUtils.createEventSourceResponseHandler(chatChunkSchema),
1169
+ abortSignal: options.abortSignal,
1170
+ fetch: this.config.fetch
1171
+ });
1172
+ const toolCalls = [];
1173
+ let finishReason = {
1174
+ unified: "other",
1175
+ raw: void 0
1176
+ };
1177
+ let usage = {
1178
+ inputTokens: {
1179
+ total: void 0,
1180
+ noCache: void 0,
1181
+ cacheRead: void 0,
1182
+ cacheWrite: void 0
1183
+ },
1184
+ outputTokens: {
1185
+ total: void 0,
1186
+ text: void 0,
1187
+ reasoning: void 0
1188
+ }
1189
+ };
1190
+ let isFirstChunk = true;
1191
+ let textStarted = false;
1192
+ let reasoningStarted = false;
1193
+ const self = this;
1194
+ return {
1195
+ stream: response.pipeThrough(
1196
+ new TransformStream({
1197
+ start(controller) {
1198
+ controller.enqueue({ type: "stream-start", warnings });
1199
+ },
1200
+ transform(chunk, controller) {
1201
+ if (!chunk.success) {
1202
+ finishReason = { unified: "error", raw: void 0 };
1203
+ controller.enqueue({ type: "error", error: chunk.error });
1204
+ return;
1205
+ }
1206
+ const value = chunk.value;
1207
+ if ("error" in value && value.error != null && !("choices" in value)) {
1208
+ finishReason = { unified: "error", raw: void 0 };
1209
+ controller.enqueue({ type: "error", error: value.error });
1210
+ return;
1211
+ }
1212
+ if (!("choices" in value)) {
1213
+ return;
1214
+ }
1215
+ if (isFirstChunk) {
1216
+ isFirstChunk = false;
1217
+ const metadata = getResponseMetadata(value);
1218
+ if (metadata.id || metadata.timestamp || metadata.modelId) {
1219
+ controller.enqueue({ type: "response-metadata", ...metadata });
1220
+ }
1221
+ }
1222
+ if (value.usage != null) {
1223
+ usage = {
1224
+ inputTokens: {
1225
+ total: value.usage.prompt_tokens ?? void 0,
1226
+ noCache: void 0,
1227
+ cacheRead: void 0,
1228
+ cacheWrite: void 0
1229
+ },
1230
+ outputTokens: {
1231
+ total: value.usage.completion_tokens ?? void 0,
1232
+ text: void 0,
1233
+ reasoning: void 0
1234
+ }
1235
+ };
1236
+ }
1237
+ const choice = value.choices[0];
1238
+ if (choice?.finish_reason != null) {
1239
+ finishReason = {
1240
+ unified: mapFinishReason(choice.finish_reason),
1241
+ raw: choice.finish_reason
1242
+ };
1243
+ }
1244
+ if (choice?.delta == null) {
1245
+ return;
1246
+ }
1247
+ const delta = choice.delta;
1248
+ const reasoningText = delta.reasoning ?? delta.reasoning_content;
1249
+ if (reasoningText != null && reasoningText.length > 0) {
1250
+ if (!reasoningStarted) {
1251
+ reasoningStarted = true;
1252
+ controller.enqueue({
1253
+ type: "reasoning-start",
1254
+ id: "reasoning-0"
1255
+ });
1256
+ }
1257
+ controller.enqueue({
1258
+ type: "reasoning-delta",
1259
+ id: "reasoning-0",
1260
+ delta: reasoningText
1261
+ });
1262
+ }
1263
+ if (delta.content != null && delta.content.length > 0) {
1264
+ if (!textStarted) {
1265
+ textStarted = true;
1266
+ controller.enqueue({ type: "text-start", id: "text-0" });
1267
+ }
1268
+ controller.enqueue({
1269
+ type: "text-delta",
1270
+ id: "text-0",
1271
+ delta: delta.content
1272
+ });
1273
+ }
1274
+ if (delta.tool_calls != null) {
1275
+ for (const toolCallDelta of delta.tool_calls) {
1276
+ const index = toolCallDelta.index;
1277
+ if (toolCalls[index] == null) {
1278
+ if (toolCallDelta.id == null) {
1279
+ throw new provider.InvalidResponseDataError({
1280
+ data: toolCallDelta,
1281
+ message: `Expected tool call 'id' to be a string.`
1282
+ });
1283
+ }
1284
+ if (toolCallDelta.function?.name == null) {
1285
+ throw new provider.InvalidResponseDataError({
1286
+ data: toolCallDelta,
1287
+ message: `Expected tool call 'function.name' to be a string.`
1288
+ });
1289
+ }
1290
+ toolCalls[index] = {
1291
+ id: toolCallDelta.id,
1292
+ name: toolCallDelta.function.name,
1293
+ arguments: toolCallDelta.function.arguments ?? "",
1294
+ hasFinished: false
1295
+ };
1296
+ const toolCall2 = toolCalls[index];
1297
+ controller.enqueue({
1298
+ type: "tool-input-start",
1299
+ id: toolCall2.id,
1300
+ toolName: toolCall2.name
1301
+ });
1302
+ if (toolCall2.arguments.length > 0) {
1303
+ controller.enqueue({
1304
+ type: "tool-input-delta",
1305
+ id: toolCall2.id,
1306
+ delta: toolCall2.arguments
1307
+ });
1308
+ }
1309
+ if (providerUtils.isParsableJson(toolCall2.arguments)) {
1310
+ controller.enqueue({
1311
+ type: "tool-input-end",
1312
+ id: toolCall2.id
1313
+ });
1314
+ controller.enqueue({
1315
+ type: "tool-call",
1316
+ toolCallId: toolCall2.id,
1317
+ toolName: toolCall2.name,
1318
+ input: toolCall2.arguments
1319
+ });
1320
+ toolCall2.hasFinished = true;
1321
+ }
1322
+ continue;
1323
+ }
1324
+ const toolCall = toolCalls[index];
1325
+ if (toolCall.hasFinished) continue;
1326
+ if (toolCallDelta.function?.arguments != null) {
1327
+ toolCall.arguments += toolCallDelta.function.arguments;
1328
+ controller.enqueue({
1329
+ type: "tool-input-delta",
1330
+ id: toolCall.id,
1331
+ delta: toolCallDelta.function.arguments
1332
+ });
1333
+ }
1334
+ if (toolCall.name != null && toolCall.arguments != null && providerUtils.isParsableJson(toolCall.arguments)) {
1335
+ controller.enqueue({
1336
+ type: "tool-input-end",
1337
+ id: toolCall.id
1338
+ });
1339
+ controller.enqueue({
1340
+ type: "tool-call",
1341
+ toolCallId: toolCall.id,
1342
+ toolName: toolCall.name,
1343
+ input: toolCall.arguments
1344
+ });
1345
+ toolCall.hasFinished = true;
1346
+ }
1347
+ }
1348
+ }
1349
+ },
1350
+ flush(controller) {
1351
+ if (reasoningStarted) {
1352
+ controller.enqueue({ type: "reasoning-end", id: "reasoning-0" });
1353
+ }
1354
+ if (textStarted) {
1355
+ controller.enqueue({ type: "text-end", id: "text-0" });
1356
+ }
1357
+ controller.enqueue({
1358
+ type: "finish",
1359
+ finishReason,
1360
+ usage,
1361
+ providerMetadata: {
1362
+ krutrim: {
1363
+ resolvedModelId: self.resolvedModelId
1364
+ }
1365
+ }
1366
+ });
1367
+ }
1368
+ })
1369
+ ),
1370
+ request: { body: args },
1371
+ response: { headers: responseHeaders }
1372
+ };
1373
+ }
1374
+ };
1375
+
1376
+ // src/config.ts
1377
+ var KRUTRIM_DEFAULT_BASE_URL = "https://cloud.olakrutrim.com/v1";
1378
+ var KRUTRIM_DEFAULT_API_HOST = "https://cloud.olakrutrim.com";
1379
+ function resolveKrutrimApiKey(apiKey) {
1380
+ if (apiKey && apiKey.trim().length > 0) {
1381
+ return apiKey;
1382
+ }
1383
+ if (typeof process === "undefined" || !process.env) {
1384
+ return void 0;
1385
+ }
1386
+ return process.env.KRUTRIM_API_KEY?.trim() || process.env.KRUTRIM_CLOUD_API_KEY?.trim() || void 0;
1387
+ }
1388
+ var embeddingResponseSchema = zod.z.object({
1389
+ object: zod.z.string().nullish(),
1390
+ data: zod.z.array(
1391
+ zod.z.object({
1392
+ object: zod.z.string().nullish(),
1393
+ embedding: zod.z.array(zod.z.number()),
1394
+ index: zod.z.number()
1395
+ })
1396
+ ),
1397
+ model: zod.z.string().nullish(),
1398
+ usage: zod.z.object({
1399
+ prompt_tokens: zod.z.number().nullish(),
1400
+ total_tokens: zod.z.number().nullish()
1401
+ }).nullish()
1402
+ });
1403
+ var KrutrimEmbeddingModel = class {
1404
+ constructor(modelId, config) {
1405
+ this.specificationVersion = "v3";
1406
+ this.maxEmbeddingsPerCall = 32;
1407
+ this.supportsParallelCalls = true;
1408
+ this.modelId = modelId;
1409
+ this.resolvedModelId = resolveModelId(modelId);
1410
+ this.config = config;
1411
+ }
1412
+ get provider() {
1413
+ return this.config.provider;
1414
+ }
1415
+ async doEmbed({
1416
+ values,
1417
+ headers,
1418
+ abortSignal,
1419
+ providerOptions
1420
+ }) {
1421
+ const krutrimOptions = providerOptions?.krutrim;
1422
+ const {
1423
+ responseHeaders,
1424
+ value: response,
1425
+ rawValue
1426
+ } = await providerUtils.postJsonToApi({
1427
+ url: this.config.url({
1428
+ path: "/embeddings",
1429
+ modelId: this.resolvedModelId
1430
+ }),
1431
+ headers: providerUtils.combineHeaders(this.config.headers(), headers),
1432
+ body: {
1433
+ model: this.resolvedModelId,
1434
+ input: values,
1435
+ dimensions: krutrimOptions?.dimensions,
1436
+ user: krutrimOptions?.user
1437
+ },
1438
+ failedResponseHandler: krutrimFailedResponseHandler,
1439
+ successfulResponseHandler: providerUtils.createJsonResponseHandler(embeddingResponseSchema),
1440
+ abortSignal,
1441
+ fetch: this.config.fetch
1442
+ });
1443
+ return {
1444
+ embeddings: response.data.slice().sort((a, b) => a.index - b.index).map((item) => item.embedding),
1445
+ usage: response.usage?.total_tokens ? { tokens: response.usage.total_tokens } : void 0,
1446
+ warnings: [],
1447
+ response: { headers: responseHeaders, body: rawValue }
1448
+ };
1449
+ }
1450
+ };
1451
+
1452
+ // src/provider.ts
1453
+ function createKrutrim(options = {}) {
1454
+ const baseURL = providerUtils.withoutTrailingSlash(options.baseURL) ?? KRUTRIM_DEFAULT_BASE_URL;
1455
+ const apiHost = providerUtils.withoutTrailingSlash(options.apiHost) ?? KRUTRIM_DEFAULT_API_HOST;
1456
+ const getApiKey = () => {
1457
+ const resolved = resolveKrutrimApiKey(options.apiKey);
1458
+ return providerUtils.loadApiKey({
1459
+ apiKey: resolved,
1460
+ environmentVariableName: "KRUTRIM_API_KEY",
1461
+ description: "Krutrim Cloud"
1462
+ });
1463
+ };
1464
+ const getHeaders = () => {
1465
+ const apiKey = getApiKey();
1466
+ return {
1467
+ Authorization: `Bearer ${apiKey}`,
1468
+ "User-Agent": "krutrim-ai-sdk",
1469
+ ...options.headers
1470
+ };
1471
+ };
1472
+ const sharedConfig = {
1473
+ headers: getHeaders,
1474
+ fetch: options.fetch,
1475
+ generateId: options.generateId ?? providerUtils.generateId,
1476
+ url: ({ path }) => `${baseURL}${path}`,
1477
+ languageLabsUrl: (path) => {
1478
+ const normalized = path.startsWith("/") ? path : `/${path}`;
1479
+ return `${apiHost}/api/v1${normalized}`;
1480
+ }
1481
+ };
1482
+ const createChatModel = (modelId, settings = {}) => new KrutrimChatLanguageModel(modelId, settings, {
1483
+ ...sharedConfig,
1484
+ provider: "krutrim.chat"
1485
+ });
1486
+ const createLanguageModel = (modelId, settings) => {
1487
+ if (new.target) {
1488
+ throw new Error(
1489
+ "The Krutrim model function cannot be called with the new keyword."
1490
+ );
1491
+ }
1492
+ return createChatModel(modelId, settings);
1493
+ };
1494
+ const createEmbeddingModel = (modelId) => new KrutrimEmbeddingModel(modelId, {
1495
+ ...sharedConfig,
1496
+ provider: "krutrim.embedding"
1497
+ });
1498
+ const provider = ((modelId, settings) => createLanguageModel(modelId, settings));
1499
+ provider.languageModel = createLanguageModel;
1500
+ provider.chat = createChatModel;
1501
+ provider.embedding = createEmbeddingModel;
1502
+ provider.embeddingModel = createEmbeddingModel;
1503
+ provider.textEmbeddingModel = createEmbeddingModel;
1504
+ provider.speech = (language, settings) => new KrutrimSpeechModel(language, settings ?? {}, {
1505
+ ...sharedConfig,
1506
+ provider: "krutrim.speech"
1507
+ });
1508
+ provider.transcription = (language) => new KrutrimTranscriptionModel(language, {
1509
+ ...sharedConfig,
1510
+ provider: "krutrim.transcription"
1511
+ });
1512
+ provider.languageDetection = () => new KrutrimLanguageDetectionModel({
1513
+ ...sharedConfig,
1514
+ provider: "krutrim.language-detection"
1515
+ });
1516
+ provider.translation = (settings) => new KrutrimTranslationModel(settings, {
1517
+ ...sharedConfig,
1518
+ provider: "krutrim.translation"
1519
+ });
1520
+ return provider;
1521
+ }
1522
+ var krutrim = createKrutrim();
1523
+
1524
+ // src/indic/prompts.ts
1525
+ function languageLabel(code) {
1526
+ const entry = INDIC_LANGUAGES.find((l) => l.code === code);
1527
+ if (entry) {
1528
+ return `${entry.name} (${entry.nativeName})`;
1529
+ }
1530
+ return code;
1531
+ }
1532
+ function indicResponsePrompt(language, options) {
1533
+ const nativeScript = options?.nativeScript ?? true;
1534
+ const allowCodeMix = options?.allowCodeMix ?? false;
1535
+ const label = languageLabel(language);
1536
+ return [
1537
+ `You are a helpful assistant optimized for Indian languages and culture.`,
1538
+ `Respond primarily in ${label}.`,
1539
+ nativeScript ? `Prefer the language's native script over Latin transliteration unless the user writes in Latin script and clearly wants Romanized output.` : `Latin / Romanized script is acceptable when natural for the user.`,
1540
+ allowCodeMix ? `Light code-mixing with English is fine when it matches how speakers actually talk.` : `Avoid unnecessary English code-mixing unless the user does so first.`,
1541
+ `Be culturally aware of Indian context (festivals, geography, INR, regional nuance) without stereotyping.`
1542
+ ].join(" ");
1543
+ }
1544
+ function languageDetectionPrompt() {
1545
+ return [
1546
+ "Identify the primary language of the user message.",
1547
+ "Reply with ONLY a BCP-47 language tag such as hi-IN, ta-IN, en-IN, bn-IN, ml-IN.",
1548
+ "If mixed, pick the dominant language. No explanation."
1549
+ ].join(" ");
1550
+ }
1551
+ function transliterationNotes(targetLanguage) {
1552
+ const target = targetLanguage ? ` When responding, prefer native script for ${languageLabel(targetLanguage)} unless asked otherwise.` : "";
1553
+ return [
1554
+ 'Users may type Indian languages in Latin script (e.g. Hinglish: "aap kaise ho", Tanglish, etc.).',
1555
+ "Interpret Romanized Indic phonetically; do not treat it as English only.",
1556
+ "When the meaning is clear, reply in the same language; offer native script when helpful.",
1557
+ target
1558
+ ].join(" ").trim();
1559
+ }
1560
+ function indicSupportAgentPrompt(options) {
1561
+ const brand = options?.brandName ?? "our service";
1562
+ const langs = options?.languages?.map(languageLabel).join(", ") ?? "Hindi, English (India), and other major Indian languages";
1563
+ return [
1564
+ `You are a polite, efficient customer support agent for ${brand}.`,
1565
+ `You can assist in: ${langs}.`,
1566
+ `Mirror the customer's language and script when possible.`,
1567
+ `Keep answers clear, short, and actionable. Amounts should use \u20B9 / INR when relevant.`,
1568
+ `If you are unsure, ask a clarifying question instead of guessing personal data.`
1569
+ ].join(" ");
1570
+ }
1571
+
1572
+ exports.INDIC_LANGUAGES = INDIC_LANGUAGES;
1573
+ exports.KRUTRIM_CHAT_MODELS = KRUTRIM_CHAT_MODELS;
1574
+ exports.KRUTRIM_DEFAULT_API_HOST = KRUTRIM_DEFAULT_API_HOST;
1575
+ exports.KRUTRIM_DEFAULT_BASE_URL = KRUTRIM_DEFAULT_BASE_URL;
1576
+ exports.KRUTRIM_EMBEDDING_MODELS = KRUTRIM_EMBEDDING_MODELS;
1577
+ exports.KRUTRIM_SPEECH_MODELS = KRUTRIM_SPEECH_MODELS;
1578
+ exports.KRUTRIM_VISION_MODELS = KRUTRIM_VISION_MODELS;
1579
+ exports.MODEL_ALIASES = MODEL_ALIASES;
1580
+ exports.createKrutrim = createKrutrim;
1581
+ exports.enhanceKrutrimErrorMessage = enhanceKrutrimErrorMessage;
1582
+ exports.indicResponsePrompt = indicResponsePrompt;
1583
+ exports.indicSupportAgentPrompt = indicSupportAgentPrompt;
1584
+ exports.krutrim = krutrim;
1585
+ exports.krutrimErrorDataSchema = krutrimErrorDataSchema;
1586
+ exports.krutrimFailedResponseHandler = krutrimFailedResponseHandler;
1587
+ exports.languageDetectionPrompt = languageDetectionPrompt;
1588
+ exports.resolveKrutrimApiKey = resolveKrutrimApiKey;
1589
+ exports.resolveModelId = resolveModelId;
1590
+ exports.toBhashikLanguageCode = toBhashikLanguageCode;
1591
+ exports.toTranslationLanguageCode = toTranslationLanguageCode;
1592
+ exports.transliterationNotes = transliterationNotes;
1593
+ //# sourceMappingURL=index.cjs.map
1594
+ //# sourceMappingURL=index.cjs.map