@nookplot/runtime 0.5.138 → 0.5.140

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 (115) hide show
  1. package/dist/__tests__/autonomous.dedup.test.js +11 -0
  2. package/dist/__tests__/autonomous.dedup.test.js.map +1 -1
  3. package/dist/__tests__/autonomous.getAvailableActions.test.js +13 -1
  4. package/dist/__tests__/autonomous.getAvailableActions.test.js.map +1 -1
  5. package/dist/__tests__/autonomous.goalBootstrap.test.d.ts +2 -0
  6. package/dist/__tests__/autonomous.goalBootstrap.test.d.ts.map +1 -0
  7. package/dist/__tests__/autonomous.goalBootstrap.test.js +148 -0
  8. package/dist/__tests__/autonomous.goalBootstrap.test.js.map +1 -0
  9. package/dist/__tests__/autonomous.miningTrack.test.d.ts +2 -0
  10. package/dist/__tests__/autonomous.miningTrack.test.d.ts.map +1 -0
  11. package/dist/__tests__/autonomous.miningTrack.test.js +38 -0
  12. package/dist/__tests__/autonomous.miningTrack.test.js.map +1 -0
  13. package/dist/__tests__/autonomous.workspaceOpportunity.test.d.ts +2 -0
  14. package/dist/__tests__/autonomous.workspaceOpportunity.test.d.ts.map +1 -0
  15. package/dist/__tests__/autonomous.workspaceOpportunity.test.js +200 -0
  16. package/dist/__tests__/autonomous.workspaceOpportunity.test.js.map +1 -0
  17. package/dist/__tests__/codegen-drift.test.js +3 -1
  18. package/dist/__tests__/codegen-drift.test.js.map +1 -1
  19. package/dist/__tests__/conversation/modelThresholdsParity.test.js +6 -11
  20. package/dist/__tests__/conversation/modelThresholdsParity.test.js.map +1 -1
  21. package/dist/__tests__/economy.surplusBranch.test.d.ts +17 -0
  22. package/dist/__tests__/economy.surplusBranch.test.d.ts.map +1 -0
  23. package/dist/__tests__/economy.surplusBranch.test.js +95 -0
  24. package/dist/__tests__/economy.surplusBranch.test.js.map +1 -0
  25. package/dist/__tests__/goalLoop.test.d.ts +2 -0
  26. package/dist/__tests__/goalLoop.test.d.ts.map +1 -0
  27. package/dist/__tests__/goalLoop.test.js +335 -0
  28. package/dist/__tests__/goalLoop.test.js.map +1 -0
  29. package/dist/__tests__/helpers/mockRuntime.d.ts.map +1 -1
  30. package/dist/__tests__/helpers/mockRuntime.js +7 -0
  31. package/dist/__tests__/helpers/mockRuntime.js.map +1 -1
  32. package/dist/__tests__/loadProfile.test.d.ts +8 -0
  33. package/dist/__tests__/loadProfile.test.d.ts.map +1 -0
  34. package/dist/__tests__/loadProfile.test.js +134 -0
  35. package/dist/__tests__/loadProfile.test.js.map +1 -0
  36. package/dist/__tests__/mining.test.d.ts +2 -0
  37. package/dist/__tests__/mining.test.d.ts.map +1 -0
  38. package/dist/__tests__/mining.test.js +306 -0
  39. package/dist/__tests__/mining.test.js.map +1 -0
  40. package/dist/__tests__/presetLoader.test.d.ts +2 -0
  41. package/dist/__tests__/presetLoader.test.d.ts.map +1 -0
  42. package/dist/__tests__/presetLoader.test.js +749 -0
  43. package/dist/__tests__/presetLoader.test.js.map +1 -0
  44. package/dist/__tests__/sandbox.test.js +24 -24
  45. package/dist/__tests__/surplusInference.test.d.ts +11 -0
  46. package/dist/__tests__/surplusInference.test.d.ts.map +1 -0
  47. package/dist/__tests__/surplusInference.test.js +346 -0
  48. package/dist/__tests__/surplusInference.test.js.map +1 -0
  49. package/dist/actionCatalog.generated.d.ts +1 -1
  50. package/dist/actionCatalog.generated.d.ts.map +1 -1
  51. package/dist/actionCatalog.generated.js +168 -19
  52. package/dist/actionCatalog.generated.js.map +1 -1
  53. package/dist/autonomous.d.ts +16 -1
  54. package/dist/autonomous.d.ts.map +1 -1
  55. package/dist/autonomous.js +232 -37
  56. package/dist/autonomous.js.map +1 -1
  57. package/dist/connection.d.ts +5 -1
  58. package/dist/connection.d.ts.map +1 -1
  59. package/dist/connection.js +4 -0
  60. package/dist/connection.js.map +1 -1
  61. package/dist/contentSafety.d.ts +1 -1
  62. package/dist/contentSafety.d.ts.map +1 -1
  63. package/dist/contentSafety.js +6 -2
  64. package/dist/contentSafety.js.map +1 -1
  65. package/dist/conversation/modelLimits.js +17 -17
  66. package/dist/discovery.js +1 -1
  67. package/dist/discovery.js.map +1 -1
  68. package/dist/economy.d.ts +19 -1
  69. package/dist/economy.d.ts.map +1 -1
  70. package/dist/economy.js +35 -1
  71. package/dist/economy.js.map +1 -1
  72. package/dist/goal/goalLoop.d.ts +78 -0
  73. package/dist/goal/goalLoop.d.ts.map +1 -0
  74. package/dist/goal/goalLoop.js +376 -0
  75. package/dist/goal/goalLoop.js.map +1 -0
  76. package/dist/goal/goalPrompts.d.ts +20 -0
  77. package/dist/goal/goalPrompts.d.ts.map +1 -0
  78. package/dist/goal/goalPrompts.js +54 -0
  79. package/dist/goal/goalPrompts.js.map +1 -0
  80. package/dist/goal/types.d.ts +98 -0
  81. package/dist/goal/types.d.ts.map +1 -0
  82. package/dist/goal/types.js +7 -0
  83. package/dist/goal/types.js.map +1 -0
  84. package/dist/identity.d.ts +51 -0
  85. package/dist/identity.d.ts.map +1 -1
  86. package/dist/identity.js +50 -0
  87. package/dist/identity.js.map +1 -1
  88. package/dist/index.d.ts +12 -2
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +6 -0
  91. package/dist/index.js.map +1 -1
  92. package/dist/inference/surplusInference.d.ts +171 -0
  93. package/dist/inference/surplusInference.d.ts.map +1 -0
  94. package/dist/inference/surplusInference.js +455 -0
  95. package/dist/inference/surplusInference.js.map +1 -0
  96. package/dist/loadProfile.d.ts +100 -0
  97. package/dist/loadProfile.d.ts.map +1 -0
  98. package/dist/loadProfile.js +221 -0
  99. package/dist/loadProfile.js.map +1 -0
  100. package/dist/presetLoader.d.ts +130 -0
  101. package/dist/presetLoader.d.ts.map +1 -0
  102. package/dist/presetLoader.js +734 -0
  103. package/dist/presetLoader.js.map +1 -0
  104. package/dist/signalActionMap.d.ts.map +1 -1
  105. package/dist/signalActionMap.js +9 -0
  106. package/dist/signalActionMap.js.map +1 -1
  107. package/dist/swarms.d.ts +13 -0
  108. package/dist/swarms.d.ts.map +1 -1
  109. package/dist/swarms.js +4 -0
  110. package/dist/swarms.js.map +1 -1
  111. package/dist/tools.js +1 -1
  112. package/dist/tools.js.map +1 -1
  113. package/dist/types.d.ts +50 -0
  114. package/dist/types.d.ts.map +1 -1
  115. package/package.json +17 -2
