@blockrun/llm 2.0.0 → 2.1.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
@@ -781,6 +781,28 @@ var LLMClient = class _LLMClient {
781
781
  } catch {
782
782
  }
783
783
  }
784
+ /**
785
+ * Parse the chat response JSON and attach `fallback` metadata when the
786
+ * gateway signalled a transparent free-fallback substitution. The
787
+ * gateway sets X-Fallback-Used / X-Fallback-Model / X-Settlement-Skipped
788
+ * on the response when it served a paid request from a free model
789
+ * (route.ts createPaymentResponseHeader path). Without surfacing these
790
+ * to the caller, the user gets a different model than requested with
791
+ * no visibility — silent quality drop and no clue why the on-chain
792
+ * balance didn't change.
793
+ */
794
+ async parseChatResponse(response) {
795
+ const body = await response.json();
796
+ const used = response.headers.get("X-Fallback-Used") === "true";
797
+ if (used) {
798
+ body.fallback = {
799
+ used: true,
800
+ model: response.headers.get("X-Fallback-Model") || void 0,
801
+ settlementSkipped: response.headers.get("X-Settlement-Skipped") === "free-fallback"
802
+ };
803
+ }
804
+ return body;
805
+ }
784
806
  /**
785
807
  * Make a request with automatic x402 payment handling.
786
808
  */
@@ -809,7 +831,7 @@ var LLMClient = class _LLMClient {
809
831
  }
810
832
  throw new APIError(`API error: ${retryResp.status}`, retryResp.status, sanitizeErrorResponse(errorBody));
811
833
  }
812
- return retryResp.json();
834
+ return this.parseChatResponse(retryResp);
813
835
  }
814
836
  }
815
837
  if (response.status === 402) {
@@ -828,7 +850,7 @@ var LLMClient = class _LLMClient {
828
850
  sanitizeErrorResponse(errorBody)
829
851
  );
830
852
  }
831
- return response.json();
853
+ return this.parseChatResponse(response);
832
854
  }
833
855
  /**
834
856
  * Handle 402 response: parse requirements, sign payment, retry.
@@ -903,7 +925,7 @@ var LLMClient = class _LLMClient {
903
925
  this.sessionCalls += 1;
904
926
  this.sessionTotalUsd += costUsd2;
905
927
  this.recordCost(url, costUsd2, { body, network: details.network });
906
- return retryResp2.json();
928
+ return this.parseChatResponse(retryResp2);
907
929
  }
908
930
  }
909
931
  if (retryResponse.status === 402) {
@@ -926,7 +948,7 @@ var LLMClient = class _LLMClient {
926
948
  this.sessionCalls += 1;
927
949
  this.sessionTotalUsd += costUsd;
928
950
  this.recordCost(url, costUsd, { body, network: details.network });
929
- return retryResponse.json();
951
+ return this.parseChatResponse(retryResponse);
930
952
  }
931
953
  /**
932
954
  * Sign a payment header and return the PAYMENT-SIGNATURE value.
package/dist/index.d.cts CHANGED
@@ -58,6 +58,25 @@ interface ChatResponse {
58
58
  choices: ChatChoice[];
59
59
  usage?: ChatUsage;
60
60
  citations?: string[];
61
+ /**
62
+ * Populated when the gateway transparently substituted a different
63
+ * model for the one the caller asked for — typically because the
64
+ * requested model errored and the gateway routed to a free fallback
65
+ * to fulfil the request. When `used` is true:
66
+ * - `model` is the model that actually answered (vs `ChatResponse.model`
67
+ * which historically reflected the requested model id).
68
+ * - `settlementSkipped` is `true` when the gateway also skipped the
69
+ * on-chain settle — i.e. the user was not charged for this call
70
+ * because a free fallback served it.
71
+ * Surfaced from the gateway's `X-Fallback-Used / X-Fallback-Model /
72
+ * X-Settlement-Skipped` response headers. Absent when the headers
73
+ * aren't present (most calls).
74
+ */
75
+ fallback?: {
76
+ used: true;
77
+ model?: string;
78
+ settlementSkipped?: boolean;
79
+ };
61
80
  }
