@brotu/ai 0.3.0 → 0.4.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.js CHANGED
@@ -2,6 +2,7 @@ import {
2
2
  BYTEPLUS_CATALOG,
3
3
  BYTEPLUS_IMAGE_MODELS,
4
4
  BYTEPLUS_MODELS,
5
+ DEFAULT_BROTU_API_URL,
5
6
  ELEVENLABS_CATALOG,
6
7
  ELEVENLABS_MODELS,
7
8
  ELEVENLABS_OUTPUT_FORMATS,
@@ -35,7 +36,7 @@ import {
35
36
  resetCatalog,
36
37
  resolveProvider,
37
38
  videoPathFor
38
- } from "./chunk-PL534BFN.js";
39
+ } from "./chunk-QOWHHKSI.js";
39
40
 
40
41
  // src/lib/jobs.ts
41
42
  import { AsyncLocalStorage } from "async_hooks";
@@ -91,12 +92,316 @@ function estimateFor(provider, type, params, defaults) {
91
92
  };
92
93
  }
93
94
 
95
+ // src/adapters/brotu.adapter.ts
96
+ var DEFAULT_API_URL = "https://api.brotu.app";
97
+ var POLL_INTERVAL_MS = 3e3;
98
+ var DEFAULT_MAX_POLL_ATTEMPTS = 400;
99
+ var PLATFORM_MODEL_IDS = {
100
+ "kling/v2-6": "kling-2.6",
101
+ "kling/v3": "kling-3.0/video",
102
+ "dreamina-seedance-2-5-260628": "bytedance/seedance-2-5",
103
+ "dreamina-seedance-2-0-260128": "bytedance/seedance-2",
104
+ "dreamina-seedance-2-0-fast-260128": "bytedance/seedance-2-fast",
105
+ "gpt-image-1.5": "gpt-image/1.5"
106
+ };
107
+ var UNSUPPORTED_VIA_CREDITS = "Speech and text generate on the vendor. Pass that provider's key.";
108
+ var BrotuAdapter = class {
109
+ constructor(opts) {
110
+ this.opts = opts;
111
+ }
112
+ opts;
113
+ providerName = "brotu";
114
+ supportedTypes = ["image", "video"];
115
+ workspaceIdCache;
116
+ get origin() {
117
+ return (this.opts.apiUrl ?? DEFAULT_API_URL).replace(/\/$/, "");
118
+ }
119
+ headers() {
120
+ return {
121
+ Authorization: `Bearer ${this.opts.apiKey}`,
122
+ "Content-Type": "application/json"
123
+ };
124
+ }
125
+ async workspaceId() {
126
+ if (this.opts.workspaceId) return this.opts.workspaceId;
127
+ if (this.workspaceIdCache) return this.workspaceIdCache;
128
+ const payload = await this.request("/api/v1/studio/default-workspace");
129
+ const id = payload.workspaceId?.trim();
130
+ if (!id) {
131
+ throw new Error(
132
+ "This Brotu account has no workspace. Open https://brotu.app and create one."
133
+ );
134
+ }
135
+ this.workspaceIdCache = id;
136
+ return id;
137
+ }
138
+ studioPath(path, workspaceId) {
139
+ const joiner = path.includes("?") ? "&" : "?";
140
+ return `${path}${joiner}workspaceId=${encodeURIComponent(workspaceId)}`;
141
+ }
142
+ async request(path, init) {
143
+ const response = await fetch(`${this.origin}${path}`, {
144
+ ...init,
145
+ headers: { ...this.headers(), ...init?.headers }
146
+ });
147
+ const text = await response.text();
148
+ let body = void 0;
149
+ if (text) {
150
+ try {
151
+ body = JSON.parse(text);
152
+ } catch {
153
+ body = text;
154
+ }
155
+ }
156
+ if (!response.ok) {
157
+ const parsed = body;
158
+ const message = parsed && typeof parsed === "object" ? parsed.error?.message || parsed.message || text : text;
159
+ throw new Error(message || `Brotu API ${response.status}`);
160
+ }
161
+ return body;
162
+ }
163
+ platformModel(modelId) {
164
+ return PLATFORM_MODEL_IDS[modelId] ?? modelId;
165
+ }
166
+ async startGeneration(kind, params) {
167
+ const modelId = params.model ?? "";
168
+ const workspaceId = await this.workspaceId();
169
+ const path = kind === "video" ? "/api/v1/studio/videos" : "/api/v1/studio/images";
170
+ const body = kind === "video" ? this.videoBody(params, modelId) : this.imageBody(params, modelId);
171
+ const result = await this.request(
172
+ this.studioPath(path, workspaceId),
173
+ { method: "POST", body: JSON.stringify(body) }
174
+ );
175
+ const generationId = result.generationId?.trim();
176
+ if (!generationId) {
177
+ throw new Error("Brotu accepted the request but returned no generation id.");
178
+ }
179
+ return { generationId, workspaceId };
180
+ }
181
+ imageBody(params, modelId) {
182
+ return {
183
+ prompt: params.prompt,
184
+ model: this.platformModel(modelId),
185
+ aspectRatio: params.aspectRatio,
186
+ resolution: params.resolution,
187
+ negativePrompt: params.negativePrompt,
188
+ outputFormat: params.outputFormat,
189
+ seed: params.seed,
190
+ referenceImages: params.referenceImages
191
+ };
192
+ }
193
+ videoBody(params, modelId) {
194
+ return {
195
+ prompt: params.prompt,
196
+ model: this.platformModel(modelId),
197
+ duration: params.duration,
198
+ resolution: params.resolution,
199
+ aspectRatio: params.aspectRatio,
200
+ mode: params.mode,
201
+ withAudio: params.withAudio,
202
+ seed: params.seed,
203
+ imageUrl: params.imageUrl,
204
+ imageUrls: params.imageUrls,
205
+ videoUrl: params.videoUrl,
206
+ videoUrls: params.videoUrls,
207
+ referenceImages: params.referenceImages
208
+ };
209
+ }
210
+ async run(kind, params) {
211
+ const startedAt = Date.now();
212
+ const modelId = params.model ?? "(none)";
213
+ const failure = (error) => ({
214
+ success: false,
215
+ outputs: [],
216
+ creditsUsed: 0,
217
+ provider: this.providerName,
218
+ model: modelId,
219
+ processingTimeMs: Date.now() - startedAt,
220
+ error
221
+ });
222
+ let submitted;
223
+ try {
224
+ submitted = await this.startGeneration(kind, params);
225
+ } catch (error) {
226
+ return failure(error instanceof Error ? error.message : String(error));
227
+ }
228
+ const pollEndpoint = this.studioPath(
229
+ `/api/v1/studio/generations/${submitted.generationId}`,
230
+ submitted.workspaceId
231
+ );
232
+ if (isSubmitMode()) {
233
+ throw new PendingJob(submitted.generationId, pollEndpoint);
234
+ }
235
+ const job = {
236
+ id: submitted.generationId,
237
+ provider: this.providerName,
238
+ model: modelId,
239
+ kind,
240
+ pollEndpoint,
241
+ params,
242
+ submittedAt: new Date(startedAt).toISOString()
243
+ };
244
+ const maxAttempts = this.opts.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS;
245
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
246
+ const snapshot = await this.completeJob(job);
247
+ if (snapshot.status === "failed") {
248
+ return failure(snapshot.error ?? "Brotu generation failed.");
249
+ }
250
+ if (snapshot.status === "succeeded" && snapshot.result) {
251
+ return { ...snapshot.result, processingTimeMs: Date.now() - startedAt };
252
+ }
253
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
254
+ }
255
+ return failure(
256
+ `Brotu generation ${submitted.generationId} did not finish after ${maxAttempts} checks.`
257
+ );
258
+ }
259
+ async completeJob(job) {
260
+ const workspaceId = this.workspaceFromPoll(job.pollEndpoint) ?? await this.workspaceId();
261
+ const path = this.studioPath(
262
+ `/api/v1/studio/generations/${job.id}`,
263
+ workspaceId
264
+ );
265
+ const generation = await this.request(path);
266
+ const status = (generation.status ?? "").toLowerCase();
267
+ if (status === "failed") {
268
+ return {
269
+ status: "failed",
270
+ error: generation.errorMessage ?? "Brotu generation failed."
271
+ };
272
+ }
273
+ if (status !== "completed") {
274
+ return { status: "pending" };
275
+ }
276
+ const outputs = outputsFrom(generation, job.kind);
277
+ return {
278
+ status: "succeeded",
279
+ result: {
280
+ success: true,
281
+ outputs,
282
+ creditsUsed: generation.creditsUsed ?? 0,
283
+ provider: this.providerName,
284
+ model: job.model,
285
+ processingTimeMs: 0
286
+ }
287
+ };
288
+ }
289
+ workspaceFromPoll(pollEndpoint) {
290
+ if (!pollEndpoint) return void 0;
291
+ try {
292
+ const url = new URL(pollEndpoint, "https://brotu.invalid");
293
+ return url.searchParams.get("workspaceId") ?? void 0;
294
+ } catch {
295
+ return void 0;
296
+ }
297
+ }
298
+ generateImage(params) {
299
+ return this.run("image", params);
300
+ }
301
+ generateVideo(params) {
302
+ return this.run("video", params);
303
+ }
304
+ async generateText(params) {
305
+ return {
306
+ success: false,
307
+ outputs: [],
308
+ creditsUsed: 0,
309
+ provider: this.providerName,
310
+ model: params.model ?? "(none)",
311
+ processingTimeMs: 0,
312
+ error: UNSUPPORTED_VIA_CREDITS
313
+ };
314
+ }
315
+ async generateAudio(params) {
316
+ return {
317
+ success: false,
318
+ outputs: [],
319
+ creditsUsed: 0,
320
+ provider: this.providerName,
321
+ model: params.model ?? "(none)",
322
+ processingTimeMs: 0,
323
+ error: UNSUPPORTED_VIA_CREDITS
324
+ };
325
+ }
326
+ async estimateCost(type, params) {
327
+ if (type === "audio" || type === "text") {
328
+ const estimate = estimateFor(this.providerName, type, params);
329
+ return {
330
+ ...estimate,
331
+ usd: null,
332
+ note: UNSUPPORTED_VIA_CREDITS
333
+ };
334
+ }
335
+ try {
336
+ const workspaceId = await this.workspaceId();
337
+ const video = params;
338
+ const image = params;
339
+ const payload = await this.request(
340
+ this.studioPath("/api/v1/studio/estimate", workspaceId),
341
+ {
342
+ method: "POST",
343
+ body: JSON.stringify({
344
+ model: this.platformModel(params.model ?? ""),
345
+ duration: video.duration,
346
+ resolution: video.resolution ?? image.resolution,
347
+ aspectRatio: video.aspectRatio ?? image.aspectRatio,
348
+ withAudio: video.withAudio,
349
+ hasReferenceImage: Boolean(
350
+ video.imageUrl || video.imageUrls?.length || video.referenceImages?.length || image.referenceImages?.length
351
+ ),
352
+ hasReferenceVideo: Boolean(video.videoUrl || video.videoUrls?.length),
353
+ quality: image.quality
354
+ })
355
+ }
356
+ );
357
+ const credits = payload.estimatedCredits ?? 0;
358
+ return {
359
+ unit: type === "video" ? "second" : "image",
360
+ units: credits,
361
+ usd: null,
362
+ note: `${credits} Brotu credit${credits === 1 ? "" : "s"}. A vendor key generates on that provider.`,
363
+ provider: this.providerName,
364
+ model: params.model ?? ""
365
+ };
366
+ } catch (error) {
367
+ const estimate = estimateFor(this.providerName, type, params);
368
+ return {
369
+ ...estimate,
370
+ usd: null,
371
+ note: error instanceof Error ? error.message : "Could not estimate Brotu credits."
372
+ };
373
+ }
374
+ }
375
+ supportsModel() {
376
+ return true;
377
+ }
378
+ getAvailableModels() {
379
+ return [];
380
+ }
381
+ };
382
+ function outputsFrom(generation, kind) {
383
+ const bucket = generation.outputs;
384
+ const urls = kind === "video" ? bucket?.videos ?? bucket?.images ?? [] : bucket?.images ?? bucket?.videos ?? [];
385
+ const copies = bucket?.copies ?? [];
386
+ const mimeType = kind === "video" ? "video/mp4" : "image/png";
387
+ const fromUrls = urls.filter(Boolean).map((url) => ({
388
+ url,
389
+ mimeType
390
+ }));
391
+ if (fromUrls.length > 0) return fromUrls;
392
+ return copies.filter(Boolean).map((url) => ({
393
+ url,
394
+ mimeType: "text/plain",
395
+ raw: { text: url }
396
+ }));
397
+ }
398
+
94
399
  // src/adapters/byteplus.adapter.ts
