@antseed/cli 0.1.156 → 0.1.158

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.
Files changed (242) hide show
  1. package/README.md +135 -6
  2. package/dist/cli/commands/ants/addresses.d.ts +3 -0
  3. package/dist/cli/commands/ants/addresses.d.ts.map +1 -0
  4. package/dist/cli/commands/ants/addresses.js +20 -0
  5. package/dist/cli/commands/ants/addresses.js.map +1 -0
  6. package/dist/cli/commands/ants/addresses.test.d.ts +2 -0
  7. package/dist/cli/commands/ants/addresses.test.d.ts.map +1 -0
  8. package/dist/cli/commands/ants/addresses.test.js +12 -0
  9. package/dist/cli/commands/ants/addresses.test.js.map +1 -0
  10. package/dist/cli/commands/ants/arguments.test.d.ts +2 -0
  11. package/dist/cli/commands/ants/arguments.test.d.ts.map +1 -0
  12. package/dist/cli/commands/ants/arguments.test.js +51 -0
  13. package/dist/cli/commands/ants/arguments.test.js.map +1 -0
  14. package/dist/cli/commands/ants/dashboard.d.ts +4 -0
  15. package/dist/cli/commands/ants/dashboard.d.ts.map +1 -0
  16. package/dist/cli/commands/ants/dashboard.js +45 -0
  17. package/dist/cli/commands/ants/dashboard.js.map +1 -0
  18. package/dist/cli/commands/ants/dashboard.test.d.ts +2 -0
  19. package/dist/cli/commands/ants/dashboard.test.d.ts.map +1 -0
  20. package/dist/cli/commands/ants/dashboard.test.js +14 -0
  21. package/dist/cli/commands/ants/dashboard.test.js.map +1 -0
  22. package/dist/cli/commands/ants/emissions.d.ts +5 -0
  23. package/dist/cli/commands/ants/emissions.d.ts.map +1 -0
  24. package/dist/cli/commands/ants/emissions.js +44 -0
  25. package/dist/cli/commands/ants/emissions.js.map +1 -0
  26. package/dist/cli/commands/ants/emissions.test.d.ts +2 -0
  27. package/dist/cli/commands/ants/emissions.test.d.ts.map +1 -0
  28. package/dist/cli/commands/ants/emissions.test.js +17 -0
  29. package/dist/cli/commands/ants/emissions.test.js.map +1 -0
  30. package/dist/cli/commands/ants/extend.d.ts +3 -0
  31. package/dist/cli/commands/ants/extend.d.ts.map +1 -0
  32. package/dist/cli/commands/ants/extend.js +14 -0
  33. package/dist/cli/commands/ants/extend.js.map +1 -0
  34. package/dist/cli/commands/ants/extend.test.d.ts +2 -0
  35. package/dist/cli/commands/ants/extend.test.d.ts.map +1 -0
  36. package/dist/cli/commands/ants/extend.test.js +13 -0
  37. package/dist/cli/commands/ants/extend.test.js.map +1 -0
  38. package/dist/cli/commands/ants/index.d.ts +7 -0
  39. package/dist/cli/commands/ants/index.d.ts.map +1 -0
  40. package/dist/cli/commands/ants/index.js +46 -0
  41. package/dist/cli/commands/ants/index.js.map +1 -0
  42. package/dist/cli/commands/ants/index.test.d.ts +2 -0
  43. package/dist/cli/commands/ants/index.test.d.ts.map +1 -0
  44. package/dist/cli/commands/ants/index.test.js +24 -0
  45. package/dist/cli/commands/ants/index.test.js.map +1 -0
  46. package/dist/cli/commands/ants/max-lock.d.ts +3 -0
  47. package/dist/cli/commands/ants/max-lock.d.ts.map +1 -0
  48. package/dist/cli/commands/ants/max-lock.js +13 -0
  49. package/dist/cli/commands/ants/max-lock.js.map +1 -0
  50. package/dist/cli/commands/ants/max-lock.test.d.ts +2 -0
  51. package/dist/cli/commands/ants/max-lock.test.d.ts.map +1 -0
  52. package/dist/cli/commands/ants/max-lock.test.js +15 -0
  53. package/dist/cli/commands/ants/max-lock.test.js.map +1 -0
  54. package/dist/cli/commands/ants/merge.d.ts +3 -0
  55. package/dist/cli/commands/ants/merge.d.ts.map +1 -0
  56. package/dist/cli/commands/ants/merge.js +12 -0
  57. package/dist/cli/commands/ants/merge.js.map +1 -0
  58. package/dist/cli/commands/ants/merge.test.d.ts +2 -0
  59. package/dist/cli/commands/ants/merge.test.d.ts.map +1 -0
  60. package/dist/cli/commands/ants/merge.test.js +16 -0
  61. package/dist/cli/commands/ants/merge.test.js.map +1 -0
  62. package/dist/cli/commands/ants/move.d.ts +3 -0
  63. package/dist/cli/commands/ants/move.d.ts.map +1 -0
  64. package/dist/cli/commands/ants/move.js +14 -0
  65. package/dist/cli/commands/ants/move.js.map +1 -0
  66. package/dist/cli/commands/ants/move.test.d.ts +2 -0
  67. package/dist/cli/commands/ants/move.test.d.ts.map +1 -0
  68. package/dist/cli/commands/ants/move.test.js +16 -0
  69. package/dist/cli/commands/ants/move.test.js.map +1 -0
  70. package/dist/cli/commands/ants/pool.d.ts +3 -0
  71. package/dist/cli/commands/ants/pool.d.ts.map +1 -0
  72. package/dist/cli/commands/ants/pool.js +21 -0
  73. package/dist/cli/commands/ants/pool.js.map +1 -0
  74. package/dist/cli/commands/ants/pool.test.d.ts +2 -0
  75. package/dist/cli/commands/ants/pool.test.d.ts.map +1 -0
  76. package/dist/cli/commands/ants/pool.test.js +13 -0
  77. package/dist/cli/commands/ants/pool.test.js.map +1 -0
  78. package/dist/cli/commands/ants/pools.d.ts +6 -0
  79. package/dist/cli/commands/ants/pools.d.ts.map +1 -0
  80. package/dist/cli/commands/ants/pools.js +50 -0
  81. package/dist/cli/commands/ants/pools.js.map +1 -0
  82. package/dist/cli/commands/ants/pools.test.d.ts +2 -0
  83. package/dist/cli/commands/ants/pools.test.d.ts.map +1 -0
  84. package/dist/cli/commands/ants/pools.test.js +18 -0
  85. package/dist/cli/commands/ants/pools.test.js.map +1 -0
  86. package/dist/cli/commands/ants/positions.d.ts +6 -0
  87. package/dist/cli/commands/ants/positions.d.ts.map +1 -0
  88. package/dist/cli/commands/ants/positions.js +46 -0
  89. package/dist/cli/commands/ants/positions.js.map +1 -0
  90. package/dist/cli/commands/ants/positions.test.d.ts +2 -0
  91. package/dist/cli/commands/ants/positions.test.d.ts.map +1 -0
  92. package/dist/cli/commands/ants/positions.test.js +19 -0
  93. package/dist/cli/commands/ants/positions.test.js.map +1 -0
  94. package/dist/cli/commands/ants/rewards.d.ts +9 -0
  95. package/dist/cli/commands/ants/rewards.d.ts.map +1 -0
  96. package/dist/cli/commands/ants/rewards.js +93 -0
  97. package/dist/cli/commands/ants/rewards.js.map +1 -0
  98. package/dist/cli/commands/ants/rewards.test.d.ts +2 -0
  99. package/dist/cli/commands/ants/rewards.test.d.ts.map +1 -0
  100. package/dist/cli/commands/ants/rewards.test.js +46 -0
  101. package/dist/cli/commands/ants/rewards.test.js.map +1 -0
  102. package/dist/cli/commands/ants/seller.d.ts +3 -0
  103. package/dist/cli/commands/ants/seller.d.ts.map +1 -0
  104. package/dist/cli/commands/ants/seller.js +32 -0
  105. package/dist/cli/commands/ants/seller.js.map +1 -0
  106. package/dist/cli/commands/ants/seller.test.d.ts +2 -0
  107. package/dist/cli/commands/ants/seller.test.d.ts.map +1 -0
  108. package/dist/cli/commands/ants/seller.test.js +16 -0
  109. package/dist/cli/commands/ants/seller.test.js.map +1 -0
  110. package/dist/cli/commands/ants/shared.d.ts +26 -0
  111. package/dist/cli/commands/ants/shared.d.ts.map +1 -0
  112. package/dist/cli/commands/ants/shared.js +94 -0
  113. package/dist/cli/commands/ants/shared.js.map +1 -0
  114. package/dist/cli/commands/ants/shared.test.d.ts +2 -0
  115. package/dist/cli/commands/ants/shared.test.d.ts.map +1 -0
  116. package/dist/cli/commands/ants/shared.test.js +25 -0
  117. package/dist/cli/commands/ants/shared.test.js.map +1 -0
  118. package/dist/cli/commands/ants/split.d.ts +3 -0
  119. package/dist/cli/commands/ants/split.d.ts.map +1 -0
  120. package/dist/cli/commands/ants/split.js +12 -0
  121. package/dist/cli/commands/ants/split.js.map +1 -0
  122. package/dist/cli/commands/ants/split.test.d.ts +2 -0
  123. package/dist/cli/commands/ants/split.test.d.ts.map +1 -0
  124. package/dist/cli/commands/ants/split.test.js +13 -0
  125. package/dist/cli/commands/ants/split.test.js.map +1 -0
  126. package/dist/cli/commands/ants/stake.d.ts +3 -0
  127. package/dist/cli/commands/ants/stake.d.ts.map +1 -0
  128. package/dist/cli/commands/ants/stake.js +15 -0
  129. package/dist/cli/commands/ants/stake.js.map +1 -0
  130. package/dist/cli/commands/ants/stake.test.d.ts +2 -0
  131. package/dist/cli/commands/ants/stake.test.d.ts.map +1 -0
  132. package/dist/cli/commands/ants/stake.test.js +17 -0
  133. package/dist/cli/commands/ants/stake.test.js.map +1 -0
  134. package/dist/cli/commands/ants/status.d.ts +9 -0
  135. package/dist/cli/commands/ants/status.d.ts.map +1 -0
  136. package/dist/cli/commands/ants/status.js +43 -0
  137. package/dist/cli/commands/ants/status.js.map +1 -0
  138. package/dist/cli/commands/ants/status.test.d.ts +2 -0
  139. package/dist/cli/commands/ants/status.test.d.ts.map +1 -0
  140. package/dist/cli/commands/ants/status.test.js +23 -0
  141. package/dist/cli/commands/ants/status.test.js.map +1 -0
  142. package/dist/cli/commands/ants/usage.d.ts +4 -0
  143. package/dist/cli/commands/ants/usage.d.ts.map +1 -0
  144. package/dist/cli/commands/ants/usage.js +31 -0
  145. package/dist/cli/commands/ants/usage.js.map +1 -0
  146. package/dist/cli/commands/ants/usage.test.d.ts +2 -0
  147. package/dist/cli/commands/ants/usage.test.d.ts.map +1 -0
  148. package/dist/cli/commands/ants/usage.test.js +15 -0
  149. package/dist/cli/commands/ants/usage.test.js.map +1 -0
  150. package/dist/cli/commands/ants/verify.d.ts +3 -0
  151. package/dist/cli/commands/ants/verify.d.ts.map +1 -0
  152. package/dist/cli/commands/ants/verify.js +51 -0
  153. package/dist/cli/commands/ants/verify.js.map +1 -0
  154. package/dist/cli/commands/ants/verify.test.d.ts +2 -0
  155. package/dist/cli/commands/ants/verify.test.d.ts.map +1 -0
  156. package/dist/cli/commands/ants/verify.test.js +51 -0
  157. package/dist/cli/commands/ants/verify.test.js.map +1 -0
  158. package/dist/cli/commands/ants/withdraw.d.ts +16 -0
  159. package/dist/cli/commands/ants/withdraw.d.ts.map +1 -0
  160. package/dist/cli/commands/ants/withdraw.js +48 -0
  161. package/dist/cli/commands/ants/withdraw.js.map +1 -0
  162. package/dist/cli/commands/ants/withdraw.test.d.ts +2 -0
  163. package/dist/cli/commands/ants/withdraw.test.d.ts.map +1 -0
  164. package/dist/cli/commands/ants/withdraw.test.js +30 -0
  165. package/dist/cli/commands/ants/withdraw.test.js.map +1 -0
  166. package/dist/cli/commands/emissions.d.ts +7 -0
  167. package/dist/cli/commands/emissions.d.ts.map +1 -1
  168. package/dist/cli/commands/emissions.js +105 -27
  169. package/dist/cli/commands/emissions.js.map +1 -1
  170. package/dist/cli/commands/emissions.test.js +7 -1
  171. package/dist/cli/commands/emissions.test.js.map +1 -1
  172. package/dist/cli/commands/network/chain-config-helper.d.ts +18 -0
  173. package/dist/cli/commands/network/chain-config-helper.d.ts.map +1 -1
  174. package/dist/cli/commands/network/chain-config-helper.js.map +1 -1
  175. package/dist/cli/commands/parse-positive-integer.d.ts +2 -0
  176. package/dist/cli/commands/parse-positive-integer.d.ts.map +1 -0
  177. package/dist/cli/commands/parse-positive-integer.js +9 -0
  178. package/dist/cli/commands/parse-positive-integer.js.map +1 -0
  179. package/dist/cli/commands/reward-actions.d.ts +11 -0
  180. package/dist/cli/commands/reward-actions.d.ts.map +1 -0
  181. package/dist/cli/commands/reward-actions.js +22 -0
  182. package/dist/cli/commands/reward-actions.js.map +1 -0
  183. package/dist/cli/commands/seller/contract-clients.test.d.ts +2 -0
  184. package/dist/cli/commands/seller/contract-clients.test.d.ts.map +1 -0
  185. package/dist/cli/commands/seller/contract-clients.test.js +45 -0
  186. package/dist/cli/commands/seller/contract-clients.test.js.map +1 -0
  187. package/dist/cli/commands/seller/index.d.ts.map +1 -1
  188. package/dist/cli/commands/seller/index.js +4 -2
  189. package/dist/cli/commands/seller/index.js.map +1 -1
  190. package/dist/cli/commands/seller/pool.d.ts +15 -0
  191. package/dist/cli/commands/seller/pool.d.ts.map +1 -0
  192. package/dist/cli/commands/seller/pool.js +201 -0
  193. package/dist/cli/commands/seller/pool.js.map +1 -0
  194. package/dist/cli/commands/seller/pool.test.d.ts +2 -0
  195. package/dist/cli/commands/seller/pool.test.d.ts.map +1 -0
  196. package/dist/cli/commands/seller/pool.test.js +16 -0
  197. package/dist/cli/commands/seller/pool.test.js.map +1 -0
  198. package/dist/cli/commands/seller/register.d.ts.map +1 -1
  199. package/dist/cli/commands/seller/register.js +38 -8
  200. package/dist/cli/commands/seller/register.js.map +1 -1
  201. package/dist/cli/commands/seller/rewards.d.ts +13 -0
  202. package/dist/cli/commands/seller/rewards.d.ts.map +1 -0
  203. package/dist/cli/commands/seller/rewards.js +115 -0
  204. package/dist/cli/commands/seller/rewards.js.map +1 -0
  205. package/dist/cli/commands/seller/rewards.test.d.ts +2 -0
  206. package/dist/cli/commands/seller/rewards.test.d.ts.map +1 -0
  207. package/dist/cli/commands/seller/rewards.test.js +21 -0
  208. package/dist/cli/commands/seller/rewards.test.js.map +1 -0
  209. package/dist/cli/commands/seller/setup.d.ts.map +1 -1
  210. package/dist/cli/commands/seller/setup.js +2 -1
  211. package/dist/cli/commands/seller/setup.js.map +1 -1
  212. package/dist/cli/commands/seller/stake.d.ts.map +1 -1
  213. package/dist/cli/commands/seller/stake.js +104 -65
  214. package/dist/cli/commands/seller/stake.js.map +1 -1
  215. package/dist/cli/commands/seller/stake.test.d.ts +2 -0
  216. package/dist/cli/commands/seller/stake.test.d.ts.map +1 -0
  217. package/dist/cli/commands/seller/stake.test.js +99 -0
  218. package/dist/cli/commands/seller/stake.test.js.map +1 -0
  219. package/dist/cli/commands/seller/start.d.ts.map +1 -1
  220. package/dist/cli/commands/seller/start.js +6 -0
  221. package/dist/cli/commands/seller/start.js.map +1 -1
  222. package/dist/cli/commands/seller/status.d.ts.map +1 -1
  223. package/dist/cli/commands/seller/status.js +44 -2
  224. package/dist/cli/commands/seller/status.js.map +1 -1
  225. package/dist/cli/index.js +2 -0
  226. package/dist/cli/index.js.map +1 -1
  227. package/dist/cli/payment-utils.d.ts +33 -2
  228. package/dist/cli/payment-utils.d.ts.map +1 -1
  229. package/dist/cli/payment-utils.js +101 -2
  230. package/dist/cli/payment-utils.js.map +1 -1
  231. package/dist/config/types.d.ts +20 -0
  232. package/dist/config/types.d.ts.map +1 -1
  233. package/dist/proxy/buyer-proxy.d.ts.map +1 -1
  234. package/dist/proxy/buyer-proxy.js +27 -8
  235. package/dist/proxy/buyer-proxy.js.map +1 -1
  236. package/dist/proxy/buyer-proxy.test.js +126 -2
  237. package/dist/proxy/buyer-proxy.test.js.map +1 -1
  238. package/package.json +7 -6
  239. package/dist/cli/commands/seller/emissions.d.ts +0 -3
  240. package/dist/cli/commands/seller/emissions.d.ts.map +0 -1
  241. package/dist/cli/commands/seller/emissions.js +0 -5
  242. package/dist/cli/commands/seller/emissions.js.map +0 -1
