@friendliai/ai-provider 0.2.7-alpha.0 → 0.2.7-alpha.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @friendliai/ai-provider
2
2
 
3
+ ## 0.2.7-alpha.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 07b0162: enable regex on v5 (beta)
8
+ - 3f15a05: enable support Tool Assisted API
9
+
10
+ ## 0.2.7-alpha.1
11
+
12
+ ### Patch Changes
13
+
14
+ - dda6520: Added supported type model to friendli-provider
15
+
3
16
  ## 0.2.7-alpha.0
4
17
 
5
18
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -1,21 +1,35 @@
1
- import { LanguageModelV2 } from '@ai-sdk/provider';
1
+ import { LanguageModelV1ProviderDefinedTool, ProviderV2, LanguageModelV2, EmbeddingModelV2, ImageModelV2, TranscriptionModelV1, SpeechModelV1 } from '@ai-sdk/provider';
2
2
  import { FetchFunction } from '@ai-sdk/provider-utils';
3
3
  import { z } from 'zod';
4
4
 
5
5
  declare const FriendliAIServerlessModelIds: readonly ["meta-llama-3.1-8b-instruct", "meta-llama-3.3-70b-instruct", "deepseek-r1"];
6
6
  type FriendliAIServerlessModelId = (typeof FriendliAIServerlessModelIds)[number];
7
7
  type FriendliAILanguageModelId = FriendliAIServerlessModelId | (string & {});
8
- type FriendliAIBetaChatModelId = string & {};
8
+
9
+ declare function webUrlBetaTool(): LanguageModelV1ProviderDefinedTool;
10
+ declare function webSearchBetaTool(): LanguageModelV1ProviderDefinedTool;
11
+ declare function mathCalendarBetaTool(): LanguageModelV1ProviderDefinedTool;
12
+ declare function mathStatisticsBetaTool(): LanguageModelV1ProviderDefinedTool;
13
+ declare function mathCalculatorBetaTool(): LanguageModelV1ProviderDefinedTool;
14
+ declare function codePythonInterpreterBetaTool(): LanguageModelV1ProviderDefinedTool;
15
+ declare const friendliTools: {
16
+ webSearchBetaTool: typeof webSearchBetaTool;
17
+ webUrlBetaTool: typeof webUrlBetaTool;
18
+ mathCalendarBetaTool: typeof mathCalendarBetaTool;
19
+ mathStatisticsBetaTool: typeof mathStatisticsBetaTool;
20
+ mathCalculatorBetaTool: typeof mathCalculatorBetaTool;
21
+ codePythonInterpreterBetaTool: typeof codePythonInterpreterBetaTool;
22
+ };
9
23
 