95
400
  var DEFAULT_BASE_URL = "https://ark.ap-southeast.bytepluses.com";
96
401
  var TASKS_PATH = "/api/v3/contents/generations/tasks";
97
402
  var IMAGES_PATH = "/api/v3/images/generations";
98
- var POLL_INTERVAL_MS = 5e3;
99
- var DEFAULT_MAX_POLL_ATTEMPTS = 240;
403
+ var POLL_INTERVAL_MS2 = 5e3;
404
+ var DEFAULT_MAX_POLL_ATTEMPTS2 = 240;
100
405
  var BytePlusAdapter = class {
101
406
  providerName = "byteplus";
102
407
  supportedTypes = ["image", "video"];
@@ -296,7 +601,7 @@ var BytePlusAdapter = class {
296
601
  params,
297
602
  submittedAt: new Date(startedAt).toISOString()
298
603
  };
299
- const maxAttempts = this.opts.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS;
604
+ const maxAttempts = this.opts.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS2;
300
605
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
301
606
  const snapshot = await this.completeJob(job);
302
607
  if (snapshot.status === "failed") {
@@ -305,7 +610,7 @@ var BytePlusAdapter = class {
305
610
  if (snapshot.status === "succeeded" && snapshot.result) {
306
611
  return { ...snapshot.result, processingTimeMs: Date.now() - startedAt };
307
612
  }
308
- await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
613
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS2));
309
614
  }