@@ -5,7 +5,7 @@ import { tmpdir } from 'node:os';
5
5
  import { join } from 'node:path';
6
6
  import { Readable } from 'node:stream';
7
7
  import test from 'node:test';
8
- import { ANTSEED_BUYER_FAULT_ERROR_CODE, ANTSEED_FAULT_ATTRIBUTION_HEADER, CONNECTION_CAPABILITY_COOPERATIVE_CLOSE_V1, CONNECTION_CAPABILITY_RELAYS_SWEEPS_V1, buyerFault, computeOnChainReputationScore, } from '@antseed/node';
8
+ import { ANTSEED_BUYER_FAULT_ERROR_CODE, ANTSEED_FAULT_ATTRIBUTION_HEADER, CONNECTION_CAPABILITY_COOPERATIVE_CLOSE_V1, CONNECTION_CAPABILITY_RELAYS_SWEEPS_V1, adaptPeerFaultErrorResponse, buyerFault, computeOnChainReputationScore, } from '@antseed/node';
9
9
  import { DEFAULT_BUYER_PEER_REFRESH_INTERVAL_MS } from '../config/defaults.js';
10
10
  import { BuyerProxy, isModelNotFoundResponse, makeVerifierReach, mergeJsonStateFile, parsePeerPinnedService, parsePersistedPeers, rewritePeerPinnedServiceInBody, sanitizePeerBuyerFaultMarker, selectCandidatePeersForRouting, substituteRoutedModelAlias, sweepStaleStateTmpFiles, } from './buyer-proxy.js';
