@prestyj/ai 4.12.1 → 4.14.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 CHANGED
@@ -112,6 +112,7 @@ var PROVIDER_DISPLAY = {
112
112
  moonshot: "Moonshot",
113
113
  deepseek: "DeepSeek",
114
114
  openrouter: "OpenRouter",
115
+ sakana: "Sakana",
115
116
  xiaomi: "Xiaomi (MiMo)",
116
117
  minimax: "MiniMax"
117
118
  };
@@ -336,7 +337,7 @@ var EventStream = class {
336
337
  }
337
338
  }
338
339
  };
339
- var StreamResult = class {
340
+ var StreamResult = class _StreamResult {
340
341
  response;
341
342
  buffer = [];
342
343
  done = false;
@@ -344,6 +345,18 @@ var StreamResult = class {
344
345
  resolveResponse;
345
346
  rejectResponse;
346
347
  resolveWait = null;
348
+ /**
349
+ * High-water mark: when the buffer exceeds this many unconsumed events,
350
+ * the pump pauses until the consumer drains below the low-water mark.
351
+ * Prevents unbounded memory growth when a consumer is slow.
352
+ * Only active when someone IS iterating — if nobody iterates (the `then()`
353
+ * path), backpressure is skipped so the pump can complete and resolve.
354
+ */
355
+ static HIGH_WATER = 5e3;
356
+ static LOW_WATER = 1e3;
357
+ iterating = false;
358
+ paused = false;
359
+ resolveDrain = null;
347
360
  constructor(generator, signal) {
348
361
  this.response = new Promise((resolve, reject) => {
349
362
  this.resolveResponse = resolve;
@@ -358,6 +371,13 @@ var StreamResult = class {
358
371
  this.buffer.push(next.value);
359
372
  this.resolveWait?.();
360
373
  this.resolveWait = null;
374
+ if (this.iterating && this.buffer.length > _StreamResult.HIGH_WATER) {
375
+ this.paused = true;
376
+ await new Promise((r) => {
377
+ this.resolveDrain = r;
378
+ });
379
+ this.paused = false;
380
+ }
361
381
  next = await this._nextWithAbort(generator, signal);
362
382
  }
363
383
  this.done = true;
@@ -396,11 +416,20 @@ var StreamResult = class {
396
416
  }
397
417
  }
398
418
  async *[Symbol.asyncIterator]() {
419
+ this.iterating = true;
399
420
  let index = 0;
400
421
  while (true) {
401
422
  while (index < this.buffer.length) {
402
423
  yield this.buffer[index++];
403
424
  }
425
+ if (this.paused && index > _StreamResult.LOW_WATER) {
426
+ this.resolveDrain?.();
427
+ this.resolveDrain = null;
428
+ }
429
+ if (index > 0 && !this.paused) {
430
+ this.buffer.splice(0, index);
431
+ index = 0;
432
+ }
404
433
  if (this.error) throw this.error;
405
434
  if (this.done) return;
406
435
  await new Promise((r) => {
@@ -413,6 +442,11 @@ var StreamResult = class {
413
442
  }
414
443
  }
415
444
  then(onfulfilled, onrejected) {
445
+ if (this.paused) {
446
+ this.paused = false;
447
+ this.resolveDrain?.();
448
+ this.resolveDrain = null;
449
+ }
416
450
  return this.response.then(onfulfilled, onrejected);
417
451
  }
418
452
  };
@@ -987,8 +1021,12 @@ function toOpenAIToolChoice(choice) {
987
1021
  if (choice === "required") return "required";
988
1022
  return { type: "function", function: { name: choice.name } };
989
1023
  }
990
- function toOpenAIReasoningEffort(level, _model) {
991
- return level === "max" ? "xhigh" : level;
1024
+ function toOpenAIReasoningEffort(level, model) {
1025
+ const effort = level === "max" ? "xhigh" : level;
1026
+ if (model.startsWith("fugu") && (effort === "low" || effort === "medium")) {
1027
+ return "high";
1028
+ }
1029
+ return effort;
992
1030
  }
993
1031
  function normalizeAnthropicStopReason(reason) {
994
1032
  switch (reason) {
@@ -3151,6 +3189,16 @@ providerRegistry.register("openrouter", {
3151
3189
  baseUrl: options.baseUrl ?? "https://openrouter.ai/api/v1"
3152
3190
  })
3153
3191
  });
3192
+ providerRegistry.register("sakana", {
3193
+ // Sakana Fugu is a multi-agent system exposed as a standard LLM through the
3194
+ // OpenAI-compatible Sakana API. We ride the Chat Completions transport (the
3195
+ // Responses API is also offered). Fugu models only accept "high"/"xhigh"
3196
+ // reasoning effort — clamped centrally in toOpenAIReasoningEffort.
3197
+ stream: (options) => streamOpenAI({
3198
+ ...options,
3199
+ baseUrl: options.baseUrl ?? "https://api.sakana.ai/v1"
3200
+ })
3201
+ });
3154
3202
  providerRegistry.register("minimax", {
3155
3203
  stream: (options) => streamAnthropic({
3156
3204
  ...options,