310
615
  return failure(
311
616
  `Ark task ${taskId} did not finish after ${maxAttempts} checks.`
@@ -582,8 +887,8 @@ var ElevenLabsAdapter = class {
582
887
  // src/adapters/google.adapter.ts
583
888
  var DEFAULT_BASE_URL3 = "https://generativelanguage.googleapis.com";
584
889
  var INTERACTIONS_PATH = "/v1beta/interactions";
585
- var POLL_INTERVAL_MS2 = 1e4;
586
- var DEFAULT_MAX_POLL_ATTEMPTS2 = 120;
890
+ var POLL_INTERVAL_MS3 = 1e4;
891
+ var DEFAULT_MAX_POLL_ATTEMPTS3 = 120;
587
892
  var GoogleAdapter = class {
588
893
  providerName = "google";
589
894
  supportedTypes = [
@@ -855,7 +1160,7 @@ var GoogleAdapter = class {
855
1160
  params,
856
1161
  submittedAt: new Date(startedAt).toISOString()
857
1162
  };
858
- const maxAttempts = this.opts.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS2;
1163
+ const maxAttempts = this.opts.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS3;
859
1164
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
860
1165
  const snapshot = await this.completeJob(job);
861
1166
  if (snapshot.status === "failed") {
@@ -864,7 +1169,7 @@ var GoogleAdapter = class {
864
1169
  if (snapshot.status === "succeeded" && snapshot.result) {
865
1170
  return { ...snapshot.result, processingTimeMs: Date.now() - startedAt };
866
1171
  }
867
- await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS2));
1172
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS3));
868
1173
  }
869
1174
  return failure(`Veo operation ${operation} did not finish in time.`);
870
1175
  }
