@nookplot/runtime 0.5.142 → 0.5.143

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 (140) hide show
  1. package/dist/__tests__/apiMarketplace.test.js +189 -2
  2. package/dist/__tests__/apiMarketplace.test.js.map +1 -1
  3. package/dist/__tests__/autonomous.dedup.test.js +11 -0
  4. package/dist/__tests__/autonomous.dedup.test.js.map +1 -1
  5. package/dist/__tests__/autonomous.getAvailableActions.test.js +13 -1
  6. package/dist/__tests__/autonomous.getAvailableActions.test.js.map +1 -1
  7. package/dist/__tests__/autonomous.goalBootstrap.test.d.ts +2 -0
  8. package/dist/__tests__/autonomous.goalBootstrap.test.d.ts.map +1 -0
  9. package/dist/__tests__/autonomous.goalBootstrap.test.js +148 -0
  10. package/dist/__tests__/autonomous.goalBootstrap.test.js.map +1 -0
  11. package/dist/__tests__/autonomous.miningTrack.test.d.ts +2 -0
  12. package/dist/__tests__/autonomous.miningTrack.test.d.ts.map +1 -0
  13. package/dist/__tests__/autonomous.miningTrack.test.js +38 -0
  14. package/dist/__tests__/autonomous.miningTrack.test.js.map +1 -0
  15. package/dist/__tests__/autonomous.payApi.test.d.ts +2 -0
  16. package/dist/__tests__/autonomous.payApi.test.d.ts.map +1 -0
  17. package/dist/__tests__/autonomous.payApi.test.js +73 -0
  18. package/dist/__tests__/autonomous.payApi.test.js.map +1 -0
  19. package/dist/__tests__/autonomous.workspaceOpportunity.test.d.ts +2 -0
  20. package/dist/__tests__/autonomous.workspaceOpportunity.test.d.ts.map +1 -0
  21. package/dist/__tests__/autonomous.workspaceOpportunity.test.js +200 -0
  22. package/dist/__tests__/autonomous.workspaceOpportunity.test.js.map +1 -0
  23. package/dist/__tests__/codegen-drift.test.js +3 -1
  24. package/dist/__tests__/codegen-drift.test.js.map +1 -1
  25. package/dist/__tests__/conversation/modelThresholdsParity.test.js +19 -14
  26. package/dist/__tests__/conversation/modelThresholdsParity.test.js.map +1 -1
  27. package/dist/__tests__/economy.surplusBranch.test.js +64 -0
  28. package/dist/__tests__/economy.surplusBranch.test.js.map +1 -1
  29. package/dist/__tests__/goalLoop.test.d.ts +2 -0
  30. package/dist/__tests__/goalLoop.test.d.ts.map +1 -0
  31. package/dist/__tests__/goalLoop.test.js +358 -0
  32. package/dist/__tests__/goalLoop.test.js.map +1 -0
  33. package/dist/__tests__/helpers/mockRuntime.d.ts.map +1 -1
  34. package/dist/__tests__/helpers/mockRuntime.js +7 -0
  35. package/dist/__tests__/helpers/mockRuntime.js.map +1 -1
  36. package/dist/__tests__/loadProfile.test.d.ts +8 -0
  37. package/dist/__tests__/loadProfile.test.d.ts.map +1 -0
  38. package/dist/__tests__/loadProfile.test.js +134 -0
  39. package/dist/__tests__/loadProfile.test.js.map +1 -0
  40. package/dist/__tests__/mining.test.d.ts +2 -0
  41. package/dist/__tests__/mining.test.d.ts.map +1 -0
  42. package/dist/__tests__/mining.test.js +306 -0
  43. package/dist/__tests__/mining.test.js.map +1 -0
  44. package/dist/__tests__/presetLoader.test.d.ts +2 -0
  45. package/dist/__tests__/presetLoader.test.d.ts.map +1 -0
  46. package/dist/__tests__/presetLoader.test.js +749 -0
  47. package/dist/__tests__/presetLoader.test.js.map +1 -0
  48. package/dist/__tests__/signalActionMap.test.d.ts +17 -0
  49. package/dist/__tests__/signalActionMap.test.d.ts.map +1 -0
  50. package/dist/__tests__/signalActionMap.test.js +165 -0
  51. package/dist/__tests__/signalActionMap.test.js.map +1 -0
  52. package/dist/__tests__/usdcBudget.test.d.ts +2 -0
  53. package/dist/__tests__/usdcBudget.test.d.ts.map +1 -0
  54. package/dist/__tests__/usdcBudget.test.js +128 -0
  55. package/dist/__tests__/usdcBudget.test.js.map +1 -0
  56. package/dist/__tests__/x402.test.d.ts +2 -0
  57. package/dist/__tests__/x402.test.d.ts.map +1 -0
  58. package/dist/__tests__/x402.test.js +117 -0
  59. package/dist/__tests__/x402.test.js.map +1 -0
  60. package/dist/actionCatalog.d.ts.map +1 -1
  61. package/dist/actionCatalog.generated.d.ts +1 -1
  62. package/dist/actionCatalog.generated.d.ts.map +1 -1
  63. package/dist/actionCatalog.generated.js +143 -23
  64. package/dist/actionCatalog.generated.js.map +1 -1
  65. package/dist/actionCatalog.js +0 -10
  66. package/dist/actionCatalog.js.map +1 -1
  67. package/dist/api-marketplace.d.ts +146 -0
  68. package/dist/api-marketplace.d.ts.map +1 -1
  69. package/dist/api-marketplace.js +218 -0
  70. package/dist/api-marketplace.js.map +1 -1
  71. package/dist/autonomous.d.ts +16 -9
  72. package/dist/autonomous.d.ts.map +1 -1
  73. package/dist/autonomous.js +268 -59
  74. package/dist/autonomous.js.map +1 -1
  75. package/dist/contentSafety.d.ts +1 -1
  76. package/dist/contentSafety.d.ts.map +1 -1
  77. package/dist/contentSafety.js +6 -2
  78. package/dist/contentSafety.js.map +1 -1
  79. package/dist/discovery.js +1 -1
  80. package/dist/discovery.js.map +1 -1
  81. package/dist/economy.d.ts +10 -15
  82. package/dist/economy.d.ts.map +1 -1
  83. package/dist/economy.js +16 -29
  84. package/dist/economy.js.map +1 -1
  85. package/dist/goal/goalLoop.d.ts +78 -0
  86. package/dist/goal/goalLoop.d.ts.map +1 -0
  87. package/dist/goal/goalLoop.js +388 -0
  88. package/dist/goal/goalLoop.js.map +1 -0
  89. package/dist/goal/goalPrompts.d.ts +20 -0
  90. package/dist/goal/goalPrompts.d.ts.map +1 -0
  91. package/dist/goal/goalPrompts.js +54 -0
  92. package/dist/goal/goalPrompts.js.map +1 -0
  93. package/dist/goal/types.d.ts +102 -0
  94. package/dist/goal/types.d.ts.map +1 -0
  95. package/dist/goal/types.js +7 -0
  96. package/dist/goal/types.js.map +1 -0
  97. package/dist/identity.d.ts +51 -0
  98. package/dist/identity.d.ts.map +1 -1
  99. package/dist/identity.js +50 -0
  100. package/dist/identity.js.map +1 -1
  101. package/dist/index.d.ts +20 -3
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +16 -1
  104. package/dist/index.js.map +1 -1
  105. package/dist/loadProfile.d.ts +100 -0
  106. package/dist/loadProfile.d.ts.map +1 -0
  107. package/dist/loadProfile.js +221 -0
  108. package/dist/loadProfile.js.map +1 -0
  109. package/dist/presetLoader.d.ts +130 -0
  110. package/dist/presetLoader.d.ts.map +1 -0
  111. package/dist/presetLoader.js +734 -0
  112. package/dist/presetLoader.js.map +1 -0
  113. package/dist/signalActionMap.d.ts.map +1 -1
  114. package/dist/signalActionMap.js +15 -5
  115. package/dist/signalActionMap.js.map +1 -1
  116. package/dist/swarms.d.ts +13 -0
  117. package/dist/swarms.d.ts.map +1 -1
  118. package/dist/swarms.js +4 -0
  119. package/dist/swarms.js.map +1 -1
  120. package/dist/tools.js +1 -1
  121. package/dist/tools.js.map +1 -1
  122. package/dist/types.d.ts +21 -0
  123. package/dist/types.d.ts.map +1 -1
  124. package/dist/usdcBudget.d.ts +90 -0
  125. package/dist/usdcBudget.d.ts.map +1 -0
  126. package/dist/usdcBudget.js +155 -0
  127. package/dist/usdcBudget.js.map +1 -0
  128. package/dist/x402.d.ts +69 -0
  129. package/dist/x402.d.ts.map +1 -0
  130. package/dist/x402.js +139 -0
  131. package/dist/x402.js.map +1 -0
  132. package/package.json +2 -2
  133. package/dist/__tests__/economy.frontierInference.test.d.ts +0 -2
  134. package/dist/__tests__/economy.frontierInference.test.d.ts.map +0 -1
  135. package/dist/__tests__/economy.frontierInference.test.js +0 -61
  136. package/dist/__tests__/economy.frontierInference.test.js.map +0 -1
  137. package/dist/frontierPass.d.ts +0 -30
  138. package/dist/frontierPass.d.ts.map +0 -1
  139. package/dist/frontierPass.js +0 -42
  140. package/dist/frontierPass.js.map +0 -1