11
11
  import { extractRequestedService, overrideRoutedModelInBody, SYSTEM_ROUTED_MODEL_HEADER, } from './request-utils.js';
@@ -1294,6 +1294,37 @@ test('a buyer-authored 503 does not affect router metrics or peer health', async
1294
1294
  assert.equal(health?.failureStreak, 0);
1295
1295
  assert.equal(health?.cooldownUntil, 0);
1296
1296
  });
1297
+ test('a pinned seller failure explains the peer boundary and preserves the seller message', async () => {
1298
+ const peer = makePeer('a', ['openai']);
1299
+ const proxy = makeBuyerProxyWithPeers([peer], [peer], permissiveRouter());
1300
+ proxy._node.sendRequest = async (_peer, request) => ({
1301
+ requestId: request.requestId,
1302
+ statusCode: 503,
1303
+ headers: { 'content-type': 'application/json' },
1304
+ body: Buffer.from(JSON.stringify({
1305
+ error: {
1306
+ type: 'billing_configuration_error',
1307
+ message: 'No billing tier matches this request.',
1308
+ },
1309
+ })),
1310
+ });
1311
+ const res = await invokeProxy(proxy, makeProxyRequest({
1312
+ headers: { 'x-antseed-pin-peer': peer.peerId },
1313
+ }));
1314
+ const parsed = JSON.parse(res.body);
1315
+ assert.equal(res.statusCode, 503);
1316
+ assert.equal(res.headers[ANTSEED_FAULT_ATTRIBUTION_HEADER], 'peer');
1317
+ assert.equal(parsed.error.type, 'billing_configuration_error');
1318
+ assert.equal(parsed.error.antseed_fault, 'peer');
1319
+ assert.equal(parsed.error.antseed_pinned, true);
1320
+ assert.equal(parsed.error.peer_message, 'No billing tier matches this request.');
1321
+ assert.equal(parsed.error.peer_status, 503);
1322
+ assert.equal(parsed.error.message, [
1323
+ 'Oops, pinned peer could not complete the request.',
1324
+ 'AntSeed is a peer-to-peer network. Try another peer or use Auto routing.',
1325
+ 'Original Response: {"message":"No billing tier matches this request.","status":503}',
1326
+ ].join('\n'));
1327
+ });
1297
1328
  test('a seller cannot inject the reserved buyer-fault error code', async () => {
1298
1329
  const peer = makePeer('a', ['openai']);
1299
1330
  const proxy = makeBuyerProxyWithPeers([peer], [peer], permissiveRouter());
@@ -1334,7 +1365,10 @@ test('an untagged transport failure records a streak without evicting the peer',
1334
1365
  },
1335
1366
  }));