@@ -1079,8 +1384,8 @@ var GoogleAdapter = class {
1079
1384
 
1080
1385
  // src/adapters/kling.adapter.ts
1081
1386
  var DEFAULT_BASE_URL4 = "https://api-singapore.klingai.com";
1082
- var POLL_INTERVAL_MS3 = 5e3;
1083
- var DEFAULT_MAX_POLL_ATTEMPTS3 = 240;
1387
+ var POLL_INTERVAL_MS4 = 5e3;
1388
+ var DEFAULT_MAX_POLL_ATTEMPTS4 = 240;
1084
1389
  function stateOf(task) {
1085
1390
  const raw = (task.status ?? task.task_status ?? "").toLowerCase();
1086
1391
  if (raw === "failed") return "failed";
@@ -1277,7 +1582,7 @@ var KlingAdapter = class {
1277
1582
  params,
1278
1583
  submittedAt: new Date(startedAt).toISOString()
1279
1584
  };
1280
- const maxAttempts = this.opts.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS3;
1585
+ const maxAttempts = this.opts.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS4;
1281
1586
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
1282
1587
  const snapshot = await this.completeJob(job);
1283
1588
  if (snapshot.status === "failed") {
@@ -1286,7 +1591,7 @@ var KlingAdapter = class {
1286
1591
  if (snapshot.status === "succeeded" && snapshot.result) {
1287
1592
  return { ...snapshot.result, processingTimeMs: Date.now() - startedAt };
1288
1593
  }
1289
- await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS3));
1594
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS4));
1290
1595
  }
