@jaypie/llm 1.2.28 → 1.2.29

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.
@@ -1,11 +1,14 @@
1
+ import { ClassifiedError } from "../types.js";
1
2
  import { OpenAiAdapter } from "./OpenAiAdapter.js";
2
3
  /**
3
4
  * XaiAdapter extends OpenAiAdapter since xAI (Grok) uses an OpenAI-compatible API.
4
- * Only the name and default model are overridden; all request building, response parsing,
5
- * error classification, tool handling, and streaming are inherited.
5
+ * Name, default model, and transient-ingest-error detection are overridden;
6
+ * all request building, response parsing, tool handling, and streaming are
7
+ * inherited.
6
8
  */
7
9
  export declare class XaiAdapter extends OpenAiAdapter {
8
10
  readonly name: "xai";
9
11
  readonly defaultModel: "grok-4.20-0309-reasoning";
12
+ classifyError(error: unknown): ClassifiedError;
10
13
  }
11
14
  export declare const xaiAdapter: XaiAdapter;
package/dist/esm/index.js CHANGED
@@ -3338,10 +3338,29 @@ class OpenRouterAdapter extends BaseProviderAdapter {
3338
3338
  // Export singleton instance
3339
3339
  const openRouterAdapter = new OpenRouterAdapter();
3340
3340
 
3341
+ /**
3342
+ * Error-message substrings that indicate a transient xAI media-ingest flake.
3343
+ * The xAI ingest service enters a bad state after ~12 consecutive file-bearing
3344
+ * calls and rejects subsequent requests with HTTP 400. The condition is
3345
+ * self-clearing, so these errors should be retried with backoff rather than
3346
+ * surfaced as unrecoverable.
3347
+ *
3348
+ * See: github.com/finlaysonstudio/jaypie issue #301
3349
+ */
3350
+ const TRANSIENT_INGEST_MESSAGE_PATTERNS = [
3351
+ "failed to ingest inline file bytes",
3352
+ ];
3353
+ function isTransientIngestError(error) {
3354
+ if (!(error instanceof BadRequestError))
3355
+ return false;
3356
+ const message = (error.message ?? "").toLowerCase();
3357
+ return TRANSIENT_INGEST_MESSAGE_PATTERNS.some((pattern) => message.includes(pattern));
3358
+ }
3341
3359
  /**
3342
3360
  * XaiAdapter extends OpenAiAdapter since xAI (Grok) uses an OpenAI-compatible API.
3343
- * Only the name and default model are overridden; all request building, response parsing,
3344
- * error classification, tool handling, and streaming are inherited.
3361
+ * Name, default model, and transient-ingest-error detection are overridden;
3362
+ * all request building, response parsing, tool handling, and streaming are
3363
+ * inherited.
3345
3364
  */
3346
3365
  class XaiAdapter extends OpenAiAdapter {
3347
3366
  constructor() {
@@ -3351,6 +3370,16 @@ class XaiAdapter extends OpenAiAdapter {
3351
3370
  // @ts-expect-error Narrowing override: xAI default model differs from parent's literal
3352
3371
  this.defaultModel = PROVIDER.XAI.MODEL.DEFAULT;
3353
3372
  }
3373
+ classifyError(error) {
3374
+ if (isTransientIngestError(error)) {
3375
+ return {
3376
+ error,
3377
+ category: ErrorCategory.Retryable,
3378
+ shouldRetry: true,
3379
+ };
3380
+ }
3381
+ return super.classifyError(error);
3382
+ }
3354
3383
  }
3355
3384
  // Export singleton instance
3356
3385
  const xaiAdapter = new XaiAdapter();