@@ -0,0 +1,155 @@
1
+ /**
2
+ * UsdcBudget — a hard-stop, rolling-window USDC spend cap for the per-call x402
3
+ * `pay_api` action.
4
+ *
5
+ * A first-class sibling to the goal loop's `budgetNook`, with two deliberate
6
+ * differences: it is **money-denominated** (USDC base units) and it **enforces**
7
+ * (`budgetNook` is soft/warn-only — `goalLoop.ts:190`). One tracker per agent
8
+ * process, hung off `runtime.usdcBudget`, so every `pay_api` dispatch site
9
+ * (reactive + goal-loop, TS + the Python mirror) shares the SAME ledger and the
10
+ * cap holds no matter which path spends.
11
+ *
12
+ * Enforcement model (zero overshoot):
13
+ * 1. Before paying, a dispatch site asks `maxForNextCall()` for the largest
14
+ * amount this call may spend (min of the per-call ceiling and remaining
15
+ * daily headroom). It passes that as `payAndCall`'s `maxAmountBaseUnits`,
16
+ * which aborts BEFORE signing if the 402 quote exceeds it.
17
+ * 2. After a successful pay, the site `record()`s the exact amount.
18
+ * 3. The goal loop reads `isExhausted()` and terminates with `blocked_budget`
19
+ * once the daily cap is fully consumed (the consumer that finally makes the
20
+ * `blocked_budget` outcome live — see `goal/types.ts`).
21
+ *
22
+ * Amounts are USDC base units (6 decimals): 1 USDC = 1_000_000n.
23
+ * A `dailyCapBaseUnits` of 0n means "unlimited" (cap disabled); likewise 0n for
24
+ * the per-call ceiling means "no per-call ceiling".
25
+ *
26
+ * @module usdcBudget
27
+ */
28
+ /** USDC has 6 decimals on Base. */
29
+ export const USDC_DECIMALS = 6;
30
+ const USDC_ONE = 1000000n;
31
+ /** Default daily cap when nothing is configured: $10/day. Conservative
32
+ * safety net for a runaway buyer — operators raise it via `X402_DAILY_USDC_CAP`
33
+ * (or `dailyCapBaseUnits: 0n` to disable). pay_api is the only consumer, so a
34
+ * non-zero default never affects non-buying agents. */
35
+ export const DEFAULT_DAILY_USDC_CAP_BASE_UNITS = 10n * USDC_ONE;
36
+ const WINDOW_MS = 24 * 60 * 60 * 1000;
37
+ /** Parse a USDC display amount ("10", "0.5") into base units. Returns 0n
38
+ * (unlimited) for empty / non-positive / unparseable input. */
39
+ export function parseUsdcToBaseUnits(display) {
40
+ if (!display)
41
+ return 0n;
42
+ const trimmed = display.trim();
43
+ if (!/^\d+(\.\d+)?$/.test(trimmed))
44
+ return 0n;
45
+ const [whole, frac = ""] = trimmed.split(".");
46
+ const fracPadded = (frac + "000000").slice(0, USDC_DECIMALS);
47
+ return BigInt(whole) * USDC_ONE + BigInt(fracPadded || "0");
48
+ }
49
+ /** Format base units as a `$x.xx` USDC string for log/agent messages. */
50
+ export function formatUsdc(baseUnits) {
51
+ const whole = baseUnits / USDC_ONE;
52
+ const frac = (baseUnits % USDC_ONE).toString().padStart(USDC_DECIMALS, "0").replace(/0+$/, "");
53
+ return frac ? `$${whole}.${frac}` : `$${whole}`;
54
+ }
55
+ export class UsdcBudget {
56
+ /** Daily cap in USDC base units. 0n = unlimited. */
57
+ dailyCapBaseUnits;
58
+ /** Per-call ceiling in USDC base units. 0n = none. */
59
+ perCallCapBaseUnits;
60
+ windowMs;
61
+ now;
62
+ spentBaseUnits = 0n;
63
+ windowStartMs;
64
+ constructor(opts = {}) {
65
+ this.dailyCapBaseUnits = opts.dailyCapBaseUnits ?? DEFAULT_DAILY_USDC_CAP_BASE_UNITS;
66
+ this.perCallCapBaseUnits = opts.perCallCapBaseUnits ?? 0n;
67
+ this.windowMs = opts.windowMs ?? WINDOW_MS;
68
+ this.now = opts.now ?? (() => Date.now());
69
+ this.windowStartMs = this.now();
70
+ }
71
+ /** Roll the spend window when the current 24h period has elapsed. */
72
+ roll() {
73
+ const t = this.now();
74
+ if (t - this.windowStartMs >= this.windowMs) {
75
+ this.spentBaseUnits = 0n;
76
+ this.windowStartMs = t;
77
+ }
78
+ }
79
+ /** Pre-pay check for a known quote. Honors both the per-call ceiling and the
80
+ * remaining daily headroom. */
81
+ check(amountBaseUnits) {
82
+ this.roll();
83
+ if (this.perCallCapBaseUnits > 0n && amountBaseUnits > this.perCallCapBaseUnits) {
84
+ return {
85
+ allowed: false,
86
+ reason: `per-call ${formatUsdc(amountBaseUnits)} exceeds the ceiling ${formatUsdc(this.perCallCapBaseUnits)}`,
87
+ remainingBaseUnits: this.remaining(),
88
+ };
89
+ }
90
+ if (this.dailyCapBaseUnits > 0n && this.spentBaseUnits + amountBaseUnits > this.dailyCapBaseUnits) {
91
+ return {
92
+ allowed: false,
93
+ reason: `daily USDC cap ${formatUsdc(this.dailyCapBaseUnits)} would be exceeded (already spent ${formatUsdc(this.spentBaseUnits)})`,
94
+ remainingBaseUnits: this.remaining(),
95
+ };
96
+ }
97
+ return { allowed: true, remainingBaseUnits: this.remaining() };
98
+ }
99
+ /** The largest amount a single call may spend right now (min of per-call
100
+ * ceiling and remaining daily headroom). `undefined` = unlimited. `0n` =
101
+ * budget already exhausted (caller should not pay at all). */
102
+ maxForNextCall() {
103
+ this.roll();
104
+ const limits = [];
105
+ if (this.perCallCapBaseUnits > 0n)
106
+ limits.push(this.perCallCapBaseUnits);
107
+ if (this.dailyCapBaseUnits > 0n)
108
+ limits.push(this.dailyCapBaseUnits - this.spentBaseUnits);
109
+ if (limits.length === 0)
110
+ return undefined; // fully unlimited
111
+ const m = limits.reduce((a, b) => (b < a ? b : a));
112
+ return m > 0n ? m : 0n;
113
+ }
114
+ /** Record a completed spend (call AFTER a successful payment). */
115
+ record(amountBaseUnits) {
116
+ this.roll();
117
+ if (amountBaseUnits > 0n)
118
+ this.spentBaseUnits += amountBaseUnits;
119
+ }
120
+ /** Remaining daily headroom in base units; -1n when unlimited. */
121
+ remaining() {
122
+ if (this.dailyCapBaseUnits === 0n)
123
+ return -1n;
124
+ this.roll();
125
+ const r = this.dailyCapBaseUnits - this.spentBaseUnits;
126
+ return r > 0n ? r : 0n;
127
+ }
128
+ /** True when a daily cap is set and fully consumed — the goal loop's
129
+ * `blocked_budget` trigger. Always false when unlimited. */
130
+ isExhausted() {
131
+ if (this.dailyCapBaseUnits === 0n)
132
+ return false;
133
+ this.roll();
134
+ return this.spentBaseUnits >= this.dailyCapBaseUnits;
135
+ }
136
+ /** Spent-so-far in the current window (base units). */
137
+ get spent() {
138
+ this.roll();
139
+ return this.spentBaseUnits;
140
+ }
141
+ }
142
+ /** Build a UsdcBudget from explicit options falling back to env
143
+ * (`X402_DAILY_USDC_CAP`, `X402_PER_CALL_USDC_CAP`, both USDC display units)
144
+ * and finally the conservative default daily cap. */
145
+ export function createUsdcBudget(opts = {}) {
146
+ const env = typeof process !== "undefined" ? process.env : undefined;
147
+ const dailyCapBaseUnits = opts.dailyCapBaseUnits ??
148
+ (env?.X402_DAILY_USDC_CAP !== undefined
149
+ ? parseUsdcToBaseUnits(env.X402_DAILY_USDC_CAP)
150
+ : DEFAULT_DAILY_USDC_CAP_BASE_UNITS);
151
+ const perCallCapBaseUnits = opts.perCallCapBaseUnits ??
152
+ (env?.X402_PER_CALL_USDC_CAP !== undefined ? parseUsdcToBaseUnits(env.X402_PER_CALL_USDC_CAP) : 0n);
153
+ return new UsdcBudget({ ...opts, dailyCapBaseUnits, perCallCapBaseUnits });
154
+ }
155
+ //# sourceMappingURL=usdcBudget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usdcBudget.js","sourceRoot":"","sources":["../src/usdcBudget.ts"],"names":[],"mappings":"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"}
package/dist/x402.d.ts ADDED
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Optional convenience wrapper for paying marketplace API listings per-call via
3
+ * x402 (ROADMAP_x402-marketplace-fees.md v2). This is NOT required — any standard
4
+ * x402 client (Base MCP, x402-axios, x402-py) can pay a Nookplot listing because
5
+ * the gateway speaks the standard `"exact"` scheme. This wrapper just removes the
6
+ * boilerplate for agents already holding an ethers signer.
7
+ *
8
+ * Unlike the agreement-based {@link ApiMarketplaceManager.proxyRequest}, the x402
9
+ * path is **accountless**: there is no gateway API key and no on-chain agreement.
10
+ * The buyer's per-call EIP-3009 USDC authorization IS the payment + the auth.
11
+ *
12
+ * Flow:
13
+ * 1. Probe `GET/POST /v1/api-x402/:listingId/*` with no payment → HTTP 402 +
14
+ * the `accepts[]` challenge (splitter `payTo`, USDC `asset`, price).
15
+ * 2. Sign an EIP-3009 `ReceiveWithAuthorization` over the advertised amount.
16
+ * 3. Re-send the request with the encoded payment header → upstream response.
17
+ *
18
+ * v2.0 accepts USDC only, so the token's EIP-712 domain is the USDC default
19
+ * ("USD Coin" / "2"). NOOK (a different domain) is deferred to v2.1.
20
+ *
21
+ * @module x402
22
+ */
23
+ import { ethers } from "ethers";
24
+ export interface X402PayAndCallInput {
25
+ /** On-chain listing id. */
26
+ listingId: number | string;
27
+ /** Upstream path after the listing id (e.g. "chat/completions"). */
28
+ path: string;
29
+ /** HTTP method. Default "GET". */
30
+ method?: string;
31
+ /** JSON request body (serialized for non-GET/HEAD). */
32
+ body?: unknown;
33
+ /** Extra request headers passed through to the upstream. */
34
+ headers?: Record<string, string>;
35
+ /** Hard per-call ceiling in USDC base units. When set, `payAndCall` throws
36
+ * BEFORE signing if the 402-quoted `maxAmountRequired` exceeds it. The
37
+ * `pay_api` dispatch sites pass `runtime.usdcBudget.maxForNextCall()` here so
38
+ * the spend cap is enforced at the point of payment. */
39
+ maxAmountBaseUnits?: bigint;
40
+ }
41
+ export interface X402PayAndCallResult {
42
+ status: number;
43
+ headers: Record<string, string>;
44
+ /** Parsed JSON when possible, else raw text. */
45
+ body: unknown;
46
+ /** True when a payment was signed + submitted; false when the gateway
47
+ * short-circuited before payment (e.g. listing unavailable). */
48
+ paid: boolean;
49
+ /** USDC base units actually authorized when `paid` is true (the 402
50
+ * `maxAmountRequired`). Lets the caller record the spend against a budget. */
51
+ amountPaidBaseUnits?: string;
52
+ }
53
+ export interface X402ManagerOptions {
54
+ /** Override the EIP-712 chain id (else derived from the 402 `network`). */
55
+ chainId?: number;
56
+ }
57
+ export declare class X402Manager {
58
+ private readonly gatewayUrl;
59
+ private readonly chainIdOverride?;
60
+ constructor(gatewayUrl: string, opts?: X402ManagerOptions);
61
+ /**
62
+ * Pay for and make a single metered call to a marketplace API listing.
63
+ *
64
+ * @param input The listing + upstream request.
65
+ * @param signer An ethers signer holding the buyer's USDC (e.g. `new ethers.Wallet(pk)`).
66
+ */
67
+ payAndCall(input: X402PayAndCallInput, signer: ethers.Signer): Promise<X402PayAndCallResult>;
68
+ }
69
+ //# sourceMappingURL=x402.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"x402.d.ts","sourceRoot":"","sources":["../src/x402.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAgBhC,MAAM,WAAW,mBAAmB;IAClC,2BAA2B;IAC3B,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC;;;6DAGyD;IACzD,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,gDAAgD;IAChD,IAAI,EAAE,OAAO,CAAC;IACd;qEACiE;IACjE,IAAI,EAAE,OAAO,CAAC;IACd;mFAC+E;IAC/E,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAYD,MAAM,WAAW,kBAAkB;IACjC,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAS;gBAE9B,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB;IAK7D;;;;;OAKG;IACG,UAAU,CAAC,KAAK,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAiEnG"}
package/dist/x402.js ADDED
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Optional convenience wrapper for paying marketplace API listings per-call via
3
+ * x402 (ROADMAP_x402-marketplace-fees.md v2). This is NOT required — any standard
4
+ * x402 client (Base MCP, x402-axios, x402-py) can pay a Nookplot listing because
5
+ * the gateway speaks the standard `"exact"` scheme. This wrapper just removes the
6
+ * boilerplate for agents already holding an ethers signer.
7
+ *
8
+ * Unlike the agreement-based {@link ApiMarketplaceManager.proxyRequest}, the x402
9
+ * path is **accountless**: there is no gateway API key and no on-chain agreement.
10
+ * The buyer's per-call EIP-3009 USDC authorization IS the payment + the auth.
11
+ *
12
+ * Flow:
13
+ * 1. Probe `GET/POST /v1/api-x402/:listingId/*` with no payment → HTTP 402 +
14
+ * the `accepts[]` challenge (splitter `payTo`, USDC `asset`, price).
15
+ * 2. Sign an EIP-3009 `ReceiveWithAuthorization` over the advertised amount.
16
+ * 3. Re-send the request with the encoded payment header → upstream response.
17
+ *
18
+ * v2.0 accepts USDC only, so the token's EIP-712 domain is the USDC default
19
+ * ("USD Coin" / "2"). NOOK (a different domain) is deferred to v2.1.
20
+ *
21
+ * @module x402
22
+ */
23
+ import { ethers } from "ethers";
24
+ /** EIP-3009 ReceiveWithAuthorization typed-data fields (USDC FiatTokenV2). */
25
+ const RECEIVE_WITH_AUTHORIZATION_TYPES = {
26
+ ReceiveWithAuthorization: [
27
+ { name: "from", type: "address" },
28
+ { name: "to", type: "address" },
29
+ { name: "value", type: "uint256" },
30
+ { name: "validAfter", type: "uint256" },
31
+ { name: "validBefore", type: "uint256" },
32
+ { name: "nonce", type: "bytes32" },
33
+ ],
34
+ };
35
+ const DEFAULT_TIMEOUT_SECONDS = 600;
36
+ export class X402Manager {
37
+ gatewayUrl;
38
+ chainIdOverride;
39
+ constructor(gatewayUrl, opts = {}) {
40
+ this.gatewayUrl = gatewayUrl.replace(/\/+$/, "");
41
+ this.chainIdOverride = opts.chainId;
42
+ }
43
+ /**
44
+ * Pay for and make a single metered call to a marketplace API listing.
45
+ *
46
+ * @param input The listing + upstream request.
47
+ * @param signer An ethers signer holding the buyer's USDC (e.g. `new ethers.Wallet(pk)`).
48
+ */
49
+ async payAndCall(input, signer) {
50
+ const method = (input.method ?? "GET").toUpperCase();
51
+ const path = String(input.path).replace(/^\/+/, "");
52
+ const url = `${this.gatewayUrl}/v1/api-x402/${input.listingId}/${path}`;
53
+ const bodyStr = input.body !== undefined ? JSON.stringify(input.body) : "";
54
+ const makeInit = (extraHeaders) => {
55
+ const headers = {
56
+ "Content-Type": "application/json",
57
+ ...input.headers,
58
+ ...extraHeaders,
59
+ };
60
+ const init = { method, headers };
61
+ if (bodyStr && !["GET", "HEAD"].includes(method))
62
+ init.body = bodyStr;
63
+ return init;
64
+ };
65
+ // 1. Probe — the gateway answers 402 with the payment challenge.
66
+ const probe = await fetch(url, makeInit());
67
+ if (probe.status !== 402) {
68
+ return toResult(probe, false);
69
+ }
70
+ const challenge = (await probe.json());
71
+ const accept = challenge.accepts?.[0];
72
+ if (!accept || accept.scheme !== "exact") {
73
+ throw new Error("x402: gateway did not offer a supported 'exact' payment option");
74
+ }
75
+ // Hard spend guard — refuse BEFORE signing if the quoted price exceeds the
76
+ // caller's per-call ceiling (the budgetUsdc cap). No funds move.
77
+ if (input.maxAmountBaseUnits !== undefined) {
78
+ const quote = BigInt(accept.maxAmountRequired);
79
+ if (quote > input.maxAmountBaseUnits) {
80
+ throw new Error(`x402 spend blocked: quoted ${quote} base units exceeds the allowed ${input.maxAmountBaseUnits} for this call (USDC spend cap)`);
81
+ }
82
+ }
83
+ // 2. Sign the EIP-3009 authorization over the advertised amount.
84
+ const from = await signer.getAddress();
85
+ const chainId = this.chainIdOverride ?? parseChainId(accept.network);
86
+ const nowSec = Math.floor(Date.now() / 1000);
87
+ const authorization = {
88
+ from,
89
+ to: accept.payTo,
90
+ value: accept.maxAmountRequired,
91
+ validAfter: 0,
92
+ validBefore: nowSec + (accept.maxTimeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS),
93
+ nonce: ethers.hexlify(ethers.randomBytes(32)),
94
+ };
95
+ const domain = {
96
+ name: accept.extra?.eip712?.name ?? "USD Coin",
97
+ version: accept.extra?.eip712?.version ?? "2",
98
+ chainId,
99
+ verifyingContract: accept.asset,
100
+ };
101
+ const signature = await signer.signTypedData(domain, RECEIVE_WITH_AUTHORIZATION_TYPES, authorization);
102
+ // 3. Re-send with the encoded payment header.
103
+ const header = encodePaymentHeader({ payload: { authorization, signature } });
104
+ const paid = await fetch(url, makeInit({ "PAYMENT-SIGNATURE": header }));
105
+ return toResult(paid, true, accept.maxAmountRequired);
106
+ }
107
+ }
108
+ function parseChainId(network) {
109
+ const m = /^eip155:(\d+)$/.exec(network);
110
+ if (m)
111
+ return Number(m[1]);
112
+ if (network === "base")
113
+ return 8453;
114
+ if (network === "base-sepolia")
115
+ return 84532;
116
+ throw new Error(`x402: unsupported network "${network}"`);
117
+ }
118
+ function encodePaymentHeader(payload) {
119
+ const json = JSON.stringify(payload);
120
+ return typeof Buffer !== "undefined"
121
+ ? Buffer.from(json, "utf8").toString("base64")
122
+ : btoa(json);
123
+ }
124
+ async function toResult(res, paid, amountPaidBaseUnits) {
125
+ const text = await res.text();
126
+ let body;
127
+ try {
128
+ body = JSON.parse(text);
129
+ }
130
+ catch {
131
+ body = text;
132
+ }
133
+ const headers = {};
134
+ res.headers.forEach((val, key) => {
135
+ headers[key] = val;
136
+ });
137
+ return { status: res.status, headers, body, paid, ...(paid ? { amountPaidBaseUnits } : {}) };
138
+ }
139
+ //# sourceMappingURL=x402.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"x402.js","sourceRoot":"","sources":["../src/x402.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nookplot/runtime",
3
- "version": "0.5.142",
4
- "description": "Agent Runtime SDK — persistent connection, events, memory bridge, and economy for AI agents on Nookplot",
3
+ "version": "0.5.143",
4
+ "description": "Agent Runtime SDK persistent connection, events, memory bridge, and economy for AI agents on Nookplot",
5
5
  "author": "nookplot",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=economy.frontierInference.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"economy.frontierInference.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/economy.frontierInference.test.ts"],"names":[],"mappings":""}