1291
1596
  return failure(
1292
1597
  `Kling task ${submitted.taskId} did not finish after ${maxAttempts} checks.`
@@ -1657,8 +1962,8 @@ var OpenAIAdapter = class {
1657
1962
  // src/adapters/qwen.adapter.ts
1658
1963
  var DEFAULT_BASE_URL6 = "https://dashscope-intl.aliyuncs.com";
1659
1964
  var TASKS_PATH2 = "/api/v1/tasks";
1660
- var POLL_INTERVAL_MS4 = 5e3;
1661
- var DEFAULT_MAX_POLL_ATTEMPTS4 = 240;
1965
+ var POLL_INTERVAL_MS5 = 5e3;
1966
+ var DEFAULT_MAX_POLL_ATTEMPTS5 = 240;
1662
1967
  var QwenAdapter = class {
1663
1968
  providerName = "qwen";
1664
1969
  supportedTypes = ["image", "video"];
@@ -1865,7 +2170,7 @@ var QwenAdapter = class {
1865
2170
  params,
1866
2171
  submittedAt: new Date(startedAt).toISOString()
1867
2172
  };
1868
- const maxAttempts = this.opts.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS4;
2173
+ const maxAttempts = this.opts.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS5;
1869
2174
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
1870
2175
  const snapshot = await this.completeJob(job);
1871
2176
  if (snapshot.status === "failed") {
@@ -1874,7 +2179,7 @@ var QwenAdapter = class {
1874
2179
  if (snapshot.status === "succeeded" && snapshot.result) {
1875
2180
  return { ...snapshot.result, processingTimeMs: Date.now() - startedAt };
1876
2181
  }
1877
- await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS4));
2182
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS5));
1878
2183
  }
