@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.d.cts CHANGED
@@ -2,7 +2,7 @@ import { z } from 'zod';
2
2
  import Anthropic from '@anthropic-ai/sdk';
3
3
  import OpenAI from 'openai';
4
4
 
5
- type Provider = "anthropic" | "xiaomi" | "openai" | "gemini" | "glm" | "moonshot" | "minimax" | "deepseek" | "openrouter" | "palsu";
5
+ type Provider = "anthropic" | "xiaomi" | "openai" | "gemini" | "glm" | "moonshot" | "minimax" | "deepseek" | "openrouter" | "sakana" | "palsu";
6
6
  type ThinkingLevel = "low" | "medium" | "high" | "xhigh" | "max";
7
7
  type CacheRetention = "none" | "short" | "long";
8
8
  interface TextContent {
@@ -255,6 +255,18 @@ declare class StreamResult implements AsyncIterable<StreamEvent> {
255
255
  private resolveResponse;
256
256
  private rejectResponse;
257
257
  private resolveWait;
258
+ /**
259
+ * High-water mark: when the buffer exceeds this many unconsumed events,
260
+ * the pump pauses until the consumer drains below the low-water mark.
261
+ * Prevents unbounded memory growth when a consumer is slow.
262
+ * Only active when someone IS iterating — if nobody iterates (the `then()`
263
+ * path), backpressure is skipped so the pump can complete and resolve.
264
+ */
265
+ private static readonly HIGH_WATER;
266
+ private static readonly LOW_WATER;
267
+ private iterating;
268
+ private paused;
269
+ private resolveDrain;
258
270
  constructor(generator: AsyncGenerator<StreamEvent, StreamResponse>, signal?: AbortSignal);
259
271
  private pump;
260
272
  private _nextWithAbort;
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import { z } from 'zod';
2
2
  import Anthropic from '@anthropic-ai/sdk';
3
3
  import OpenAI from 'openai';
4
4
 
5
- type Provider = "anthropic" | "xiaomi" | "openai" | "gemini" | "glm" | "moonshot" | "minimax" | "deepseek" | "openrouter" | "palsu";
5
+ type Provider = "anthropic" | "xiaomi" | "openai" | "gemini" | "glm" | "moonshot" | "minimax" | "deepseek" | "openrouter" | "sakana" | "palsu";
6
6
  type ThinkingLevel = "low" | "medium" | "high" | "xhigh" | "max";
7
7
  type CacheRetention = "none" | "short" | "long";
8
8
  interface TextContent {
@@ -255,6 +255,18 @@ declare class StreamResult implements AsyncIterable<StreamEvent> {
255
255
  private resolveResponse;
256
256
  private rejectResponse;
257
257
  private resolveWait;
258
+ /**
259
+ * High-water mark: when the buffer exceeds this many unconsumed events,
260
+ * the pump pauses until the consumer drains below the low-water mark.
261
+ * Prevents unbounded memory growth when a consumer is slow.
262
+ * Only active when someone IS iterating — if nobody iterates (the `then()`
263
+ * path), backpressure is skipped so the pump can complete and resolve.
264
+ */
265
+ private static readonly HIGH_WATER;
266
+ private static readonly LOW_WATER;
267
+ private iterating;
268
+ private paused;
269
+ private resolveDrain;
258
270
  constructor(generator: AsyncGenerator<StreamEvent, StreamResponse>, signal?: AbortSignal);
259
271
  private pump;
260
272
  private _nextWithAbort;
package/dist/index.js CHANGED
@@ -57,6 +57,7 @@ var PROVIDER_DISPLAY = {
57
57
  moonshot: "Moonshot",
58
58
  deepseek: "DeepSeek",
59
59
  openrouter: "OpenRouter",
60
+ sakana: "Sakana",
60
61
  xiaomi: "Xiaomi (MiMo)",
61
62
  minimax: "MiniMax"
62
63
  };
@@ -281,7 +282,7 @@ var EventStream = class {
281
282
  }
282
283
  }
283
284
  };
284
- var StreamResult = class {
285
+ var StreamResult = class _StreamResult {
285
286
  response;
286
287
  buffer = [];
287
288
  done = false;
@@ -289,6 +290,18 @@ var StreamResult = class {
289
290
  resolveResponse;
290
291
  rejectResponse;
291
292
  resolveWait = null;
293
+ /**
294
+ * High-water mark: when the buffer exceeds this many unconsumed events,
295
+ * the pump pauses until the consumer drains below the low-water mark.
296
+ * Prevents unbounded memory growth when a consumer is slow.
297
+ * Only active when someone IS iterating — if nobody iterates (the `then()`
298
+ * path), backpressure is skipped so the pump can complete and resolve.
299
+ */
300
+ static HIGH_WATER = 5e3;
301
+ static LOW_WATER = 1e3;
302
+ iterating = false;
303
+ paused = false;
304
+ resolveDrain = null;
292
305
  constructor(generator, signal) {
293
306
  this.response = new Promise((resolve, reject) => {
294
307
  this.resolveResponse = resolve;
@@ -303,6 +316,13 @@ var StreamResult = class {
303
316
  this.buffer.push(next.value);
304
317
  this.resolveWait?.();
305
318
  this.resolveWait = null;
319
+ if (this.iterating && this.buffer.length > _StreamResult.HIGH_WATER) {
320
+ this.paused = true;
321
+ await new Promise((r) => {
322
+ this.resolveDrain = r;
323
+ });
324
+ this.paused = false;
325
+ }
306
326
  next = await this._nextWithAbort(generator, signal);
307
327
  }
308
328
  this.done = true;
@@ -341,11 +361,20 @@ var StreamResult = class {
341
361
  }
342
362
  }
343
363
  async *[Symbol.asyncIterator]() {
364
+ this.iterating = true;
344
365
  let index = 0;
345
366
  while (true) {
346
367
  while (index < this.buffer.length) {
347
368
  yield this.buffer[index++];
348
369
  }
370
+ if (this.paused && index > _StreamResult.LOW_WATER) {
371
+ this.resolveDrain?.();
372
+ this.resolveDrain = null;
373
+ }
374
+ if (index > 0 && !this.paused) {
375
+ this.buffer.splice(0, index);
376
+ index = 0;
377
+ }
349
378
  if (this.error) throw this.error;
350
379
  if (this.done) return;
351
380
  await new Promise((r) => {
@@ -358,6 +387,11 @@ var StreamResult = class {
358
387
  }
359
388
  }
360
389
  then(onfulfilled, onrejected) {
390
+ if (this.paused) {
391
+ this.paused = false;
392
+ this.resolveDrain?.();
393
+ this.resolveDrain = null;
394
+ }
361
395
  return this.response.then(onfulfilled, onrejected);
362
396
  }
363
397
  };
@@ -932,8 +966,12 @@ function toOpenAIToolChoice(choice) {
932
966
  if (choice === "required") return "required";
933
967
  return { type: "function", function: { name: choice.name } };
934
968
  }
935
- function toOpenAIReasoningEffort(level, _model) {
936
- return level === "max" ? "xhigh" : level;
969
+ function toOpenAIReasoningEffort(level, model) {
970
+ const effort = level === "max" ? "xhigh" : level;
971
+ if (model.startsWith("fugu") && (effort === "low" || effort === "medium")) {
972
+ return "high";
973
+ }
974
+ return effort;
937
975
  }
938
976
  function normalizeAnthropicStopReason(reason) {
939
977
  switch (reason) {
@@ -3096,6 +3134,16 @@ providerRegistry.register("openrouter", {
3096
3134
  baseUrl: options.baseUrl ?? "https://openrouter.ai/api/v1"
3097
3135
  })
3098
3136
  });
3137
+ providerRegistry.register("sakana", {
3138
+ // Sakana Fugu is a multi-agent system exposed as a standard LLM through the
3139
+ // OpenAI-compatible Sakana API. We ride the Chat Completions transport (the
3140
+ // Responses API is also offered). Fugu models only accept "high"/"xhigh"
3141
+ // reasoning effort — clamped centrally in toOpenAIReasoningEffort.
3142
+ stream: (options) => streamOpenAI({
3143
+ ...options,
3144
+ baseUrl: options.baseUrl ?? "https://api.sakana.ai/v1"
3145
+ })
3146
+ });
3099
3147
  providerRegistry.register("minimax", {
3100
3148
  stream: (options) => streamAnthropic({
3101
3149
  ...options,