62
81
  interface Model {
63
82
  id: string;
@@ -811,6 +830,17 @@ declare class LLMClient {
811
830
  * cost_log.jsonl is a single source of truth regardless of caller.
812
831
  */
813
832
  private recordCost;
833
+ /**
834
+ * Parse the chat response JSON and attach `fallback` metadata when the
835
+ * gateway signalled a transparent free-fallback substitution. The
836
+ * gateway sets X-Fallback-Used / X-Fallback-Model / X-Settlement-Skipped
837
+ * on the response when it served a paid request from a free model
838
+ * (route.ts createPaymentResponseHeader path). Without surfacing these
839
+ * to the caller, the user gets a different model than requested with
840
+ * no visibility — silent quality drop and no clue why the on-chain
841
+ * balance didn't change.
842
+ */
843
+ private parseChatResponse;
814
844
  /**
815
845
  * Make a request with automatic x402 payment handling.
816
846
  */
package/dist/index.d.ts CHANGED
@@ -58,6 +58,25 @@ interface ChatResponse {
58
58
  choices: ChatChoice[];
59
59
  usage?: ChatUsage;
60
60
  citations?: string[];
61
+ /**
62
+ * Populated when the gateway transparently substituted a different
63
+ * model for the one the caller asked for — typically because the
64
+ * requested model errored and the gateway routed to a free fallback
65
+ * to fulfil the request. When `used` is true:
66
+ * - `model` is the model that actually answered (vs `ChatResponse.model`
67
+ * which historically reflected the requested model id).
68
+ * - `settlementSkipped` is `true` when the gateway also skipped the
69
+ * on-chain settle — i.e. the user was not charged for this call
70
+ * because a free fallback served it.
71
+ * Surfaced from the gateway's `X-Fallback-Used / X-Fallback-Model /
72
+ * X-Settlement-Skipped` response headers. Absent when the headers
73
+ * aren't present (most calls).
74
+ */
75
+ fallback?: {
76
+ used: true;
77
+ model?: string;
78
+ settlementSkipped?: boolean;
79
+ };
61
80
  }
62
81
  interface Model {
63
82
  id: string;
@@ -811,6 +830,17 @@ declare class LLMClient {
811
830
  * cost_log.jsonl is a single source of truth regardless of caller.
812
831
  */
813
832
  private recordCost;
833
+ /**
834
+ * Parse the chat response JSON and attach `fallback` metadata when the
835
+ * gateway signalled a transparent free-fallback substitution. The
836
+ * gateway sets X-Fallback-Used / X-Fallback-Model / X-Settlement-Skipped
837
+ * on the response when it served a paid request from a free model
838
+ * (route.ts createPaymentResponseHeader path). Without surfacing these
839
+ * to the caller, the user gets a different model than requested with
840
+ * no visibility — silent quality drop and no clue why the on-chain
841
+ * balance didn't change.
842
+ */
843
+ private parseChatResponse;
814
844
  /**
815
845
  * Make a request with automatic x402 payment handling.
816
846
  */
package/dist/index.js CHANGED
@@ -686,6 +686,28 @@ var LLMClient = class _LLMClient {
686
686
  } catch {
687
687
  }
688
688
  }
689
+ /**
690
+ * Parse the chat response JSON and attach `fallback` metadata when the
691
+ * gateway signalled a transparent free-fallback substitution. The
692
+ * gateway sets X-Fallback-Used / X-Fallback-Model / X-Settlement-Skipped
693
+ * on the response when it served a paid request from a free model
694
+ * (route.ts createPaymentResponseHeader path). Without surfacing these
695
+ * to the caller, the user gets a different model than requested with
696
+ * no visibility — silent quality drop and no clue why the on-chain
697
+ * balance didn't change.
698
+ */
699
+ async parseChatResponse(response) {
700
+ const body = await response.json();
701
+ const used = response.headers.get("X-Fallback-Used") === "true";
702
+ if (used) {
703
+ body.fallback = {
704
+ used: true,
705
+ model: response.headers.get("X-Fallback-Model") || void 0,
706
+ settlementSkipped: response.headers.get("X-Settlement-Skipped") === "free-fallback"
707
+ };
708
+ }
709
+ return body;
710
+ }
689
711
  /**
690
712
  * Make a request with automatic x402 payment handling.
691
713
  */
@@ -714,7 +736,7 @@ var LLMClient = class _LLMClient {
714
736
  }
715
737
  throw new APIError(`API error: ${retryResp.status}`, retryResp.status, sanitizeErrorResponse(errorBody));
716
738
  }
717
- return retryResp.json();
739
+ return this.parseChatResponse(retryResp);
718
740
  }
719
741
  }
720
742
  if (response.status === 402) {
@@ -733,7 +755,7 @@ var LLMClient = class _LLMClient {
733
755
  sanitizeErrorResponse(errorBody)
734
756
  );
735
757
  }
736
- return response.json();
758
+ return this.parseChatResponse(response);
737
759
  }
738
760
  /**
739
761
  * Handle 402 response: parse requirements, sign payment, retry.
@@ -808,7 +830,7 @@ var LLMClient = class _LLMClient {
808
830
  this.sessionCalls += 1;
809
831
  this.sessionTotalUsd += costUsd2;
810
832
  this.recordCost(url, costUsd2, { body, network: details.network });
811
- return retryResp2.json();
833
+ return this.parseChatResponse(retryResp2);
812
834
  }
813
835
  }
814
836
  if (retryResponse.status === 402) {
@@ -831,7 +853,7 @@ var LLMClient = class _LLMClient {
831
853
  this.sessionCalls += 1;
832
854
  this.sessionTotalUsd += costUsd;
833
855
  this.recordCost(url, costUsd, { body, network: details.network });
834
- return retryResponse.json();
856
+ return this.parseChatResponse(retryResponse);
835
857
  }
836
858
  /**
837
859
  * Sign a payment header and return the PAYMENT-SIGNATURE value.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/llm",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "type": "module",
5
5
  "description": "BlockRun SDK - Pay-per-request AI (LLM, Image, Video, Music) via x402 on Base and Solana",
6
6
  "main": "dist/index.cjs",