1879
2184
  return failure(
1880
2185
  `DashScope task ${taskId} did not finish after ${maxAttempts} checks.`
@@ -2305,9 +2610,14 @@ var NATIVE_PROVIDERS = [
2305
2610
  "qwen"
2306
2611
  ];
2307
2612
  function brotuClient(options) {
2308
- if (Object.keys(options.providers).length === 0) {
2309
- throw new Error("brotuClient requires at least one provider API key.");
2613
+ const apiKey = options.apiKey?.trim();
2614
+ if (!apiKey) {
2615
+ throw new Error(
2616
+ "Pass a Brotu API key (brotu_sk_\u2026). Get one at https://brotu.app."
2617
+ );
2310
2618
  }
2619
+ const optionsWithKey = { ...options, apiKey };
2620
+ const vendors = optionsWithKey.providers ?? {};
2311
2621
  registerModels(options.models);
2312
2622
  let registeredWebhook = resolveWebhook(options.webhook);
2313
2623
  const notifiedJobIds = /* @__PURE__ */ new Set();
@@ -2331,7 +2641,7 @@ function brotuClient(options) {
2331
2641
  }
2332
2642
  let provider;
2333
2643
  try {
2334
- provider = resolveProvider(modelId, options);
2644
+ provider = resolveProvider(modelId, optionsWithKey);
2335
2645
  } catch (error) {
2336
2646
  return failFrom("missing_key", error, { model: modelId });
2337
2647
  }
@@ -2352,6 +2662,13 @@ function brotuClient(options) {
2352
2662
  return ok({ adapter, provider: provider.id, model: modelId });
2353
2663
  }
2354
2664
  function buildAdapter(provider) {
2665
+ if (provider.id === "brotu") {
2666
+ return new BrotuAdapter({
2667
+ apiKey,
2668
+ apiUrl: optionsWithKey.apiUrl,
2669
+ workspaceId: optionsWithKey.workspaceId
2670
+ });
2671
+ }
2355
2672
  if (provider.id === "kling") {
2356
2673
  return new KlingAdapter({
2357
2674
  apiKey: provider.apiKey,
@@ -2626,7 +2943,7 @@ function brotuClient(options) {
2626
2943
  }
2627
2944
  }
2628
2945
  function klingNamespace() {
2629
- const configured = options.providers.kling;
2946
+ const configured = vendors.kling;
2630
2947
  if (!configured) return void 0;
2631
2948
  const adapter = new KlingAdapter({
2632
2949
  apiKey: configured.apiKey,
@@ -2651,7 +2968,7 @@ function brotuClient(options) {
2651
2968
  };
2652
2969
  }
2653
2970
  function googleNamespace() {
2654
- const configured = options.providers.google;
2971
+ const configured = vendors.google;
2655
2972
  if (!configured) return void 0;
2656
2973
  const adapter = new GoogleAdapter({
2657
2974
  apiKey: configured.apiKey,
@@ -2734,7 +3051,7 @@ function brotuClient(options) {
2734
3051
  }
2735
3052
  }
2736
3053
  },
2737
- models: () => getAvailableModels(options),
3054
+ models: () => getAvailableModels(optionsWithKey),
2738
3055
  estimateCost: async (type, params) => {
2739
3056
  const routed = route(params.model);
2740
3057
  if (routed.error) return fail(routed.error);
@@ -2752,7 +3069,9 @@ function brotuClient(options) {
2752
3069
  export {
2753
3070
  BYTEPLUS_CATALOG,
2754
3071
  BYTEPLUS_MODELS,
3072
+ BrotuAdapter,
2755
3073
  BytePlusAdapter,
3074
+ DEFAULT_BROTU_API_URL,
2756
3075
  ELEVENLABS_CATALOG,
2757
3076
  ELEVENLABS_MODELS,
2758
3077
  ELEVENLABS_OUTPUT_FORMATS,
package/dist/types.d.ts CHANGED
@@ -12,8 +12,20 @@ export interface ReferenceVideoInfo {
12
12
  height?: number;
13
13
  }
14
14
  export interface BrotuAIOptions {
15
- /** Provider keys the caller owns. Keys are provider ids used by the catalog. */
16
- providers: Record<string, ProviderConfig>;
15
+ /**
16
+ * Your Brotu key (`brotu_sk_…`), from https://brotu.app.
17
+ * Vendor keys below generate on the vendor; everything else generates on Brotu.
18
+ */
19
+ apiKey: string;
20
+ /** Brotu API origin. Defaults to `https://api.brotu.app`. */
21
+ apiUrl?: string;
22
+ /**
23
+ * Workspace billed on Brotu generations. Resolved via
24
+ * `GET /studio/default-workspace` when omitted.
25
+ */
26
+ workspaceId?: string;
27
+ /** Vendor keys you already have. Those models generate on the vendor. */
28
+ providers?: Record<string, ProviderConfig>;
17
29
  /** Provider used by catalog entries that do not declare one. Defaults to "kie". */
18
30
  defaultProvider?: string;
19
31
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IAClC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC9B,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC1C,mFAAmF;IACnF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC1D;;;;OAIG;IACH,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B;;;OAGG;IACH,WAAW,CAAC,EAAE,CACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,KACZ,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iEAAiE;IACjE,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;CACjC;AAED,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CAChB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IAClC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC9B;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC3C,mFAAmF;IACnF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC1D;;;;OAIG;IACH,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B;;;OAGG;IACH,WAAW,CAAC,EAAE,CACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,KACZ,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iEAAiE;IACjE,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;CACjC;AAED,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CAChB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brotu/ai",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "exports": {
@@ -66,11 +66,11 @@
66
66
  "module": "./dist/index.js",
67
67
  "repository": {
68
68
  "type": "git",
69
- "url": "git+https://github.com/Zorbi-Tech/brotu-sdk.git",
69
+ "url": "git+https://github.com/Zorbi-Tech/brotu.git",
70
70
  "directory": "sdks/node"
71
71
  },
72
- "homepage": "https://github.com/Zorbi-Tech/brotu-sdk",
72
+ "homepage": "https://github.com/Zorbi-Tech/brotu",
73
73
  "bugs": {
74
- "url": "https://github.com/Zorbi-Tech/brotu-sdk/issues"
74
+ "url": "https://github.com/Zorbi-Tech/brotu/issues"
75
75
  }
76
76
  }