@@ -0,0 +1,455 @@
1
+ /**
2
+ * Surplus Intelligence inference via x402 (non-custodial USDC passthrough).
3
+ *
4
+ * Lets a self-hosted agent pay for inference per-request in USDC, signed and
5
+ * settled directly from its OWN wallet via the x402 protocol — the Nookplot
6
+ * gateway is bypassed entirely (no proxy, no metering, no custody).
7
+ *
8
+ * Scope: self-hosted runtime/CLI agents only. The agent MUST hold a local
9
+ * signing key (`connection.privateKey`). API-key-only / gasless-relay agents
10
+ * cannot sign x402 and are rejected with a {@link SurplusError}.
11
+ *
12
+ * The x402 + viem dependencies are OPTIONAL peers, lazily `import()`-ed only
13
+ * when this path actually runs (mirrors the optional-`ethers` pattern in
14
+ * `signing.ts`). Agents that never select Surplus never load them.
15
+ *
16
+ * @module inference/surplusInference
17
+ */
18
+ import { readFileSync, writeFileSync } from "node:fs";
19
+ // ── Constants (verified against the x402 directory listing + a live 402 probe, 2026-06-01) ──
20
+ /** Canonical Surplus x402 OpenAI-compatible chat-completions endpoint. */
21
+ export const SURPLUS_URL = "https://www.surplusintelligence.ai/x402/api/inference/v1/chat/completions";
22
+ /** CAIP-2 network id for Base mainnet — the only network Surplus settles on. */
23
+ export const SURPLUS_NETWORK = "eip155:8453";
24
+ /** Canonical Base-mainnet USDC (6 decimals). Settlement asset is asserted against this. */
25
+ export const BASE_USDC = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
26
+ /**
27
+ * Canonical Surplus settlement recipient (the x402 `payTo`), from the live 402
28
+ * probe (2026-06-01). Asserted by DEFAULT as defense-in-depth against a spoofed
29
+ * payment recipient. x402 settles to the resource server's single address, so
30
+ * one value is correct for the marketplace (peers are paid off-band, not via
31
+ * this `payTo`). Override via {@link SurplusConfig.payTo} if Surplus rotates it.
32
+ */
33
+ export const SURPLUS_PAYTO = "0x8581784D3E598cCa3482375CFF2409Ac9DD8c402";
34
+ /** Default Surplus model when none is configured (cheap, broadly available). */
35
+ export const DEFAULT_SURPLUS_MODEL = "llama-3.3-70b";
36
+ /**
37
+ * Default per-call USDC ceiling. A safety backstop against a malicious or
38
+ * mispriced 402 quote — generous enough not to block normal frontier calls
39
+ * (starting price ≈ $0.0033/call), tight enough to bound a runaway/spoofed
40
+ * quote. Override via {@link SurplusConfig.maxUsdcPerCall}.
41
+ */
42
+ export const DEFAULT_MAX_USDC_PER_CALL = 1.0;
43
+ /**
44
+ * Default AGGREGATE USDC ceiling per rolling window, applied when no
45
+ * `maxUsdcPerSession` is configured. A long-running autonomous/mining daemon is
46
+ * otherwise bounded only by the per-call cap — this is the one control that
47
+ * bounds TOTAL spend. Generous (~3,000 calls at the ≈$0.0033 starting price) so
48
+ * it never halts normal use, tight enough to stop a runaway. Raise it via
49
+ * {@link SurplusConfig.maxUsdcPerSession} for heavier workloads.
50
+ */
51
+ export const DEFAULT_MAX_USDC_PER_SESSION = 10.0;
52
+ /**
53
+ * Rolling-window length for the per-session cap (24h). When the window elapses
54
+ * the accumulator resets, so the cap behaves as a per-day budget rather than a
55
+ * lifetime one — a persisted tracker won't permanently brick an agent. Mirrors
56
+ * the daily-cap idiom used elsewhere in the protocol.
57
+ */
58
+ const SURPLUS_SESSION_WINDOW_MS = 24 * 60 * 60 * 1000;
59
+ /** USDC has 6 decimals — multiplier from human units to atomic base units. */
60
+ const USDC_DECIMALS = 6;
61
+ const USDC_BASE = 10n ** BigInt(USDC_DECIMALS);
62
+ /**
63
+ * Dynamically import an OPTIONAL peer via a NON-LITERAL specifier. The
64
+ * non-literal specifier makes `tsc` return `Promise<any>` and skip type
65
+ * resolution — `@x402/fetch` ships its types behind an `exports` map that the
66
+ * runtime's `moduleResolution: node` can't follow, and we cast against the
67
+ * hand-verified API anyway (mirrors the optional-`ethers` pattern in
68
+ * `signing.ts`).
69
+ */
70
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
71
+ async function importOptional(specifier) {
72
+ return import(specifier);
73
+ }
74
+ /** True if a thrown error is a "module not installed" failure (ESM or CJS code). */
75
+ function isModuleNotFound(err) {
76
+ if (!err || typeof err !== "object" || !("code" in err))
77
+ return false;
78
+ const code = err.code;
79
+ return code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND";
80
+ }
81
+ /**
82
+ * Walk an error's `cause` chain for a {@link SurplusError}. An x402 transport
83
+ * may re-wrap a selector throw (`over_cap` / `payto_mismatch` / …) in its own
84
+ * error type; this recovers the original typed code so it survives rather than
85
+ * degrading to a generic `request_failed` (mirrors the Python
86
+ * `_find_surplus_error`).
87
+ */
88
+ function findSurplusError(err) {
89
+ let cur = err;
90
+ const seen = new Set();
91
+ for (let i = 0; i < 8; i++) {
92
+ if (cur == null || seen.has(cur))
93
+ break;
94
+ seen.add(cur);
95
+ if (cur instanceof SurplusError)
96
+ return cur;
97
+ cur = cur.cause;
98
+ }
99
+ return null;
100
+ }
101
+ /**
102
+ * Typed error for every Surplus failure mode. Thrown — never swallowed into a
103
+ * silent fallback (default-restrictive: an error must never become an
104
+ * unintended spend on another rail).
105
+ */
106
+ export class SurplusError extends Error {
107
+ /** Stable machine code for programmatic handling / tests. */
108
+ code;
109
+ constructor(message, code = "surplus_error") {
110
+ super(message);
111
+ this.name = "SurplusError";
112
+ this.code = code;
113
+ }
114
+ }
115
+ /** Atomic USDC base units of a requirement (v2 `amount`, fallback v1 `maxAmountRequired`). */
116
+ function requirementBaseUnits(req) {
117
+ const raw = req.amount ?? req.maxAmountRequired;
118
+ if (raw == null) {
119
+ throw new SurplusError("Surplus 402 quote is missing an amount field.", "bad_quote");
120
+ }
121
+ try {
122
+ return BigInt(raw);
123
+ }
124
+ catch {
125
+ throw new SurplusError(`Surplus 402 quote has a non-integer amount: ${String(raw)}`, "bad_quote");
126
+ }
127
+ }
128
+ /** Format atomic USDC base units as a human "$X.XXXXXX" string for error messages. */
129
+ function formatUsdc(baseUnits) {
130
+ const whole = baseUnits / USDC_BASE;
131
+ const frac = (baseUnits % USDC_BASE).toString().padStart(USDC_DECIMALS, "0");
132
+ return `${whole}.${frac}`;
133
+ }
134
+ /** Convert a human USDC ceiling (e.g. 1.0) to atomic base units. */
135
+ export function usdcToBaseUnits(usdc) {
136
+ if (!Number.isFinite(usdc) || usdc < 0) {
137
+ throw new SurplusError(`Invalid maxUsdcPerCall: ${String(usdc)}`, "bad_config");
138
+ }
139
+ // Round to the nearest atomic unit; avoids float drift on values like 0.1.
140
+ return BigInt(Math.round(usdc * Number(USDC_BASE)));
141
+ }
142
+ /** Read-only clock seam (kept tiny so the selector stays easy to reason about). */
143
+ function nowMs() {
144
+ return Date.now();
145
+ }
146
+ /**
147
+ * Load a persisted spend state, rolling the window over if it has elapsed (a
148
+ * restart after the window means a fresh budget). Any read/parse failure starts
149
+ * fresh — persistence is best-effort and never blocks inference.
150
+ */
151
+ function loadSpendState(statePath) {
152
+ const now = nowMs();
153
+ try {
154
+ const obj = JSON.parse(readFileSync(statePath, "utf8"));
155
+ const windowStartMs = typeof obj.windowStartMs === "number" ? obj.windowStartMs : now;
156
+ if (now - windowStartMs >= SURPLUS_SESSION_WINDOW_MS) {
157
+ return { spentBaseUnits: 0n, windowStartMs: now };
158
+ }
159
+ let spent = 0n;
160
+ try {
161
+ spent = BigInt(String(obj.spentBaseUnits));
162
+ }
163
+ catch {
164
+ spent = 0n;
165
+ }
166
+ return { spentBaseUnits: spent < 0n ? 0n : spent, windowStartMs };
167
+ }
168
+ catch {
169
+ return { spentBaseUnits: 0n, windowStartMs: now };
170
+ }
171
+ }
172
+ /** Persist the tracker (best-effort — a write failure never blocks inference). */
173
+ function saveSpendState(statePath, tracker) {
174
+ try {
175
+ writeFileSync(statePath, JSON.stringify({
176
+ spentBaseUnits: tracker.spentBaseUnits.toString(),
177
+ windowStartMs: tracker.windowStartMs,
178
+ }), "utf8");
179
+ }
180
+ catch {
181
+ /* best-effort: never block a paid inference on a persistence failure */
182
+ }
183
+ }
184
+ /**
185
+ * Build a spend tracker for a runtime/session. With no `statePath` it is a fresh
186
+ * in-memory accumulator; with one it loads the prior cumulative spend and
187
+ * persists after each authorized spend so the cap survives restarts.
188
+ */
189
+ export function createSurplusSpendTracker(statePath) {
190
+ if (!statePath) {
191
+ return { spentBaseUnits: 0n, windowStartMs: nowMs() };
192
+ }
193
+ const loaded = loadSpendState(statePath);
194
+ const tracker = {
195
+ spentBaseUnits: loaded.spentBaseUnits,
196
+ windowStartMs: loaded.windowStartMs,
197
+ };
198
+ tracker.persist = () => saveSpendState(statePath, tracker);
199
+ return tracker;
200
+ }
201
+ /**
202
+ * Resolve the effective `payTo` assertion target: an explicit config override,
203
+ * else the canonical {@link SURPLUS_PAYTO}. The recipient is asserted by default
204
+ * (defense-in-depth) — unlike {@link makeSurplusSelector}, which only asserts
205
+ * when given a `payTo` (so its unit-level "open selector" semantics are kept).
206
+ */
207
+ export function resolveSurplusPayTo(config) {
208
+ return config?.payTo ?? SURPLUS_PAYTO;
209
+ }
210
+ /**
211
+ * Build the payment-requirements selector enforcing the spend controls:
212
+ * - scheme must be `exact`, on Base (`eip155:8453`), paying canonical USDC;
213
+ * - if `payTo` is configured, the quote's recipient must match it;
214
+ * - the cheapest eligible quote is chosen, and rejected if it exceeds the
215
+ * per-call cap;
216
+ * - if a `tracker` + `maxSessionBaseUnits` are given, the AUTHORIZED amount is
217
+ * accumulated and rejected once the running total would exceed the session
218
+ * cap. Tracking the authorized (not settled) amount is deliberately
219
+ * conservative: it can only stop spending earlier, never permit an overspend.
220
+ *
221
+ * Any violation throws a {@link SurplusError} (propagates out of the wrapped
222
+ * fetch) — the payment is never signed, and a rejected attempt is NOT counted.
223
+ */
224
+ export function makeSurplusSelector(opts) {
225
+ const wantAsset = (opts.asset ?? BASE_USDC).toLowerCase();
226
+ const wantPayTo = opts.payTo?.toLowerCase();
227
+ return (_x402Version, requirements) => {
228
+ const eligible = requirements.filter((r) => r.scheme === "exact" &&
229
+ String(r.network) === SURPLUS_NETWORK &&
230
+ typeof r.asset === "string" &&
231
+ r.asset.toLowerCase() === wantAsset);
232
+ if (eligible.length === 0) {
233
+ throw new SurplusError("Surplus offered no `exact` USDC payment option on Base (eip155:8453).", "no_eligible_requirement");
234
+ }
235
+ // Cheapest first — defends against an inflated duplicate quote.
236
+ eligible.sort((a, b) => {
237
+ const av = requirementBaseUnits(a);
238
+ const bv = requirementBaseUnits(b);
239
+ return av < bv ? -1 : av > bv ? 1 : 0;
240
+ });
241
+ const chosen = eligible[0];
242
+ if (wantPayTo &&
243
+ typeof chosen.payTo === "string" &&
244
+ chosen.payTo.toLowerCase() !== wantPayTo) {
245
+ throw new SurplusError(`Surplus payTo ${chosen.payTo} does not match the configured expected address.`, "payto_mismatch");
246
+ }
247
+ const amount = requirementBaseUnits(chosen);
248
+ if (amount > opts.maxBaseUnits) {
249
+ throw new SurplusError(`Surplus quote ${formatUsdc(amount)} USDC exceeds the per-call cap of ` +
250
+ `${formatUsdc(opts.maxBaseUnits)} USDC.`, "over_cap");
251
+ }
252
+ // Aggregate session cap — the one control that bounds TOTAL spend across a
253
+ // long-running daemon / mining loop (the per-call cap does not). Record only
254
+ // on success, so a rejected attempt never inflates the total.
255
+ if (opts.tracker && opts.maxSessionBaseUnits != null) {
256
+ const now = nowMs();
257
+ // Roll the window over once it has elapsed (covers both a >24h continuous
258
+ // run and a restart that resumed a still-open window from disk). Seed the
259
+ // window start on first use for trackers created without one.
260
+ if (opts.tracker.windowStartMs &&
261
+ now - opts.tracker.windowStartMs >= SURPLUS_SESSION_WINDOW_MS) {
262
+ opts.tracker.windowStartMs = now;
263
+ opts.tracker.spentBaseUnits = 0n;
264
+ }
265
+ else if (!opts.tracker.windowStartMs) {
266
+ opts.tracker.windowStartMs = now;
267
+ }
268
+ const projected = opts.tracker.spentBaseUnits + amount;
269
+ if (projected > opts.maxSessionBaseUnits) {
270
+ throw new SurplusError(`Surplus session spend ${formatUsdc(projected)} USDC would exceed the ` +
271
+ `per-session cap of ${formatUsdc(opts.maxSessionBaseUnits)} USDC.`, "over_session_cap");
272
+ }
273
+ opts.tracker.spentBaseUnits = projected;
274
+ opts.tracker.persist?.();
275
+ }
276
+ return chosen;
277
+ };
278
+ }
279
+ /**
280
+ * Map runtime messages + options to an OpenAI-compatible chat-completions body.
281
+ * `systemPrompt` is prepended as a `system` message (the runtime convention).
282
+ * Streaming is forced off — v1 is non-streaming.
283
+ */
284
+ export function buildSurplusBody(messages, options, model) {
285
+ const out = [];
286
+ if (options?.systemPrompt) {
287
+ out.push({ role: "system", content: options.systemPrompt });
288
+ }
289
+ for (const m of messages) {
290
+ const om = { role: m.role, content: m.content };
291
+ // Pass through tool-call linkage when present; harmless for prose agents.
292
+ if (m.role === "tool" && m.toolCallId)
293
+ om.tool_call_id = m.toolCallId;
294
+ out.push(om);
295
+ }
296
+ const body = { model, messages: out, stream: false };
297
+ if (options?.maxTokens != null)
298
+ body.max_tokens = options.maxTokens;
299
+ if (options?.temperature != null)
300
+ body.temperature = options.temperature;
301
+ return body;
302
+ }
303
+ function toCount(v) {
304
+ return typeof v === "number" && Number.isFinite(v) ? v : 0;
305
+ }
306
+ /**
307
+ * Decode the `X-PAYMENT-RESPONSE` settlement header (x402 encodes it as
308
+ * base64(JSON); base64url is tolerated). Returns `null` on any failure — the
309
+ * settlement check is best-effort and never blocks a successful 2xx body.
310
+ */
311
+ function decodeSettleHeader(header) {
312
+ try {
313
+ const normalized = header.replace(/-/g, "+").replace(/_/g, "/");
314
+ return JSON.parse(Buffer.from(normalized, "base64").toString("utf8"));
315
+ }
316
+ catch {
317
+ return null;
318
+ }
319
+ }
320
+ /**
321
+ * Parse a Surplus chat-completions Response into an {@link InferenceResult}.
322
+ *
323
+ * Also performs a defensive settlement check: if the `X-PAYMENT-RESPONSE`
324
+ * header decodes to an explicit failure, we surface it rather than returning a
325
+ * body that was not actually paid for. `creditsCost` is always 0 — these calls
326
+ * are paid in USDC, never in Nookplot credits.
327
+ */
328
+ export async function parseSurplusResponse(res, requestedModel) {
329
+ if (!res.ok) {
330
+ let detail = "";
331
+ try {
332
+ detail = (await res.text()).slice(0, 500);
333
+ }
334
+ catch {
335
+ /* ignore body read failure */
336
+ }
337
+ throw new SurplusError(`Surplus returned HTTP ${res.status}${detail ? `: ${detail}` : ""}`, res.status === 402 ? "payment_required" : "http_error");
338
+ }
339
+ // Defensive settlement true-up (best-effort): if the settlement header
340
+ // decodes to an explicit failure, surface it rather than returning a body
341
+ // that was not actually paid for.
342
+ const settleHeader = res.headers.get("X-PAYMENT-RESPONSE");
343
+ if (settleHeader) {
344
+ const settle = decodeSettleHeader(settleHeader);
345
+ if (settle && settle.success === false) {
346
+ throw new SurplusError(`Surplus payment did not settle: ${settle.errorReason ?? settle.errorMessage ?? "unknown reason"}`, "settle_failed");
347
+ }
348
+ }
349
+ let json;
350
+ try {
351
+ json = await res.json();
352
+ }
353
+ catch {
354
+ throw new SurplusError("Surplus returned a non-JSON response body.", "bad_response");
355
+ }
356
+ const obj = (json ?? {});
357
+ const content = obj.choices?.[0]?.message?.content;
358
+ if (typeof content !== "string") {
359
+ throw new SurplusError("Surplus response is missing choices[0].message.content.", "bad_response");
360
+ }
361
+ const usage = obj.usage ?? {};
362
+ return {
363
+ content,
364
+ model: typeof obj.model === "string" ? obj.model : requestedModel,
365
+ provider: "surplus",
366
+ usage: {
367
+ promptTokens: toCount(usage.prompt_tokens),
368
+ completionTokens: toCount(usage.completion_tokens),
369
+ totalTokens: toCount(usage.total_tokens),
370
+ creditsCost: 0,
371
+ },
372
+ };
373
+ }
374
+ /** Normalize a raw private key to the `0x`-prefixed form viem expects. */
375
+ function normalizePrivateKey(pk) {
376
+ const hex = pk.startsWith("0x") ? pk : `0x${pk}`;
377
+ return hex;
378
+ }
379
+ /**
380
+ * Lazily build the x402 payment-wrapped fetch from a raw private key. Imports
381
+ * the optional `@x402/*` + `viem` peers on first use; a missing peer yields a
382
+ * clear install hint. EIP-3009 (`exact`) signing is fully offline — no RPC URL.
383
+ */
384
+ async function buildPaymentFetch(privateKey, selector) {
385
+ try {
386
+ const viemAccounts = await importOptional("viem/accounts");
387
+ const x402Fetch = await importOptional("@x402/fetch");
388
+ const x402Evm = await importOptional("@x402/evm");
389
+ const account = viemAccounts.privateKeyToAccount(normalizePrivateKey(privateKey));
390
+ // `selector` is structurally an x402 SelectPaymentRequirements; the dynamic
391
+ // imports are untyped (any), so the wiring stays contained to this function.
392
+ const client = new x402Fetch.x402Client(selector).register(SURPLUS_NETWORK, new x402Evm.ExactEvmScheme(account));
393
+ return x402Fetch.wrapFetchWithPayment(globalThis.fetch, client);
394
+ }
395
+ catch (err) {
396
+ if (isModuleNotFound(err)) {
397
+ throw new SurplusError("Surplus inference requires the optional peers '@x402/fetch', '@x402/evm', and 'viem'. " +
398
+ "Install them: npm install @x402/fetch @x402/evm viem", "missing_deps");
399
+ }
400
+ if (err instanceof SurplusError)
401
+ throw err;
402
+ throw new SurplusError(`Failed to initialize the Surplus x402 client: ${err instanceof Error ? err.message : String(err)}`, "client_init_failed");
403
+ }
404
+ }
405
+ /**
406
+ * Run a single non-streaming inference against Surplus, paying per-request in
407
+ * USDC via x402 from the agent's own wallet. Returns the same
408
+ * {@link InferenceResult} shape as the gateway path, so it slots transparently
409
+ * into every downstream consumer (chat, autonomous loop, mining, goal loop).
410
+ */
411
+ export async function surplusInference(params) {
412
+ const { privateKey, messages, options, config } = params;
413
+ // Mandatory keyless gate (correctness, not an attack vector): never attempt
414
+ // an unsigned/partial payment. Throw before any network call.
415
+ if (!privateKey) {
416
+ throw new SurplusError("Surplus inference requires a local signing key (set `privateKey`). " +
417
+ "This agent is API-key-only and cannot sign x402 payments.", "keyless");
418
+ }
419
+ const model = options?.model ?? config?.model ?? DEFAULT_SURPLUS_MODEL;
420
+ const url = config?.baseUrl ?? SURPLUS_URL;
421
+ const maxBaseUnits = usdcToBaseUnits(config?.maxUsdcPerCall ?? DEFAULT_MAX_USDC_PER_CALL);
422
+ const selector = makeSurplusSelector({
423
+ maxBaseUnits,
424
+ asset: BASE_USDC,
425
+ payTo: resolveSurplusPayTo(config), // default-on payTo assertion
426
+ tracker: params.tracker,
427
+ // Default-on aggregate cap: a long-running daemon is otherwise bounded only
428
+ // by the per-call cap. Override (incl. a large value to effectively disable)
429
+ // via `maxUsdcPerSession`.
430
+ maxSessionBaseUnits: usdcToBaseUnits(config?.maxUsdcPerSession ?? DEFAULT_MAX_USDC_PER_SESSION),
431
+ });
432
+ const fetchWithPay = params.paymentFetch ?? (await buildPaymentFetch(privateKey, selector));
433
+ const body = buildSurplusBody(messages, options, model);
434
+ let res;
435
+ try {
436
+ res = await fetchWithPay(url, {
437
+ method: "POST",
438
+ headers: { "Content-Type": "application/json" },
439
+ body: JSON.stringify(body),
440
+ });
441
+ }
442
+ catch (err) {
443
+ if (err instanceof SurplusError)
444
+ throw err; // selector cap/asset/payTo rejection
445
+ // A wrapped selector throw (the transport re-raised it as its own error)
446
+ // still carries the typed code on its cause chain — recover it so the
447
+ // specific reason survives instead of a generic `request_failed`.
448
+ const wrapped = findSurplusError(err);
449
+ if (wrapped)
450
+ throw wrapped;
451
+ throw new SurplusError(`Surplus request failed: ${err instanceof Error ? err.message : String(err)}`, "request_failed");
452
+ }
453
+ return parseSurplusResponse(res, model);
454
+ }
455
+ //# sourceMappingURL=surplusInference.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surplusInference.js","sourceRoot":"","sources":["../../src/inference/surplusInference.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Profile-aware credential loading for @nookplot/runtime.
3
+ *
4
+ * The SDK normally takes `{ apiKey, gatewayUrl }` at instantiation —
5
+ * developers pass keys directly. This helper is for developers who want
6
+ * the SDK to read from `~/.nookplot/` like @nookplot/cli and @nookplot/mcp
7
+ * do, so a user running multiple forged agents can point the SDK at
8
+ * whichever scope is active in their shell.
9
+ *
10
+ * Reads from the same files the rest of the Nookplot stack uses:
11
+ * ~/.nookplot/credentials.json ← creator API key (shared)
12
+ * ~/.nookplot/profiles/<name>/profile.json ← per-agent scope
13
+ * ~/.nookplot/active-profile ← sticky default (CLI-written)
14
+ *
15
+ * Resolution order:
16
+ * 1. Explicit `name` argument to loadProfile()
17
+ * 2. NOOKPLOT_PROFILE env var
18
+ * 3. Sticky default from ~/.nookplot/active-profile
19
+ * 4. null (load default creds only, no scope)
20
+ *
21
+ * @module loadProfile
22
+ *
23
+ * @example Basic usage — pick up whatever profile is active
24
+ * ```ts
25
+ * import { NookplotRuntime } from "@nookplot/runtime";
26
+ * import { loadProfile } from "@nookplot/runtime/loadProfile";
27
+ *
28
+ * const creds = loadProfile(); // respects NOOKPLOT_PROFILE env + sticky default
29
+ * if (!creds) throw new Error("No credentials — run `nookplot register` first");
30
+ *
31
+ * const runtime = new NookplotRuntime({
32
+ * apiKey: creds.apiKey,
33
+ * gatewayUrl: creds.gatewayUrl,
34
+ * });
35
+ * ```
36
+ *
37
+ * @example Explicit profile override
38
+ * ```ts
39
+ * const creds = loadProfile("jeffs-researcher");
40
+ * ```
41
+ *
42
+ * @example Multi-agent — run two SDK instances in parallel
43
+ * ```ts
44
+ * const researcherCreds = loadProfile("jeffs-researcher");
45
+ * const writerCreds = loadProfile("jeffs-writer");
46
+ *
47
+ * const researcher = new NookplotRuntime({ apiKey: researcherCreds!.apiKey, ... });
48
+ * const writer = new NookplotRuntime({ apiKey: writerCreds!.apiKey, ... });
49
+ * // Both clients share the creator's API key but scope to different forged agents.
50
+ * ```
51
+ */
52
+ export interface LoadedProfile {
53
+ /** Creator's API key (shared across all forged agents owned by this creator). */
54
+ apiKey: string;
55
+ /** Creator's wallet address. */
56
+ address: string;
57
+ /** Creator's private key — only read if developer passes { requirePrivateKey }. */
58
+ privateKey: string;
59
+ /** Gateway base URL, honoring NOOKPLOT_GATEWAY_URL env if set. */
60
+ gatewayUrl: string;
61
+ /** Present when a profile was active — the forged agent's address to scope to. */
62
+ scopedAgentAddress?: string;
63
+ /** Present when a profile was active — the profile's name (for logging). */
64
+ profileName?: string;
65
+ /** Display name of the creator (not the scoped forged agent). */
66
+ displayName?: string;
67
+ }
68
+ /**
69
+ * Resolve the active profile name in priority order.
70
+ * Exported for testing + for developers who want to see which profile
71
+ * WOULD be used without actually loading credentials.
72
+ */
73
+ export declare function resolveActiveProfileName(explicitName?: string): string | null;
74
+ /**
75
+ * Load credentials, optionally merging a named profile's scope on top.
76
+ *
77
+ * Returns null if no `credentials.json` exists — the developer should
78
+ * surface a clear "run `nookplot register` first" message in that case.
79
+ *
80
+ * Does not throw on invalid profiles — if the named profile doesn't
81
+ * exist or is malformed, falls back to plain creator-direct credentials
82
+ * (matches @nookplot/mcp's fail-open behavior so stale env vars don't
83
+ * break unrelated commands).
84
+ */
85
+ export declare function loadProfile(name?: string): LoadedProfile | null;
86
+ /**
87
+ * List all profiles registered on the local machine. Each entry includes
88
+ * the profile name + its metadata. Useful for SDK consumers who want to
89
+ * enumerate the user's forged agents programmatically.
90
+ *
91
+ * Returns an empty array if ~/.nookplot/profiles doesn't exist. Never
92
+ * throws — invalid profiles are silently skipped.
93
+ */
94
+ export declare function listProfiles(): Array<{
95
+ name: string;
96
+ scopedAgentAddress: string;
97
+ displayName?: string;
98
+ hermesProfile?: string;
99
+ }>;
100
+ //# sourceMappingURL=loadProfile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadProfile.d.ts","sourceRoot":"","sources":["../src/loadProfile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAMH,MAAM,WAAW,aAAa;IAC5B,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,UAAU,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,UAAU,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAsBD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAa7E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAwE/D;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,IAAI,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA8BhI"}