1336
1367
  assert.equal(res.statusCode, 502);
1337
- assert.match(res.body, /Request abc123 timed out/);
1368
+ const parsed = JSON.parse(res.body);
1369
+ assert.match(parsed.error.message, /Oops, pinned peer could not complete the request/);
1370
+ assert.equal(parsed.error.peer_message, 'Request abc123 timed out');
1371
+ assert.equal(res.headers[ANTSEED_FAULT_ATTRIBUTION_HEADER], 'peer');
1338
1372
  assert.equal(routerResults.length, 0);
1339
1373
  assert.equal(proxy._peerHealth.get(peer.peerId)?.lastReason, 'request-failed');
1340
1374
  // Cooldown never evicts discovery metadata — the peer stays routable.
@@ -1800,6 +1834,45 @@ test('accept-sse transformed responses requests stream adapted client events wit
1800
1834
  assert.match(res.body, /"text":"hi"/);
1801
1835
  assert.doesNotMatch(res.body, /event: response\.completed/);
1802
1836
  });
1837
+ test('transformed pre-stream seller errors preserve peer guidance', async () => {
1838
+ const peer = makePeer('a', ['openai-responses']);
1839
+ peer.providerServiceApiProtocols = {
1840
+ 'openai-responses': {
1841
+ services: {
1842
+ 'gpt-5.6-sol': ['openai-responses'],
1843
+ },
1844
+ },
1845
+ };
1846
+ const proxy = makeBuyerProxyWithPeers([peer], [peer]);
1847
+ proxy._node.sendRequestStream = async (_peer, request) => ({
1848
+ requestId: request.requestId,
1849
+ statusCode: 503,
1850
+ headers: { 'content-type': 'application/json' },
1851
+ body: Buffer.from(JSON.stringify({
1852
+ error: {
1853
+ type: 'server_error',
1854
+ message: 'The seller upstream is unavailable.',
1855
+ },
1856
+ })),
1857
+ });
1858
+ const res = await invokeProxy(proxy, makeProxyRequest({
1859
+ path: '/v1/messages',
1860
+ headers: {
1861
+ accept: 'text/event-stream',
1862
+ 'x-antseed-pin-peer': peer.peerId,
1863
+ },
1864
+ body: {
1865
+ model: 'gpt-5.6-sol',
1866
+ max_tokens: 128,
1867
+ messages: [{ role: 'user', content: 'hello' }],
1868
+ },
1869
+ }));
1870
+ assert.equal(res.statusCode, 503);
1871
+ assert.equal(res.headers[ANTSEED_FAULT_ATTRIBUTION_HEADER], 'peer');
1872
+ assert.match(res.headers['content-type'] ?? '', /text\/event-stream/);
1873
+ assert.match(res.body, /Oops, pinned peer could not complete the request/);
1874
+ assert.match(res.body, /Original Response:.*The seller upstream is unavailable\./);
1875
+ });
1803
1876
  test('model peer prefix pins the request peer and strips the routed model', async () => {
1804
1877
  const pinnedPeer = makePeer('a', ['openai']);
1805
1878
  let capturedRequestBody = null;
@@ -2782,6 +2855,57 @@ test('sanitizePeerBuyerFaultMarker scrubs the marker at any nesting depth', () =
2782
2855
  assert.equal(nested.code, 'upstream_error');
2783
2856
  assert.equal(nested.message, 'seller-controlled message');
2784
2857
  });
2858
+ test('adaptPeerFaultErrorResponse leaves actionable request errors unchanged', () => {
2859
+ const body = Buffer.from(JSON.stringify({
2860
+ error: { type: 'invalid_request_error', message: 'The prompt is too long.' },
2861
+ }));
2862
+ const response = adaptPeerFaultErrorResponse({
2863
+ requestId: 'req-actionable',
2864
+ statusCode: 400,
2865
+ headers: { 'content-type': 'application/json' },
2866
+ body,
2867
+ }, 'openai-chat-completions');
2868
+ assert.equal(Buffer.from(response.body).toString('utf8'), body.toString('utf8'));
2869
+ assert.equal(response.headers[ANTSEED_FAULT_ATTRIBUTION_HEADER], 'peer');
2870
+ });
2871
+ test('adaptPeerFaultErrorResponse upgrades a generic wrapper for a pinned route', () => {
2872
+ const raw = {
2873
+ requestId: 'req-pinned-upgrade',
2874
+ statusCode: 429,
2875
+ headers: { 'content-type': 'application/json' },
2876
+ body: Buffer.from(JSON.stringify({
2877
+ error: {
2878
+ type: 'rate_limit_error',
2879
+ message: 'Insufficient balance or no resource package. Please recharge.',
2880
+ },
2881
+ })),
2882
+ };
2883
+ const generic = adaptPeerFaultErrorResponse(raw, 'openai-chat-completions');
2884
+ const pinned = adaptPeerFaultErrorResponse(generic, 'openai-chat-completions', { pinned: true });
2885
+ const parsed = JSON.parse(Buffer.from(pinned.body).toString('utf8'));
2886
+ assert.equal(parsed.error.antseed_pinned, true);
2887
+ assert.equal(parsed.error.peer_message, 'Insufficient balance or no resource package. Please recharge.');
2888
+ assert.equal(parsed.error.peer_status, 429);
2889
+ assert.equal(parsed.error.message, [
2890
+ 'Oops, pinned peer could not complete the request.',
2891
+ 'AntSeed is a peer-to-peer network. Try another peer or use Auto routing.',
2892
+ 'Original Response: {"message":"Insufficient balance or no resource package. Please recharge.","status":429}',
2893
+ ].join('\n'));
2894
+ });
2895
+ test('adaptPeerFaultErrorResponse preserves payment-required control messages', () => {
2896
+ const body = Buffer.from(JSON.stringify({
2897
+ error: 'payment_required',
2898
+ minBudgetPerRequest: '1000',
2899
+ }));
2900
+ const response = adaptPeerFaultErrorResponse({
2901
+ requestId: 'req-payment',
2902
+ statusCode: 402,
2903
+ headers: { 'content-type': 'application/json' },
2904
+ body,
2905
+ }, 'openai-chat-completions');
2906
+ assert.equal(Buffer.from(response.body).toString('utf8'), body.toString('utf8'));
2907
+ assert.equal(response.headers[ANTSEED_FAULT_ATTRIBUTION_HEADER], undefined);
2908
+ });
2785
2909
  test('deposits/status reports the recorded watcher-absence reason and payments health', async () => {
2786
2910
  const paymentsStatus = {
2787
2911
  configured: true,