@friendliai/ai-provider 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,1255 @@
1
+ // src/friendliai-facade.ts
2
+ import { loadApiKey, withoutTrailingSlash } from "@ai-sdk/provider-utils";
3
+
4
+ // src/friendliai-chat-language-model.ts
5
+ import {
6
+ InvalidResponseDataError,
7
+ UnsupportedFunctionalityError as UnsupportedFunctionalityError2
8
+ } from "@ai-sdk/provider";
9
+ import {
10
+ combineHeaders,
11
+ createEventSourceResponseHandler,
12
+ createJsonResponseHandler,
13
+ generateId,
14
+ isParsableJson,
15
+ postJsonToApi
16
+ } from "@ai-sdk/provider-utils";
17
+ import { z as z2 } from "zod";
18
+
19
+ // src/convert-to-friendliai-chat-messages.ts
20
+ import {
21
+ UnsupportedFunctionalityError
22
+ } from "@ai-sdk/provider";
23
+ function convertToFriendliAIChatMessages({
24
+ prompt,
25
+ useLegacyFunctionCalling = false
26
+ }) {
27
+ const messages = [];
28
+ for (const { role, content } of prompt) {
29
+ switch (role) {
30
+ case "system": {
31
+ messages.push({ role: "system", content });
32
+ break;
33
+ }
34
+ case "user": {
35
+ if (content.length === 1 && content[0].type === "text") {
36
+ messages.push({ role: "user", content: content[0].text });
37
+ break;
38
+ }
39
+ messages.push({
40
+ role: "user",
41
+ content: content.map((part) => {
42
+ switch (part.type) {
43
+ case "text": {
44
+ return { type: "text", text: part.text };
45
+ }
46
+ case "image": {
47
+ throw new UnsupportedFunctionalityError({
48
+ functionality: "image-part"
49
+ });
50
+ }
51
+ }
52
+ })
53
+ });
54
+ break;
55
+ }
56
+ case "assistant": {
57
+ let text = "";
58
+ const toolCalls = [];
59
+ for (const part of content) {
60
+ switch (part.type) {
61
+ case "text": {
62
+ text += part.text;
63
+ break;
64
+ }
65
+ case "tool-call": {
66
+ toolCalls.push({
67
+ id: part.toolCallId,
68
+ type: "function",
69
+ function: {
70
+ name: part.toolName,
71
+ arguments: JSON.stringify(part.args)
72
+ }
73
+ });
74
+ break;
75
+ }
76
+ default: {
77
+ const _exhaustiveCheck = part;
78
+ throw new Error(`Unsupported part: ${_exhaustiveCheck}`);
79
+ }
80
+ }
81
+ }
82
+ if (useLegacyFunctionCalling) {
83
+ if (toolCalls.length > 1) {
84
+ throw new UnsupportedFunctionalityError({
85
+ functionality: "useLegacyFunctionCalling with multiple tool calls in one message"
86
+ });
87
+ }
88
+ messages.push({
89
+ role: "assistant",
90
+ content: text,
91
+ function_call: toolCalls.length > 0 ? toolCalls[0].function : void 0
92
+ });
93
+ } else {
94
+ messages.push({
95
+ role: "assistant",
96
+ content: text,
97
+ tool_calls: toolCalls.length > 0 ? toolCalls : void 0
98
+ });
99
+ }
100
+ break;
101
+ }
102
+ case "tool": {
103
+ for (const toolResponse of content) {
104
+ if (useLegacyFunctionCalling) {
105
+ messages.push({
106
+ role: "function",
107
+ name: toolResponse.toolName,
108
+ content: JSON.stringify(toolResponse.result)
109
+ });
110
+ } else {
111
+ messages.push({
112
+ role: "tool",
113
+ tool_call_id: toolResponse.toolCallId,
114
+ content: JSON.stringify(toolResponse.result)
115
+ });
116
+ }
117
+ }
118
+ break;
119
+ }
120
+ default: {
121
+ const _exhaustiveCheck = role;
122
+ throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
123
+ }
124
+ }
125
+ }
126
+ return messages;
127
+ }
128
+
129
+ // src/map-friendliai-chat-logprobs.ts
130
+ function mapFriendliAIChatLogProbsOutput(logprobs) {
131
+ var _a, _b;
132
+ return (_b = (_a = logprobs == null ? void 0 : logprobs.content) == null ? void 0 : _a.map(({ token, logprob, top_logprobs }) => ({
133
+ token,
134
+ logprob,
135
+ topLogprobs: top_logprobs ? top_logprobs.map(({ token: token2, logprob: logprob2 }) => ({
136
+ token: token2,
137
+ logprob: logprob2
138
+ })) : []
139
+ }))) != null ? _b : void 0;
140
+ }
141
+
142
+ // src/map-friendliai-finish-reason.ts
143
+ function mapFriendliAIFinishReason(finishReason) {
144
+ switch (finishReason) {
145
+ case "stop":
146
+ return "stop";
147
+ case "length":
148
+ return "length";
149
+ case "content_filter":
150
+ return "content-filter";
151
+ case "function_call":
152
+ case "tool_calls":
153
+ return "tool-calls";
154
+ default:
155
+ return "unknown";
156
+ }
157
+ }
158
+
159
+ // src/friendliai-error.ts
160
+ import { z } from "zod";
161
+ import { createJsonErrorResponseHandler } from "@ai-sdk/provider-utils";
162
+ var friendliAIErrorDataSchema = z.object({
163
+ error: z.object({
164
+ message: z.string(),
165
+ // The additional information below is handled loosely to support
166
+ // FriendliAI-compatible providers that have slightly different error
167
+ // responses:
168
+ type: z.string().nullish(),
169
+ param: z.any().nullish(),
170
+ code: z.union([z.string(), z.number()]).nullish()
171
+ })
172
+ });
173
+ var friendliaiFailedResponseHandler = createJsonErrorResponseHandler({
174
+ errorSchema: friendliAIErrorDataSchema,
175
+ errorToMessage: (data) => data.error.message
176
+ });
177
+
178
+ // src/friendliai-chat-language-model.ts
179
+ var FriendliAIChatLanguageModel = class {
180
+ constructor(modelId, settings, config) {
181
+ this.specificationVersion = "v1";
182
+ this.modelId = modelId;
183
+ this.settings = settings;
184
+ this.config = config;
185
+ }
186
+ get supportsStructuredOutputs() {
187
+ return this.settings.structuredOutputs === true;
188
+ }
189
+ get defaultObjectGenerationMode() {
190
+ return this.supportsStructuredOutputs ? "json" : "tool";
191
+ }
192
+ get provider() {
193
+ return this.config.provider;
194
+ }
195
+ getArgs({
196
+ mode,
197
+ prompt,
198
+ maxTokens,
199
+ temperature,
200
+ topP,
201
+ topK,
202
+ frequencyPenalty,
203
+ presencePenalty,
204
+ stopSequences,
205
+ responseFormat,
206
+ seed
207
+ }) {
208
+ var _a;
209
+ const type = mode.type;
210
+ const warnings = [];
211
+ if (topK != null) {
212
+ warnings.push({
213
+ type: "unsupported-setting",
214
+ setting: "topK"
215
+ });
216
+ }
217
+ if (responseFormat != null && responseFormat.type === "json" && responseFormat.schema != null) {
218
+ warnings.push({
219
+ type: "unsupported-setting",
220
+ setting: "responseFormat",
221
+ details: "JSON response format schema is not supported"
222
+ });
223
+ }
224
+ const useLegacyFunctionCalling = this.settings.useLegacyFunctionCalling;
225
+ if (useLegacyFunctionCalling && this.settings.parallelToolCalls === true) {
226
+ throw new UnsupportedFunctionalityError2({
227
+ functionality: "useLegacyFunctionCalling with parallelToolCalls"
228
+ });
229
+ }
230
+ if (useLegacyFunctionCalling && this.settings.structuredOutputs === true) {
231
+ throw new UnsupportedFunctionalityError2({
232
+ functionality: "structuredOutputs with useLegacyFunctionCalling"
233
+ });
234
+ }
235
+ const baseArgs = {
236
+ // model id:
237
+ model: this.modelId,
238
+ // model specific settings:
239
+ logit_bias: this.settings.logitBias,
240
+ logprobs: this.settings.logprobs === true || typeof this.settings.logprobs === "number" ? true : void 0,
241
+ top_logprobs: typeof this.settings.logprobs === "number" ? this.settings.logprobs : typeof this.settings.logprobs === "boolean" ? this.settings.logprobs ? 0 : void 0 : void 0,
242
+ user: this.settings.user,
243
+ parallel_tool_calls: this.settings.parallelToolCalls,
244
+ // standardized settings:
245
+ max_tokens: maxTokens,
246
+ temperature,
247
+ top_p: topP,
248
+ frequency_penalty: frequencyPenalty,
249
+ presence_penalty: presencePenalty,
250
+ stop: stopSequences,
251
+ seed,
252
+ // response format:
253
+ response_format: (responseFormat == null ? void 0 : responseFormat.type) === "json" ? { type: "json_object" } : void 0,
254
+ // messages:
255
+ messages: convertToFriendliAIChatMessages({
256
+ prompt,
257
+ useLegacyFunctionCalling
258
+ })
259
+ };
260
+ switch (type) {
261
+ case "regular": {
262
+ return {
263
+ args: {
264
+ ...baseArgs,
265
+ ...prepareToolsAndToolChoice({
266
+ mode,
267
+ useLegacyFunctionCalling,
268
+ structuredOutputs: this.settings.structuredOutputs,
269
+ tools: this.settings.tools
270
+ })
271
+ },
272
+ warnings
273
+ };
274
+ }
275
+ case "object-json": {
276
+ return {
277
+ args: {
278
+ ...baseArgs,
279
+ response_format: this.settings.structuredOutputs === true ? {
280
+ type: "json_schema",
281
+ json_schema: {
282
+ schema: mode.schema,
283
+ strict: true,
284
+ name: (_a = mode.name) != null ? _a : "response",
285
+ description: mode.description
286
+ }
287
+ } : { type: "json_object" }
288
+ },
289
+ warnings
290
+ };
291
+ }
292
+ case "object-tool": {
293
+ return {
294
+ args: useLegacyFunctionCalling ? {
295
+ ...baseArgs,
296
+ function_call: {
297
+ name: mode.tool.name
298
+ },
299
+ functions: [
300
+ {
301
+ name: mode.tool.name,
302
+ description: mode.tool.description,
303
+ parameters: mode.tool.parameters
304
+ }
305
+ ]
306
+ } : {
307
+ ...baseArgs,
308
+ tool_choice: {
309
+ type: "function",
310
+ function: { name: mode.tool.name }
311
+ },
312
+ tools: [
313
+ {
314
+ type: "function",
315
+ function: {
316
+ name: mode.tool.name,
317
+ description: mode.tool.description,
318
+ parameters: mode.tool.parameters,
319
+ strict: this.settings.structuredOutputs === true ? true : void 0
320
+ }
321
+ }
322
+ ]
323
+ },
324
+ warnings
325
+ };
326
+ }
327
+ default: {
328
+ const _exhaustiveCheck = type;
329
+ throw new Error(`Unsupported type: ${_exhaustiveCheck}`);
330
+ }
331
+ }
332
+ }
333
+ async doGenerate(options) {
334
+ var _a, _b, _c, _d, _e, _f;
335
+ const { args, warnings } = this.getArgs(options);
336
+ const { responseHeaders, value: response } = await postJsonToApi({
337
+ url: this.config.url({
338
+ path: "/chat/completions",
339
+ modelId: this.modelId
340
+ }),
341
+ headers: combineHeaders(this.config.headers(), options.headers),
342
+ body: args,
343
+ failedResponseHandler: friendliaiFailedResponseHandler,
344
+ successfulResponseHandler: createJsonResponseHandler(
345
+ friendliAIChatResponseSchema
346
+ ),
347
+ abortSignal: options.abortSignal,
348
+ fetch: this.config.fetch
349
+ });
350
+ const { messages: rawPrompt, ...rawSettings } = args;
351
+ const choice = response.choices[0];
352
+ return {
353
+ text: (_a = choice.message.content) != null ? _a : void 0,
354
+ toolCalls: this.settings.useLegacyFunctionCalling && choice.message.function_call ? [
355
+ {
356
+ toolCallType: "function",
357
+ toolCallId: generateId(),
358
+ toolName: choice.message.function_call.name,
359
+ args: choice.message.function_call.arguments
360
+ }
361
+ ] : (_b = choice.message.tool_calls) == null ? void 0 : _b.map((toolCall) => {
362
+ var _a2;
363
+ return {
364
+ toolCallType: "function",
365
+ toolCallId: (_a2 = toolCall.id) != null ? _a2 : generateId(),
366
+ toolName: toolCall.function.name,
367
+ args: toolCall.function.arguments
368
+ };
369
+ }),
370
+ finishReason: mapFriendliAIFinishReason(choice.finish_reason),
371
+ usage: {
372
+ promptTokens: (_d = (_c = response.usage) == null ? void 0 : _c.prompt_tokens) != null ? _d : NaN,
373
+ completionTokens: (_f = (_e = response.usage) == null ? void 0 : _e.completion_tokens) != null ? _f : NaN
374
+ },
375
+ rawCall: { rawPrompt, rawSettings },
376
+ rawResponse: { headers: responseHeaders },
377
+ warnings,
378
+ logprobs: mapFriendliAIChatLogProbsOutput(choice.logprobs)
379
+ };
380
+ }
381
+ async doStream(options) {
382
+ const { args, warnings } = this.getArgs(options);
383
+ const { responseHeaders, value: response } = await postJsonToApi({
384
+ url: this.config.url({
385
+ path: "/chat/completions",
386
+ modelId: this.modelId
387
+ }),
388
+ headers: combineHeaders(this.config.headers(), options.headers),
389
+ body: {
390
+ ...args,
391
+ stream: true,
392
+ // only include stream_options when in strict compatibility mode:
393
+ stream_options: this.config.compatibility === "strict" ? { include_usage: true } : void 0
394
+ },
395
+ failedResponseHandler: friendliaiFailedResponseHandler,
396
+ successfulResponseHandler: createEventSourceResponseHandler(
397
+ friendliaiChatChunkSchema
398
+ ),
399
+ abortSignal: options.abortSignal,
400
+ fetch: this.config.fetch
401
+ });
402
+ const { messages: rawPrompt, ...rawSettings } = args;
403
+ const toolCalls = [];
404
+ let finishReason = "unknown";
405
+ let usage = {
406
+ promptTokens: void 0,
407
+ completionTokens: void 0
408
+ };
409
+ let logprobs;
410
+ const { useLegacyFunctionCalling } = this.settings;
411
+ return {
412
+ stream: response.pipeThrough(
413
+ new TransformStream({
414
+ transform(chunk, controller) {
415
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
416
+ if (!chunk.success) {
417
+ finishReason = "error";
418
+ controller.enqueue({ type: "error", error: chunk.error });
419
+ return;
420
+ }
421
+ const value = chunk.value;
422
+ if ("tool_call_id" in value) {
423
+ switch (value.state) {
424
+ case "START":
425
+ break;
426
+ case "UPDATE":
427
+ break;
428
+ case "END":
429
+ break;
430
+ case "ERROR":
431
+ finishReason = "error";
432
+ controller.enqueue({
433
+ type: "error",
434
+ error: new Error(
435
+ `Tool call error: ${(_b = (_a = value.error) == null ? void 0 : _a.msg) != null ? _b : "Unknown error"} (type: ${(_d = (_c = value.error) == null ? void 0 : _c.type) != null ? _d : "unknown"})`
436
+ )
437
+ });
438
+ break;
439
+ default:
440
+ finishReason = "error";
441
+ controller.enqueue({
442
+ type: "error",
443
+ error: new Error(
444
+ `Unsupported tool call state: ${value.state}`
445
+ )
446
+ });
447
+ }
448
+ return;
449
+ }
450
+ if ("error" in value) {
451
+ finishReason = "error";
452
+ controller.enqueue({ type: "error", error: value.error });
453
+ return;
454
+ }
455
+ if (value.usage != null) {
456
+ usage = {
457
+ promptTokens: (_e = value.usage.prompt_tokens) != null ? _e : void 0,
458
+ completionTokens: (_f = value.usage.completion_tokens) != null ? _f : void 0
459
+ };
460
+ }
461
+ const choice = value.choices[0];
462
+ if ((choice == null ? void 0 : choice.finish_reason) != null) {
463
+ finishReason = mapFriendliAIFinishReason(choice.finish_reason);
464
+ }
465
+ if ((choice == null ? void 0 : choice.delta) == null) {
466
+ return;
467
+ }
468
+ const delta = choice.delta;
469
+ if (delta.content != null) {
470
+ controller.enqueue({
471
+ type: "text-delta",
472
+ textDelta: delta.content
473
+ });
474
+ }
475
+ const mappedLogprobs = mapFriendliAIChatLogProbsOutput(
476
+ choice == null ? void 0 : choice.logprobs
477
+ );
478
+ if (mappedLogprobs == null ? void 0 : mappedLogprobs.length) {
479
+ if (logprobs === void 0) logprobs = [];
480
+ logprobs.push(...mappedLogprobs);
481
+ }
482
+ const mappedToolCalls = useLegacyFunctionCalling && delta.function_call != null ? [
483
+ {
484
+ type: "function",
485
+ id: generateId(),
486
+ function: delta.function_call,
487
+ index: 0
488
+ }
489
+ ] : delta.tool_calls;
490
+ if (mappedToolCalls != null) {
491
+ for (const toolCallDelta of mappedToolCalls) {
492
+ const index = toolCallDelta.index;
493
+ if (toolCalls[index] == null) {
494
+ if (toolCallDelta.type !== "function") {
495
+ throw new InvalidResponseDataError({
496
+ data: toolCallDelta,
497
+ message: `Expected 'function' type.`
498
+ });
499
+ }
500
+ if (toolCallDelta.id == null) {
501
+ throw new InvalidResponseDataError({
502
+ data: toolCallDelta,
503
+ message: `Expected 'id' to be a string.`
504
+ });
505
+ }
506
+ if (((_g = toolCallDelta.function) == null ? void 0 : _g.name) == null) {
507
+ throw new InvalidResponseDataError({
508
+ data: toolCallDelta,
509
+ message: `Expected 'function.name' to be a string.`
510
+ });
511
+ }
512
+ toolCalls[index] = {
513
+ id: toolCallDelta.id,
514
+ type: "function",
515
+ function: {
516
+ name: toolCallDelta.function.name,
517
+ arguments: (_h = toolCallDelta.function.arguments) != null ? _h : ""
518
+ }
519
+ };
520
+ const toolCall2 = toolCalls[index];
521
+ if (((_i = toolCall2.function) == null ? void 0 : _i.name) != null && ((_j = toolCall2.function) == null ? void 0 : _j.arguments) != null) {
522
+ if (toolCall2.function.arguments.length > 0) {
523
+ controller.enqueue({
524
+ type: "tool-call-delta",
525
+ toolCallType: "function",
526
+ toolCallId: toolCall2.id,
527
+ toolName: toolCall2.function.name,
528
+ argsTextDelta: toolCall2.function.arguments
529
+ });
530
+ }
531
+ if (isParsableJson(toolCall2.function.arguments)) {
532
+ controller.enqueue({
533
+ type: "tool-call",
534
+ toolCallType: "function",
535
+ toolCallId: (_k = toolCall2.id) != null ? _k : generateId(),
536
+ toolName: toolCall2.function.name,
537
+ args: toolCall2.function.arguments
538
+ });
539
+ }
540
+ }
541
+ continue;
542
+ }
543
+ const toolCall = toolCalls[index];
544
+ if (((_l = toolCallDelta.function) == null ? void 0 : _l.arguments) != null) {
545
+ toolCall.function.arguments += (_n = (_m = toolCallDelta.function) == null ? void 0 : _m.arguments) != null ? _n : "";
546
+ }
547
+ controller.enqueue({
548
+ type: "tool-call-delta",
549
+ toolCallType: "function",
550
+ toolCallId: toolCall.id,
551
+ toolName: toolCall.function.name,
552
+ argsTextDelta: (_o = toolCallDelta.function.arguments) != null ? _o : ""
553
+ });
554
+ if (((_p = toolCall.function) == null ? void 0 : _p.name) != null && ((_q = toolCall.function) == null ? void 0 : _q.arguments) != null && isParsableJson(toolCall.function.arguments)) {
555
+ controller.enqueue({
556
+ type: "tool-call",
557
+ toolCallType: "function",
558
+ toolCallId: (_r = toolCall.id) != null ? _r : generateId(),
559
+ toolName: toolCall.function.name,
560
+ args: toolCall.function.arguments
561
+ });
562
+ }
563
+ }
564
+ }
565
+ },
566
+ flush(controller) {
567
+ var _a, _b;
568
+ controller.enqueue({
569
+ type: "finish",
570
+ finishReason,
571
+ logprobs,
572
+ usage: {
573
+ promptTokens: (_a = usage.promptTokens) != null ? _a : NaN,
574
+ completionTokens: (_b = usage.completionTokens) != null ? _b : NaN
575
+ }
576
+ });
577
+ }
578
+ })
579
+ ),
580
+ rawCall: { rawPrompt, rawSettings },
581
+ rawResponse: { headers: responseHeaders },
582
+ warnings
583
+ };
584
+ }
585
+ };
586
+ var friendliAITokenUsageSchema = z2.object({
587
+ prompt_tokens: z2.number().nullish(),
588
+ completion_tokens: z2.number().nullish()
589
+ }).nullish();
590
+ var friendliAIChatResponseSchema = z2.object({
591
+ choices: z2.array(
592
+ z2.object({
593
+ message: z2.object({
594
+ role: z2.literal("assistant").nullish(),
595
+ content: z2.string().nullish(),
596
+ function_call: z2.object({
597
+ arguments: z2.string(),
598
+ name: z2.string()
599
+ }).nullish(),
600
+ tool_calls: z2.array(
601
+ z2.object({
602
+ id: z2.string().nullish(),
603
+ type: z2.literal("function"),
604
+ function: z2.object({
605
+ name: z2.string(),
606
+ arguments: z2.string()
607
+ })
608
+ })
609
+ ).nullish()
610
+ }),
611
+ index: z2.number(),
612
+ logprobs: z2.object({
613
+ content: z2.array(
614
+ z2.object({
615
+ token: z2.string(),
616
+ logprob: z2.number(),
617
+ top_logprobs: z2.array(
618
+ z2.object({
619
+ token: z2.string(),
620
+ logprob: z2.number()
621
+ })
622
+ )
623
+ })
624
+ ).nullable()
625
+ }).nullish(),
626
+ finish_reason: z2.string().nullish()
627
+ })
628
+ ),
629
+ usage: friendliAITokenUsageSchema
630
+ });
631
+ var friendliaiChatChunkSchema = z2.union([
632
+ z2.object({
633
+ name: z2.string(),
634
+ state: z2.enum(["END", "START", "ERROR", "UPDATE"]),
635
+ status: z2.enum(["ENDED", "STARTED", "ERRORED", "UPDATING"]),
636
+ message: z2.null(),
637
+ parameters: z2.array(
638
+ z2.object({
639
+ name: z2.string(),
640
+ value: z2.string()
641
+ })
642
+ ),
643
+ result: z2.string(),
644
+ error: z2.object({
645
+ type: z2.enum(["INVALID_PARAMETER", "UNKNOWN"]),
646
+ msg: z2.string()
647
+ }).nullable(),
648
+ timestamp: z2.number(),
649
+ usage: z2.null(),
650
+ tool_call_id: z2.string()
651
+ }),
652
+ z2.object({
653
+ choices: z2.array(
654
+ z2.object({
655
+ delta: z2.object({
656
+ role: z2.enum(["assistant"]).nullish(),
657
+ content: z2.string().nullish(),
658
+ function_call: z2.object({
659
+ name: z2.string().optional(),
660
+ arguments: z2.string().optional()
661
+ }).nullish(),
662
+ tool_calls: z2.array(
663
+ z2.object({
664
+ index: z2.number(),
665
+ id: z2.string().nullish(),
666
+ type: z2.literal("function").optional(),
667
+ function: z2.object({
668
+ name: z2.string().nullish(),
669
+ arguments: z2.string().nullish()
670
+ })
671
+ })
672
+ ).nullish()
673
+ }).nullish(),
674
+ logprobs: z2.object({
675
+ content: z2.array(
676
+ z2.object({
677
+ token: z2.string(),
678
+ logprob: z2.number(),
679
+ top_logprobs: z2.array(
680
+ z2.object({
681
+ token: z2.string(),
682
+ logprob: z2.number()
683
+ })
684
+ )
685
+ })
686
+ ).nullable()
687
+ }).nullish(),
688
+ finish_reason: z2.string().nullable().optional(),
689
+ index: z2.number()
690
+ })
691
+ ),
692
+ usage: friendliAITokenUsageSchema
693
+ }),
694
+ friendliAIErrorDataSchema
695
+ ]);
696
+ function prepareToolsAndToolChoice({
697
+ mode,
698
+ useLegacyFunctionCalling = false,
699
+ structuredOutputs = false,
700
+ tools: hostedTools
701
+ }) {
702
+ var _a;
703
+ const tools = ((_a = mode.tools) == null ? void 0 : _a.length) ? mode.tools : void 0;
704
+ if (tools == null && hostedTools != null) {
705
+ return { tools: void 0, tool_choice: void 0 };
706
+ }
707
+ const toolChoice = mode.toolChoice;
708
+ if (useLegacyFunctionCalling) {
709
+ const mappedFunctions = tools == null ? void 0 : tools.map((tool) => ({
710
+ name: tool.name,
711
+ description: tool.description,
712
+ parameters: tool.parameters
713
+ }));
714
+ if (toolChoice == null) {
715
+ return { functions: mappedFunctions, function_call: void 0 };
716
+ }
717
+ const type2 = toolChoice.type;
718
+ switch (type2) {
719
+ case "auto":
720
+ case "none":
721
+ case void 0:
722
+ return {
723
+ functions: mappedFunctions,
724
+ function_call: void 0
725
+ };
726
+ case "required":
727
+ throw new UnsupportedFunctionalityError2({
728
+ functionality: "useLegacyFunctionCalling and toolChoice: required"
729
+ });
730
+ default:
731
+ return {
732
+ functions: mappedFunctions,
733
+ function_call: { name: toolChoice.toolName }
734
+ };
735
+ }
736
+ }
737
+ const mappedTools = tools == null ? void 0 : tools.map((tool) => ({
738
+ type: "function",
739
+ function: {
740
+ name: tool.name,
741
+ description: tool.description,
742
+ parameters: tool.parameters,
743
+ strict: structuredOutputs === true ? true : void 0
744
+ }
745
+ }));
746
+ const mappedHostedTools = hostedTools == null ? void 0 : hostedTools.map((tool) => ({
747
+ type: tool.type
748
+ }));
749
+ if (toolChoice == null) {
750
+ return {
751
+ tools: [...mappedTools != null ? mappedTools : [], ...mappedHostedTools != null ? mappedHostedTools : []],
752
+ tool_choice: void 0
753
+ };
754
+ }
755
+ const type = toolChoice.type;
756
+ switch (type) {
757
+ case "auto":
758
+ case "none":
759
+ case "required":
760
+ return {
761
+ tools: [...mappedTools != null ? mappedTools : [], ...mappedHostedTools != null ? mappedHostedTools : []],
762
+ tool_choice: type
763
+ };
764
+ case "tool":
765
+ return {
766
+ tools: [...mappedTools != null ? mappedTools : [], ...mappedHostedTools != null ? mappedHostedTools : []],
767
+ tool_choice: {
768
+ type: "function",
769
+ function: {
770
+ name: toolChoice.toolName
771
+ }
772
+ }
773
+ };
774
+ default: {
775
+ const _exhaustiveCheck = type;
776
+ throw new Error(`Unsupported tool choice type: ${_exhaustiveCheck}`);
777
+ }
778
+ }
779
+ }
780
+
781
+ // src/friendliai-completion-language-model.ts
782
+ import {
783
+ UnsupportedFunctionalityError as UnsupportedFunctionalityError4
784
+ } from "@ai-sdk/provider";
785
+ import {
786
+ combineHeaders as combineHeaders2,
787
+ createEventSourceResponseHandler as createEventSourceResponseHandler2,
788
+ createJsonResponseHandler as createJsonResponseHandler2,
789
+ postJsonToApi as postJsonToApi2
790
+ } from "@ai-sdk/provider-utils";
791
+ import { z as z3 } from "zod";
792
+
793
+ // src/convert-to-friendliai-completion-prompt.ts
794
+ import {
795
+ InvalidPromptError,
796
+ UnsupportedFunctionalityError as UnsupportedFunctionalityError3
797
+ } from "@ai-sdk/provider";
798
+ function convertToFriendliAICompletionPrompt({
799
+ prompt,
800
+ inputFormat,
801
+ user = "user",
802
+ assistant = "assistant"
803
+ }) {
804
+ if (inputFormat === "prompt" && prompt.length === 1 && prompt[0].role === "user" && prompt[0].content.length === 1 && prompt[0].content[0].type === "text") {
805
+ return { prompt: prompt[0].content[0].text };
806
+ }
807
+ let text = "";
808
+ if (prompt[0].role === "system") {
809
+ text += `${prompt[0].content}
810
+
811
+ `;
812
+ prompt = prompt.slice(1);
813
+ }
814
+ for (const { role, content } of prompt) {
815
+ switch (role) {
816
+ case "system": {
817
+ throw new InvalidPromptError({
818
+ message: "Unexpected system message in prompt: ${content}",
819
+ prompt
820
+ });
821
+ }
822
+ case "user": {
823
+ const userMessage = content.map((part) => {
824
+ switch (part.type) {
825
+ case "text": {
826
+ return part.text;
827
+ }
828
+ case "image": {
829
+ throw new UnsupportedFunctionalityError3({
830
+ functionality: "images"
831
+ });
832
+ }
833
+ }
834
+ }).join("");
835
+ text += `${user}:
836
+ ${userMessage}
837
+
838
+ `;
839
+ break;
840
+ }
841
+ case "assistant": {
842
+ const assistantMessage = content.map((part) => {
843
+ switch (part.type) {
844
+ case "text": {
845
+ return part.text;
846
+ }
847
+ case "tool-call": {
848
+ throw new UnsupportedFunctionalityError3({
849
+ functionality: "tool-call messages"
850
+ });
851
+ }
852
+ }
853
+ }).join("");
854
+ text += `${assistant}:
855
+ ${assistantMessage}
856
+
857
+ `;
858
+ break;
859
+ }
860
+ case "tool": {
861
+ throw new UnsupportedFunctionalityError3({
862
+ functionality: "tool messages"
863
+ });
864
+ }
865
+ default: {
866
+ const _exhaustiveCheck = role;
867
+ throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
868
+ }
869
+ }
870
+ }
871
+ text += `${assistant}:
872
+ `;
873
+ return {
874
+ prompt: text,
875
+ stopSequences: [`
876
+ ${user}:`]
877
+ };
878
+ }
879
+
880
+ // src/map-friendliai-completion-logprobs.ts
881
+ function mapFriendliAICompletionLogProbs(logprobs) {
882
+ return logprobs == null ? void 0 : logprobs.tokens.map((token, index) => ({
883
+ token,
884
+ logprob: logprobs.token_logprobs[index],
885
+ topLogprobs: logprobs.top_logprobs ? Object.entries(logprobs.top_logprobs[index]).map(
886
+ ([token2, logprob]) => ({
887
+ token: token2,
888
+ logprob
889
+ })
890
+ ) : []
891
+ }));
892
+ }
893
+
894
+ // src/friendliai-completion-language-model.ts
895
+ var FriendliAICompletionLanguageModel = class {
896
+ constructor(modelId, settings, config) {
897
+ this.specificationVersion = "v1";
898
+ this.defaultObjectGenerationMode = void 0;
899
+ this.modelId = modelId;
900
+ this.settings = settings;
901
+ this.config = config;
902
+ }
903
+ get provider() {
904
+ return this.config.provider;
905
+ }
906
+ getArgs({
907
+ mode,
908
+ inputFormat,
909
+ prompt,
910
+ maxTokens,
911
+ temperature,
912
+ topP,
913
+ topK,
914
+ frequencyPenalty,
915
+ presencePenalty,
916
+ stopSequences: userStopSequences,
917
+ responseFormat,
918
+ seed
919
+ }) {
920
+ var _a;
921
+ const type = mode.type;
922
+ const warnings = [];
923
+ if (topK != null) {
924
+ warnings.push({
925
+ type: "unsupported-setting",
926
+ setting: "topK"
927
+ });
928
+ }
929
+ if (responseFormat != null && responseFormat.type !== "text") {
930
+ warnings.push({
931
+ type: "unsupported-setting",
932
+ setting: "responseFormat",
933
+ details: "JSON response format is not supported."
934
+ });
935
+ }
936
+ const { prompt: completionPrompt, stopSequences } = convertToFriendliAICompletionPrompt({ prompt, inputFormat });
937
+ const stop = [...stopSequences != null ? stopSequences : [], ...userStopSequences != null ? userStopSequences : []];
938
+ const baseArgs = {
939
+ // model id:
940
+ model: this.modelId,
941
+ // model specific settings:
942
+ echo: this.settings.echo,
943
+ logit_bias: this.settings.logitBias,
944
+ logprobs: typeof this.settings.logprobs === "number" ? this.settings.logprobs : typeof this.settings.logprobs === "boolean" ? this.settings.logprobs ? 0 : void 0 : void 0,
945
+ suffix: this.settings.suffix,
946
+ user: this.settings.user,
947
+ // standardized settings:
948
+ max_tokens: maxTokens,
949
+ temperature,
950
+ top_p: topP,
951
+ frequency_penalty: frequencyPenalty,
952
+ presence_penalty: presencePenalty,
953
+ seed,
954
+ // prompt:
955
+ prompt: completionPrompt,
956
+ // stop sequences:
957
+ stop: stop.length > 0 ? stop : void 0
958
+ };
959
+ switch (type) {
960
+ case "regular": {
961
+ if ((_a = mode.tools) == null ? void 0 : _a.length) {
962
+ throw new UnsupportedFunctionalityError4({
963
+ functionality: "tools"
964
+ });
965
+ }
966
+ if (mode.toolChoice) {
967
+ throw new UnsupportedFunctionalityError4({
968
+ functionality: "toolChoice"
969
+ });
970
+ }
971
+ return { args: baseArgs, warnings };
972
+ }
973
+ case "object-json": {
974
+ throw new UnsupportedFunctionalityError4({
975
+ functionality: "object-json mode"
976
+ });
977
+ }
978
+ case "object-tool": {
979
+ throw new UnsupportedFunctionalityError4({
980
+ functionality: "object-tool mode"
981
+ });
982
+ }
983
+ default: {
984
+ const _exhaustiveCheck = type;
985
+ throw new Error(`Unsupported type: ${_exhaustiveCheck}`);
986
+ }
987
+ }
988
+ }
989
+ async doGenerate(options) {
990
+ const { args, warnings } = this.getArgs(options);
991
+ const { responseHeaders, value: response } = await postJsonToApi2({
992
+ url: this.config.url({
993
+ path: "/completions",
994
+ modelId: this.modelId
995
+ }),
996
+ headers: combineHeaders2(this.config.headers(), options.headers),
997
+ body: args,
998
+ failedResponseHandler: friendliaiFailedResponseHandler,
999
+ successfulResponseHandler: createJsonResponseHandler2(
1000
+ friendliAICompletionResponseSchema
1001
+ ),
1002
+ abortSignal: options.abortSignal,
1003
+ fetch: this.config.fetch
1004
+ });
1005
+ const { prompt: rawPrompt, ...rawSettings } = args;
1006
+ const choice = response.choices[0];
1007
+ return {
1008
+ text: choice.text,
1009
+ usage: {
1010
+ promptTokens: response.usage.prompt_tokens,
1011
+ completionTokens: response.usage.completion_tokens
1012
+ },
1013
+ finishReason: mapFriendliAIFinishReason(choice.finish_reason),
1014
+ logprobs: mapFriendliAICompletionLogProbs(choice.logprobs),
1015
+ rawCall: { rawPrompt, rawSettings },
1016
+ rawResponse: { headers: responseHeaders },
1017
+ warnings
1018
+ };
1019
+ }
1020
+ async doStream(options) {
1021
+ const { args, warnings } = this.getArgs(options);
1022
+ const { responseHeaders, value: response } = await postJsonToApi2({
1023
+ url: this.config.url({
1024
+ path: "/completions",
1025
+ modelId: this.modelId
1026
+ }),
1027
+ headers: combineHeaders2(this.config.headers(), options.headers),
1028
+ body: {
1029
+ ...args,
1030
+ stream: true,
1031
+ // only include stream_options when in strict compatibility mode:
1032
+ stream_options: this.config.compatibility === "strict" ? { include_usage: true } : void 0
1033
+ },
1034
+ failedResponseHandler: friendliaiFailedResponseHandler,
1035
+ successfulResponseHandler: createEventSourceResponseHandler2(
1036
+ friendliaiCompletionChunkSchema
1037
+ ),
1038
+ abortSignal: options.abortSignal,
1039
+ fetch: this.config.fetch
1040
+ });
1041
+ const { prompt: rawPrompt, ...rawSettings } = args;
1042
+ let finishReason = "unknown";
1043
+ let usage = {
1044
+ promptTokens: Number.NaN,
1045
+ completionTokens: Number.NaN
1046
+ };
1047
+ let logprobs;
1048
+ return {
1049
+ stream: response.pipeThrough(
1050
+ new TransformStream({
1051
+ transform(chunk, controller) {
1052
+ if (!chunk.success) {
1053
+ finishReason = "error";
1054
+ controller.enqueue({ type: "error", error: chunk.error });
1055
+ return;
1056
+ }
1057
+ const value = chunk.value;
1058
+ if ("error" in value) {
1059
+ finishReason = "error";
1060
+ controller.enqueue({ type: "error", error: value.error });
1061
+ return;
1062
+ }
1063
+ if (value.usage != null) {
1064
+ usage = {
1065
+ promptTokens: value.usage.prompt_tokens,
1066
+ completionTokens: value.usage.completion_tokens
1067
+ };
1068
+ }
1069
+ const choice = value.choices[0];
1070
+ if ((choice == null ? void 0 : choice.finish_reason) != null) {
1071
+ finishReason = mapFriendliAIFinishReason(choice.finish_reason);
1072
+ }
1073
+ if ((choice == null ? void 0 : choice.text) != null) {
1074
+ controller.enqueue({
1075
+ type: "text-delta",
1076
+ textDelta: choice.text
1077
+ });
1078
+ }
1079
+ const mappedLogprobs = mapFriendliAICompletionLogProbs(
1080
+ choice == null ? void 0 : choice.logprobs
1081
+ );
1082
+ if (mappedLogprobs == null ? void 0 : mappedLogprobs.length) {
1083
+ if (logprobs === void 0) logprobs = [];
1084
+ logprobs.push(...mappedLogprobs);
1085
+ }
1086
+ },
1087
+ flush(controller) {
1088
+ controller.enqueue({
1089
+ type: "finish",
1090
+ finishReason,
1091
+ logprobs,
1092
+ usage
1093
+ });
1094
+ }
1095
+ })
1096
+ ),
1097
+ rawCall: { rawPrompt, rawSettings },
1098
+ rawResponse: { headers: responseHeaders },
1099
+ warnings
1100
+ };
1101
+ }
1102
+ };
1103
+ var friendliAICompletionResponseSchema = z3.object({
1104
+ choices: z3.array(
1105
+ z3.object({
1106
+ text: z3.string(),
1107
+ finish_reason: z3.string(),
1108
+ logprobs: z3.object({
1109
+ tokens: z3.array(z3.string()),
1110
+ token_logprobs: z3.array(z3.number()),
1111
+ top_logprobs: z3.array(z3.record(z3.string(), z3.number())).nullable()
1112
+ }).nullable().optional()
1113
+ })
1114
+ ),
1115
+ usage: z3.object({
1116
+ prompt_tokens: z3.number(),
1117
+ completion_tokens: z3.number()
1118
+ })
1119
+ });
1120
+ var friendliaiCompletionChunkSchema = z3.union([
1121
+ z3.object({
1122
+ choices: z3.array(
1123
+ z3.object({
1124
+ text: z3.string(),
1125
+ finish_reason: z3.string().nullish(),
1126
+ index: z3.number(),
1127
+ logprobs: z3.object({
1128
+ tokens: z3.array(z3.string()),
1129
+ token_logprobs: z3.array(z3.number()),
1130
+ top_logprobs: z3.array(z3.record(z3.string(), z3.number())).nullable()
1131
+ }).nullable().optional()
1132
+ })
1133
+ ),
1134
+ usage: z3.object({
1135
+ prompt_tokens: z3.number(),
1136
+ completion_tokens: z3.number()
1137
+ }).optional().nullable()
1138
+ }),
1139
+ friendliAIErrorDataSchema
1140
+ ]);
1141
+
1142
+ // src/friendliai-facade.ts
1143
+ var FriendliAI = class {
1144
+ /**
1145
+ * Creates a new FriendliAI provider instance.
1146
+ */
1147
+ constructor(options = {}) {
1148
+ var _a, _b;
1149
+ this.baseURL = (_b = withoutTrailingSlash((_a = options.baseURL) != null ? _a : options.baseUrl)) != null ? _b : "https://inference.friendli.ai/tools/v1";
1150
+ this.apiKey = options.apiKey;
1151
+ this.teamId = options.teamId;
1152
+ this.headers = options.headers;
1153
+ }
1154
+ get baseConfig() {
1155
+ return {
1156
+ teamId: this.teamId,
1157
+ baseURL: this.baseURL,
1158
+ headers: () => ({
1159
+ Authorization: `Bearer ${loadApiKey({
1160
+ apiKey: this.apiKey,
1161
+ environmentVariableName: "FRIENDLI_API_KEY",
1162
+ description: "FriendliAI"
1163
+ })}`,
1164
+ "X-Friendli-Team": this.teamId,
1165
+ ...this.headers
1166
+ })
1167
+ };
1168
+ }
1169
+ chat(modelId, settings = {}) {
1170
+ return new FriendliAIChatLanguageModel(modelId, settings, {
1171
+ provider: "friendliai.chat",
1172
+ ...this.baseConfig,
1173
+ compatibility: "strict",
1174
+ url: ({ path }) => `${this.baseURL}${path}`
1175
+ });
1176
+ }
1177
+ completion(modelId, settings = {}) {
1178
+ return new FriendliAICompletionLanguageModel(modelId, settings, {
1179
+ provider: "friendliai.completion",
1180
+ ...this.baseConfig,
1181
+ compatibility: "strict",
1182
+ url: ({ path }) => `${this.baseURL}${path}`
1183
+ });
1184
+ }
1185
+ };
1186
+
1187
+ // src/friendliai-provider.ts
1188
+ import {
1189
+ NoSuchModelError
1190
+ } from "@ai-sdk/provider";
1191
+ import {
1192
+ loadApiKey as loadApiKey2,
1193
+ withoutTrailingSlash as withoutTrailingSlash2
1194
+ } from "@ai-sdk/provider-utils";
1195
+ function createFriendliAI(options = {}) {
1196
+ var _a, _b;
1197
+ const baseURL = (_b = withoutTrailingSlash2((_a = options.baseURL) != null ? _a : options.baseUrl)) != null ? _b : "https://inference.friendli.ai/tools/v1";
1198
+ const compatibility = "compatible";
1199
+ const getHeaders = () => ({
1200
+ Authorization: `Bearer ${loadApiKey2({
1201
+ apiKey: options.apiKey,
1202
+ environmentVariableName: "FRIENDLI_API_KEY",
1203
+ description: "FriendliAI API key"
1204
+ })}`,
1205
+ "X-Friendli-Team": options.teamId,
1206
+ ...options.headers
1207
+ });
1208
+ const createChatModel = (modelId, settings = {}) => new FriendliAIChatLanguageModel(modelId, settings, {
1209
+ provider: "friendliai.chat",
1210
+ url: ({ path }) => `${baseURL}${path}`,
1211
+ headers: getHeaders,
1212
+ compatibility,
1213
+ fetch: options.fetch
1214
+ });
1215
+ const createCompletionModel = (modelId, settings = {}) => new FriendliAICompletionLanguageModel(modelId, settings, {
1216
+ provider: "friendliai.completion",
1217
+ url: ({ path }) => `${baseURL}${path}`,
1218
+ headers: getHeaders,
1219
+ compatibility,
1220
+ fetch: options.fetch
1221
+ });
1222
+ const createLanguageModel = (modelId, settings) => {
1223
+ if (new.target) {
1224
+ throw new Error(
1225
+ "The FriendliAI model function cannot be called with the new keyword."
1226
+ );
1227
+ }
1228
+ if (modelId === "gpt-3.5-turbo") {
1229
+ return createCompletionModel(
1230
+ modelId,
1231
+ settings
1232
+ );
1233
+ }
1234
+ return createChatModel(modelId, settings);
1235
+ };
1236
+ const provider = function(modelId, settings) {
1237
+ return createLanguageModel(modelId, settings);
1238
+ };
1239
+ provider.languageModel = createLanguageModel;
1240
+ provider.chat = createChatModel;
1241
+ provider.completion = createCompletionModel;
1242
+ provider.textEmbeddingModel = (modelId) => {
1243
+ throw new NoSuchModelError({ modelId, modelType: "textEmbeddingModel" });
1244
+ };
1245
+ return provider;
1246
+ }
1247
+ var friendliai = createFriendliAI({
1248
+ // compatibility: "compatible", // strict for FriendliAI API
1249
+ });
1250
+ export {
1251
+ FriendliAI,
1252
+ createFriendliAI,
1253
+ friendliai
1254
+ };
1255
+ //# sourceMappingURL=index.mjs.map