@@ -1,61 +0,0 @@
1
- /**
2
- * EconomyManager.frontierInference() — the one-shot frontier (Surplus) call that
3
- * backs the `use_frontier_model` autonomous action (spends an owner-reserved
4
- * pass). Contract:
5
- * 1. ALWAYS routes to Surplus regardless of the configured default source.
6
- * 2. Returns `costUsdcMicros` = the spend-tracker delta for this call (so the
7
- * caller can finalize the reserved pass with the real settled spend).
8
- * 3. Throws a keyless SurplusError (no network) when there's no private key.
9
- *
10
- * `surplusInference` is mocked here so the test doesn't require the optional
11
- * x402/viem peers (the real-client path is covered by economy.surplusBranch).
12
- */
13
- import { describe, it, expect, vi, beforeEach } from "vitest";
14
- vi.mock("../inference/surplusInference.js", async (importOriginal) => {
15
- const actual = await importOriginal();
16
- return {
17
- ...actual,
18
- // Simulate an x402 spend of $0.042 by bumping the shared tracker, and echo
19
- // the requested model so we can assert the override took effect.
20
- surplusInference: vi.fn(async (params) => {
21
- if (params.tracker)
22
- params.tracker.spentBaseUnits += 42000n;
23
- return {
24
- content: "frontier says hi",
25
- model: params.options?.model ?? "unknown",
26
- provider: "surplus",
27
- usage: { promptTokens: 1, completionTokens: 1, totalTokens: 2, creditsCost: 0 },
28
- };
29
- }),
30
- };
31
- });
32
- const { ConnectionManager } = await import("../connection.js");
33
- const { EconomyManager } = await import("../economy.js");
34
- const surplusMod = await import("../inference/surplusInference.js");
35
- const TEST_PK = "0x" + "ab".repeat(32);
36
- const TEST_BASE = "https://gateway.example.com";
37
- const MSGS = [{ role: "user", content: "Prove the theorem." }];
38
- beforeEach(() => vi.clearAllMocks());
39
- describe("EconomyManager.frontierInference()", () => {
40
- it("routes to Surplus even when the default source is platform, and returns the cost delta", async () => {
41
- const economy = new EconomyManager(new ConnectionManager({
42
- gatewayUrl: TEST_BASE,
43
- apiKey: "nk_test",
44
- privateKey: TEST_PK,
45
- inferenceSource: "platform", // default — frontierInference overrides to Surplus
46
- surplus: { model: "llama-3.3-70b" },
47
- }));
48
- const result = await economy.frontierInference(MSGS, { model: "claude-opus-4.8" });
49
- expect(surplusMod.surplusInference).toHaveBeenCalledTimes(1);
50
- expect(result.provider).toBe("surplus");
51
- expect(result.content).toBe("frontier says hi");
52
- expect(result.model).toBe("claude-opus-4.8"); // the per-call override won
53
- expect(result.costUsdcMicros).toBe(42_000); // tracker delta, 6-dec base units
54
- });
55
- it("throws keyless (no surplus call) when there is no private key", async () => {
56
- const economy = new EconomyManager(new ConnectionManager({ gatewayUrl: TEST_BASE, apiKey: "nk_test" }));
57
- await expect(economy.frontierInference(MSGS, { model: "claude-opus-4.8" })).rejects.toMatchObject({ code: "keyless" });
58
- expect(surplusMod.surplusInference).not.toHaveBeenCalled();
59
- });
60
- });
61
- //# sourceMappingURL=economy.frontierInference.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"economy.frontierInference.test.js","sourceRoot":"","sources":["../../src/__tests__/economy.frontierInference.test.ts"],"names":[],"mappings":"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"}
@@ -1,30 +0,0 @@
1
- /**
2
- * Shared `use_frontier_model` executor — used by BOTH the runtime's autonomous
3
- * loop (autonomous.ts) and the CLI dispatcher (agentLoop.ts), which have
4
- * parallel action-dispatch paths. Keeping the logic here prevents the two from
5
- * drifting on a money path.
6
- *
7
- * Flow (client-executed, non-custodial — the gateway can't run this):
8
- * 1. consume — claim ONE owner-reserved pass (gateway enforces reserved count
9
- * + rolling daily cap; a 409/429 surfaces as a thrown request error).
10
- * 2. run — one-shot Surplus completion paid by the agent's OWN client-signed
11
- * x402 key (economy.frontierInference).
12
- * 3. finalize — record the real settled spend; OR revert the pass to
13
- * 'reserved' on failure so it isn't wasted.
14
- *
15
- * @module frontierPass
16
- */
17
- import type { ConnectionManager } from "./connection.js";
18
- import type { EconomyManager } from "./economy.js";
19
- export interface FrontierPassResult {
20
- ok?: boolean;
21
- model?: string;
22
- answer?: string;
23
- spent_usdc?: string;
24
- error?: string;
25
- message?: string;
26
- /** Loose result object the agent reads as a tool result. */
27
- [key: string]: unknown;
28
- }
29
- export declare function runFrontierPass(connection: ConnectionManager, economy: EconomyManager, args: Record<string, unknown>, agentAddress?: string): Promise<FrontierPassResult>;
30
- //# sourceMappingURL=frontierPass.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"frontierPass.d.ts","sourceRoot":"","sources":["../src/frontierPass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,MAAM,WAAW,kBAAkB;IACjC,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,wBAAsB,eAAe,CACnC,UAAU,EAAE,iBAAiB,EAC7B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,kBAAkB,CAAC,CAyC7B"}
@@ -1,42 +0,0 @@
1
- export async function runFrontierPass(connection, economy, args, agentAddress) {
2
- const model = String(args.model ?? "").trim();
3
- const task = String(args.task ?? "").trim();
4
- const reason = typeof args.reason === "string" ? args.reason.slice(0, 280) : undefined;
5
- if (!model)
6
- return { error: "bad_model", message: "Pass a `model` (a Surplus model id)." };
7
- if (!task)
8
- return { error: "bad_task", message: "Pass the `task` — the full self-contained prompt for the frontier model." };
9
- if (!agentAddress)
10
- return { error: "frontier_unavailable", message: "Agent address unknown — cannot consume a pass." };
11
- // 1. Claim a reserved pass.
12
- let claim;
13
- try {
14
- claim = await connection.request("POST", `/v1/agents/${agentAddress}/inference-passes/consume`, { model, reason });
15
- }
16
- catch (err) {
17
- const msg = err instanceof Error ? err.message : String(err);
18
- return {
19
- error: "no_reserved_pass",
20
- message: `Couldn't claim a ${model} pass: ${msg}. Ask your owner to reserve passes in the agent's vault.`,
21
- };
22
- }
23
- // 2. Run the one-shot frontier completion (client-signed x402, own USDC).
24
- try {
25
- const out = await economy.frontierInference([{ role: "user", content: task }], { model });
26
- const costUsdcMicros = Number.isFinite(out.costUsdcMicros) ? out.costUsdcMicros : 0;
27
- // 3. Record the settled spend (best-effort — the inference already happened).
28
- await connection
29
- .request("POST", `/v1/agents/${agentAddress}/inference-passes/${claim.passId}/finalize`, { costUsdcMicros })
30
- .catch(() => { });
31
- return { ok: true, model, answer: out.content ?? "", spent_usdc: (costUsdcMicros / 1e6).toFixed(6) };
32
- }
33
- catch (err) {
34
- // x402 declined / timed out / provider error → return the pass to 'reserved'.
35
- await connection
36
- .request("POST", `/v1/agents/${agentAddress}/inference-passes/${claim.passId}/revert`, {})
37
- .catch(() => { });
38
- const msg = err instanceof Error ? err.message : String(err);
39
- return { error: "frontier_call_failed", message: `Frontier call failed (your pass was NOT spent): ${msg}` };
40
- }
41
- }
42
- //# sourceMappingURL=frontierPass.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"frontierPass.js","sourceRoot":"","sources":["../src/frontierPass.ts"],"names":[],"mappings":"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"}