10
24
  interface FriendliAIProviderSettings {
11
25
  /**
12
- * FriendliAI API key. (FRIENDLI__TOKEN)
26
+ * FriendliAI API key. (FRIENDLI_TOKEN)
13
27
  */
14
28
  apiKey?: string;
15
29
  /**
16
30
  * Base URL for the API calls.
17
31
  */
18
- baseURL?: string;
32
+ baseURL?: string | 'auto' | 'dedicated' | 'serverless' | 'serverless-tools';
19
33
  /**
20
34
  * Custom headers to include in the requests.
21
35
  */
@@ -30,35 +44,56 @@ interface FriendliAIProviderSettings {
30
44
  */
31
45
  fetch?: FetchFunction;
32
46
  }
33
- interface FriendliAIProvider {
47
+ interface FriendliAIProvider extends ProviderV2 {
34
48
  /**
35
49
  * Creates a model for text generation.
36
50
  */
37
51
  (modelId: FriendliAILanguageModelId): LanguageModelV2;
38
52
  /**
39
- * A model that has not yet been officially released
53
+ * Creates a chat model for text generation.
40
54
  */
41
- beta(modelId: FriendliAIBetaChatModelId): LanguageModelV2;
55
+ languageModel(modelId: FriendliAILanguageModelId): LanguageModelV2;
42
56
  /**
43
57
  * Creates a chat model for text generation.
44
58
  */
45
59
  chat(modelId: FriendliAILanguageModelId): LanguageModelV2;
46
- chatModel(modelId: FriendliAILanguageModelId): LanguageModelV2;
47
60
  /**
48
61
  * Creates a completion model for text generation.
49
62
  */
50
63
  completion(modelId: FriendliAILanguageModelId): LanguageModelV2;
51
- completionModel(modelId: FriendliAILanguageModelId): LanguageModelV2;
52
64
  /**
53
65
  * Creates a text embedding model for text generation.
66
+ * TODO: Implement for Dedicated users
67
+ */
68
+ embedding(modelId: string & {}): EmbeddingModelV2<string>;
69
+ textEmbeddingModel(modelId: string & {}): EmbeddingModelV2<string>;
70
+ /**
71
+ * Creates a model for image generation.
72
+ * TODO: Implement for Dedicated users
73
+ */
74
+ imageModel(modelId: string & {}): ImageModelV2;
75
+ /**
76
+ * Creates a model for transcription.
77
+ * TODO: Implement for Dedicated users
54
78
  */
55
- embedding(modelId: string & {}): LanguageModelV2;
56
- textEmbeddingModel(modelId: string & {}): LanguageModelV2;
79
+ transcription(modelId: string & {}): TranscriptionModelV1;
80
+ /**
81
+ * Creates a model for speech generation.
82
+ * TODO: Implement for Dedicated users
83
+ */
84
+ speech(modelId: string & {}): SpeechModelV1;
85
+ /**
86
+ * Friendli-specific tools.
87
+ */
88
+ tools: typeof friendliTools;
57
89
  }
58
90
  /**
59
91
  Create an FriendliAI provider instance.
60
92
  */
61
93
  declare function createFriendli(options?: FriendliAIProviderSettings): FriendliAIProvider;
94
+ /**
95
+ * Default FriendliAI provider instance.
96
+ */
62
97
  declare const friendli: FriendliAIProvider;
63
98
 
64
99
  declare const friendliaiErrorSchema: z.ZodObject<{
package/dist/index.d.ts CHANGED
@@ -1,21 +1,35 @@
1
- import { LanguageModelV2 } from '@ai-sdk/provider';
1
+ import { LanguageModelV1ProviderDefinedTool, ProviderV2, LanguageModelV2, EmbeddingModelV2, ImageModelV2, TranscriptionModelV1, SpeechModelV1 } from '@ai-sdk/provider';
2
2
  import { FetchFunction } from '@ai-sdk/provider-utils';
3
3
  import { z } from 'zod';
4
4
 
5
5
  declare const FriendliAIServerlessModelIds: readonly ["meta-llama-3.1-8b-instruct", "meta-llama-3.3-70b-instruct", "deepseek-r1"];
6
6
  type FriendliAIServerlessModelId = (typeof FriendliAIServerlessModelIds)[number];
7
7
  type FriendliAILanguageModelId = FriendliAIServerlessModelId | (string & {});
8
- type FriendliAIBetaChatModelId = string & {};
8
+
9
+ declare function webUrlBetaTool(): LanguageModelV1ProviderDefinedTool;
10
+ declare function webSearchBetaTool(): LanguageModelV1ProviderDefinedTool;
11
+ declare function mathCalendarBetaTool(): LanguageModelV1ProviderDefinedTool;
12
+ declare function mathStatisticsBetaTool(): LanguageModelV1ProviderDefinedTool;
13
+ declare function mathCalculatorBetaTool(): LanguageModelV1ProviderDefinedTool;
14
+ declare function codePythonInterpreterBetaTool(): LanguageModelV1ProviderDefinedTool;
15
+ declare const friendliTools: {
16
+ webSearchBetaTool: typeof webSearchBetaTool;
17
+ webUrlBetaTool: typeof webUrlBetaTool;
18
+ mathCalendarBetaTool: typeof mathCalendarBetaTool;
19
+ mathStatisticsBetaTool: typeof mathStatisticsBetaTool;
20
+ mathCalculatorBetaTool: typeof mathCalculatorBetaTool;
21
+ codePythonInterpreterBetaTool: typeof codePythonInterpreterBetaTool;
22
+ };
9
23
 
10
24
  interface FriendliAIProviderSettings {
11
25
  /**
12
- * FriendliAI API key. (FRIENDLI__TOKEN)
26
+ * FriendliAI API key. (FRIENDLI_TOKEN)
13
27
  */
14
28
  apiKey?: string;
15
29
  /**
16
30
  * Base URL for the API calls.
17
31
  */
18
- baseURL?: string;
32
+ baseURL?: string | 'auto' | 'dedicated' | 'serverless' | 'serverless-tools';
19
33
  /**
20
34
  * Custom headers to include in the requests.
21
35
  */
@@ -30,35 +44,56 @@ interface FriendliAIProviderSettings {
30
44
  */
31
45
  fetch?: FetchFunction;
32
46
  }
33
- interface FriendliAIProvider {
47
+ interface FriendliAIProvider extends ProviderV2 {
34
48
  /**
35
49
  * Creates a model for text generation.
36
50
  */
37
51
  (modelId: FriendliAILanguageModelId): LanguageModelV2;
38
52
  /**
39
- * A model that has not yet been officially released
53
+ * Creates a chat model for text generation.
40
54
  */
41
- beta(modelId: FriendliAIBetaChatModelId): LanguageModelV2;
55
+ languageModel(modelId: FriendliAILanguageModelId): LanguageModelV2;
42
56
  /**
43
57
  * Creates a chat model for text generation.
44
58
  */
45
59
  chat(modelId: FriendliAILanguageModelId): LanguageModelV2;
46
- chatModel(modelId: FriendliAILanguageModelId): LanguageModelV2;
47
60
  /**
48
61
  * Creates a completion model for text generation.
49
62
  */
50
63
  completion(modelId: FriendliAILanguageModelId): LanguageModelV2;
51
- completionModel(modelId: FriendliAILanguageModelId): LanguageModelV2;
52
64
  /**
53
65
  * Creates a text embedding model for text generation.
66
+ * TODO: Implement for Dedicated users
67
+ */
68
+ embedding(modelId: string & {}): EmbeddingModelV2<string>;
69
+ textEmbeddingModel(modelId: string & {}): EmbeddingModelV2<string>;
70
+ /**
71
+ * Creates a model for image generation.
72
+ * TODO: Implement for Dedicated users
73
+ */
74
+ imageModel(modelId: string & {}): ImageModelV2;
75
+ /**
76
+ * Creates a model for transcription.
77
+ * TODO: Implement for Dedicated users
54
78
  */
55
- embedding(modelId: string & {}): LanguageModelV2;
56
- textEmbeddingModel(modelId: string & {}): LanguageModelV2;
79
+ transcription(modelId: string & {}): TranscriptionModelV1;
80
+ /**
81
+ * Creates a model for speech generation.
82
+ * TODO: Implement for Dedicated users
83
+ */
84
+ speech(modelId: string & {}): SpeechModelV1;
85
+ /**
86
+ * Friendli-specific tools.
87
+ */
88
+ tools: typeof friendliTools;
57
89
  }
58
90
  /**
59
91
  Create an FriendliAI provider instance.
60
92
  */
61
93
  declare function createFriendli(options?: FriendliAIProviderSettings): FriendliAIProvider;
94
+ /**
95
+ * Default FriendliAI provider instance.
96
+ */
62
97
  declare const friendli: FriendliAIProvider;
63
98
 
64
99
  declare const friendliaiErrorSchema: z.ZodObject<{
package/dist/index.js CHANGED
@@ -64,6 +64,7 @@ function prepareTools({
64
64
  tools,
65
65
  toolChoice
66
66
  }) {
67
+ var _a;
67
68
  tools = (tools == null ? void 0 : tools.length) ? tools : void 0;
68
69
  const toolWarnings = [];
69
70
  if (tools == null) {
@@ -72,7 +73,10 @@ function prepareTools({
72
73
  const openaiCompatTools = [];
73
74
  for (const tool of tools) {
74
75
  if (tool.type === "provider-defined") {
75
- toolWarnings.push({ type: "unsupported-tool", tool });
76
+ openaiCompatTools.push({
77
+ // NOTE: It would be better to use tool.name, but since ":" is replaced with "_", the following code is used instead
78
+ type: (_a = tool.id.split(".")[1]) != null ? _a : "unknown"
79
+ });
76
80
  } else {
77
81
  openaiCompatTools.push({
78
82
  type: "function",
@@ -143,18 +147,24 @@ var FriendliAIChatLanguageModel = class {
143
147
  topK,
144
148
  frequencyPenalty,
145
149
  presencePenalty,
146
- // providerOptions,
150
+ providerOptions,
147
151
  stopSequences,
148
152
  responseFormat,
149
153
  seed,
150
154
  toolChoice,
151
- tools
155
+ tools,
156
+ stream
152
157
  }) {
153
158
  var _a;
154
159
  const warnings = [];
155
160
  if (topK != null) {
156
161
  warnings.push({ type: "unsupported-setting", setting: "topK" });
157
162
  }
163
+ const friendliOptions = await (0, import_provider_utils2.parseProviderOptions)({
164
+ provider: "friendli",
165
+ providerOptions,
166
+ schema: friendliProviderOptionsSchema
167
+ });
158
168
  if ((responseFormat == null ? void 0 : responseFormat.type) === "json" && responseFormat.schema != null && !this.supportsStructuredOutputs) {
159
169
  warnings.push({
160
170
  type: "unsupported-setting",
@@ -177,6 +187,7 @@ var FriendliAIChatLanguageModel = class {
177
187
  // model specific settings:
178
188
  // user: compatibleOptions.user,
179
189
  // standardized settings:
190
+ stream,
180
191
  max_tokens: maxOutputTokens,
181
192
  temperature,
182
193
  top_p: topP,
@@ -189,7 +200,10 @@ var FriendliAIChatLanguageModel = class {
189
200
  name: (_a = responseFormat.name) != null ? _a : "response",
190
201
  description: responseFormat.description
191
202
  }
192
- } : { type: "json_object" } : void 0,
203
+ } : { type: "json_object" } : (friendliOptions == null ? void 0 : friendliOptions.regex) != null ? {
204
+ type: "regex",
205
+ schema: friendliOptions.regex
206
+ } : void 0,
193
207
  stop: stopSequences,
194
208
  seed,
195
209
  // ...providerOptions?.[this.providerOptionsName],
@@ -198,14 +212,15 @@ var FriendliAIChatLanguageModel = class {
198
212
  messages: (0, import_internal.convertToOpenAICompatibleChatMessages)(prompt),
199
213
  // tools:
200
214
  tools: openaiTools,
201
- tool_choice: openaiToolChoice
215
+ tool_choice: openaiToolChoice,
216
+ parallel_tool_calls: friendliOptions == null ? void 0 : friendliOptions.parallelToolCalls
202
217
  },
203
218
  warnings: [...warnings, ...toolWarnings]
204
219
  };
205
220
  }
206
221
  async doGenerate(options) {
207
222
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
208
- const { args, warnings } = await this.getArgs({ ...options });
223
+ const { args, warnings } = await this.getArgs({ ...options, stream: false });
209
224
  const body = JSON.stringify(args);
210
225
  const {
211
226
  responseHeaders,
@@ -271,7 +286,7 @@ var FriendliAIChatLanguageModel = class {
271
286
  }
272
287
  async doStream(options) {
273
288
  var _a;
274
- const { args, warnings } = await this.getArgs({ ...options });
289
+ const { args, warnings } = await this.getArgs({ ...options, stream: true });
275
290
  const body = {
276
291
  ...args,
277
292
  stream: true,
@@ -647,6 +662,75 @@ var createOpenAICompatibleChatChunkSchema = (errorSchema) => import_zod2.z.union
647
662
  }),
648
663
  errorSchema
649
664
  ]);
665
+ var friendliProviderOptionsSchema = import_zod2.z.object({
666
+ /**
667
+ * Whether to enable parallel function calling during tool use. Default to true.
668
+ */
669
+ parallelToolCalls: import_zod2.z.boolean().nullish(),
670
+ /**
671
+ * BETA FEATURE: You can write a regular expression to force output that satisfies that regular expression.
672
+ */
673
+ // regex: z.instanceof(RegExp).nullish(),
674
+ regex: import_zod2.z.string().nullish()
675
+ });
676
+
677
+ // src/friendli-tools.ts
678
+ function webUrlBetaTool() {
679
+ return {
680
+ type: "provider-defined",
681
+ id: "friendli.web:url",
682
+ name: "web:url",
683
+ args: {}
684
+ };
685
+ }
686
+ function webSearchBetaTool() {
687
+ return {
688
+ type: "provider-defined",
689
+ id: "friendli.web:search",
690
+ name: "web:search",
691
+ args: {}
692
+ };
693
+ }
694
+ function mathCalendarBetaTool() {
695
+ return {
696
+ type: "provider-defined",
697
+ id: "friendli.math:calendar",
698
+ name: "math:calendar",
699
+ args: {}
700
+ };
701
+ }
702
+ function mathStatisticsBetaTool() {
703
+ return {
704
+ type: "provider-defined",
705
+ id: "friendli.math:statistics",
706
+ name: "math:statistics",
707
+ args: {}
708
+ };
709
+ }
710
+ function mathCalculatorBetaTool() {
711
+ return {
712
+ type: "provider-defined",
713
+ id: "friendli.math:calculator",
714
+ name: "math:calculator",
715
+ args: {}
716
+ };
717
+ }
718
+ function codePythonInterpreterBetaTool() {
719
+ return {
720
+ type: "provider-defined",
721
+ id: "friendli.code:python-interpreter",
722
+ name: "code:python-interpreter",
723
+ args: {}
724
+ };
725
+ }
726
+ var friendliTools = {
727
+ webSearchBetaTool,
728
+ webUrlBetaTool,
729
+ mathCalendarBetaTool,
730
+ mathStatisticsBetaTool,
731
+ mathCalculatorBetaTool,
732
+ codePythonInterpreterBetaTool
733
+ };
650
734
 
651
735
  // src/friendli-provider.ts
652
736
  function createFriendli(options = {}) {
@@ -659,54 +743,50 @@ function createFriendli(options = {}) {
659
743
  "X-Friendli-Team": options.teamId,
660
744
  ...options.headers
661
745
  });
662
- const baseURLAutoSelect = (modelId, endpoint, baseURL, tools) => {
663
- const customBaseURL = (0, import_provider_utils3.withoutTrailingSlash)(baseURL);
664
- if (typeof customBaseURL === "string") {
665
- return { baseURL: customBaseURL, type: "custom" };
666
- }
746
+ const baseURLAutoSelect = (modelId, baseURL) => {
667
747
  const FriendliBaseURL = {
668
- beta: "https://api.friendli.ai/serverless/beta",
669
748
  serverless: "https://api.friendli.ai/serverless/v1",
670
- tools: "https://api.friendli.ai/serverless/tools/v1",
749
+ serverless_tools: "https://api.friendli.ai/serverless/tools/v1",
671
750
  dedicated: "https://api.friendli.ai/dedicated/v1"
672
751
  };
673
- if (endpoint === "beta") {
674
- return {
675
- baseURL: FriendliBaseURL.beta,
676
- type: "beta"
677
- };
752
+ const customBaseURL = (0, import_provider_utils3.withoutTrailingSlash)(baseURL);
753
+ if (typeof customBaseURL === "string" && customBaseURL !== "dedicated" && customBaseURL !== "serverless" && customBaseURL !== "serverless-tools") {
754
+ return { baseURL: customBaseURL, type: "custom" };
678
755
  }
679
- if (
680
- // If the endpoint setting is serverless or auto and the model is floating on serverless,
681
- endpoint === "serverless" || endpoint === "auto" && Object.values(FriendliAIServerlessModelIds).includes(
682
- modelId
683
- )
684
- ) {
685
- if (tools && tools.length > 0) {
756
+ switch (baseURL) {
757
+ case "dedicated":
686
758
  return {
687
- baseURL: FriendliBaseURL.tools,
688
- type: "tools"
759
+ baseURL: FriendliBaseURL.dedicated,
760
+ type: "dedicated"
689
761
  };
690
- }
691
- return {
692
- baseURL: FriendliBaseURL.serverless,
693
- type: "serverless"
694
- };
695
- } else {
696
- return {
697
- baseURL: FriendliBaseURL.dedicated,
698
- type: "dedicated"
699
- };
762
+ case "serverless":
763
+ return {
764
+ baseURL: FriendliBaseURL.serverless,
765
+ type: "serverless"
766
+ };
767
+ case "serverless-tools":
768
+ return {
769
+ baseURL: FriendliBaseURL.serverless_tools,
770
+ type: "serverless-tools"
771
+ };
772
+ default:
773
+ if (FriendliAIServerlessModelIds.includes(
774
+ modelId
775
+ )) {
776
+ return {
777
+ baseURL: FriendliBaseURL.serverless,
778
+ type: "serverless"
779
+ };
780
+ } else {
781
+ return {
782
+ baseURL: FriendliBaseURL.dedicated,
783
+ type: "dedicated"
784
+ };
785
+ }
700
786
  }
701
787
  };
702
- const createChatModel = (modelId) => {
703
- const { baseURL, type } = baseURLAutoSelect(
704
- modelId,
705
- // settings.endpoint || 'auto',
706
- "auto",
707
- options.baseURL
708
- // settings.tools,
709
- );
788
+ const createLanguageModel = (modelId) => {
789
+ const { baseURL, type } = baseURLAutoSelect(modelId, options.baseURL);
710
790
  return new FriendliAIChatLanguageModel(modelId, {
711
791
  provider: `friendliai.${type}.chat`,
712
792
  url: ({ path }) => `${baseURL}${path}`,
@@ -715,12 +795,7 @@ function createFriendli(options = {}) {
715
795
  });
716
796
  };
717
797
  const createCompletionModel = (modelId) => {
718
- const { baseURL, type } = baseURLAutoSelect(
719
- modelId,
720
- // settings.endpoint || 'auto',
721
- "auto",
722
- options.baseURL
723
- );
798
+ const { baseURL, type } = baseURLAutoSelect(modelId, options.baseURL);
724
799
  return new import_openai_compatible.OpenAICompatibleCompletionLanguageModel(modelId, {
725
800
  provider: `friendliai.${type}.completion`,
726
801
  url: ({ path }) => `${baseURL}${path}`,
@@ -729,35 +804,31 @@ function createFriendli(options = {}) {
729
804
  errorStructure: friendliaiErrorStructure
730
805
  });
731
806
  };
732
- const createBetaModel = (modelId) => {
733
- const { baseURL, type } = baseURLAutoSelect(
734
- modelId,
735
- "beta",
736
- options.baseURL
737
- );
738
- return new FriendliAIChatLanguageModel(modelId, {
739
- provider: `friendliai.${type}.chat`,
740
- url: ({ path }) => `${baseURL}${path}`,
741
- headers: getHeaders,
742
- fetch: options.fetch
743
- });
744
- };
745
807
  const createTextEmbeddingModel = (modelId) => {
746
808
  throw new import_provider3.NoSuchModelError({ modelId, modelType: "textEmbeddingModel" });
747
809
  };
748
- const provider = function(modelId) {
749
- return createChatModel(modelId);
810
+ const createImageModel = (modelId) => {
811
+ throw new import_provider3.NoSuchModelError({ modelId, modelType: "imageModel" });
812
+ };
813
+ const createTranscriptionModel = (modelId) => {
814
+ throw new import_provider3.NoSuchModelError({ modelId, modelType: "languageModel" });
815
+ };
816
+ const createSpeechModel = (modelId) => {
817
+ throw new import_provider3.NoSuchModelError({ modelId, modelType: "languageModel" });
750
818
  };
751
- provider.beta = createBetaModel;
752
- provider.chat = createChatModel;
753
- provider.chatModel = createChatModel;
819
+ const provider = (modelId) => createLanguageModel(modelId);
820
+ provider.languageModel = createLanguageModel;
821
+ provider.chat = createLanguageModel;
754
822
  provider.completion = createCompletionModel;
755
- provider.completionModel = createCompletionModel;
756
823
  provider.embedding = createTextEmbeddingModel;
757
824
  provider.textEmbeddingModel = createTextEmbeddingModel;
825
+ provider.imageModel = createImageModel;
826
+ provider.transcription = createTranscriptionModel;
827
+ provider.speech = createSpeechModel;
828
+ provider.tools = friendliTools;
758
829
  return provider;
759
830
  }
760
- var friendli = createFriendli({});
831
+ var friendli = createFriendli();
761
832
  // Annotate the CommonJS export names for ESM import in node:
762
833
  0 && (module.exports = {
763
834
  createFriendli,