@haven_ai/sdk 0.1.15-alpha.0 → 0.1.17-alpha.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
@@ -531,6 +531,7 @@ function stableStringify(value) {
531
531
  const primitive = JSON.stringify(value);
532
532
  return primitive === void 0 ? "undefined" : primitive;
533
533
  }
534
+ if (value instanceof Date) return JSON.stringify(value.toISOString());
534
535
  if (Array.isArray(value)) return `[${value.map((item) => stableStringify(item)).join(",")}]`;
535
536
  const object = value;
536
537
  return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(object[key])}`).join(",")}}`;
@@ -632,11 +633,24 @@ var DEFAULT_REQUEST_TIMEOUT = 3e4;
632
633
  var DEFAULT_CONFIRMATION_TIMEOUT = 9e4;
633
634
  var DEFAULT_POLLING_INTERVAL = 3e3;
634
635
  function formatAtomicAmount(atomic, decimals) {
636
+ if (atomic < 0n) return "0.0";
635
637
  const s = atomic.toString().padStart(decimals + 1, "0");
636
638
  const intPart = s.slice(0, s.length - decimals) || "0";
637
639
  const fracPart = s.slice(s.length - decimals).replace(/0+$/, "") || "0";
638
640
  return `${intPart}.${fracPart}`;
639
641
  }
642
+ function safeBigInt(value) {
643
+ try {
644
+ return BigInt(value);
645
+ } catch {
646
+ return 0n;
647
+ }
648
+ }
649
+ function deriveReadiness(status, allowances) {
650
+ if (status !== "active") return "revoked";
651
+ const hasSpendable = allowances.some((a) => safeBigInt(a.remainingAtomic) > 0n);
652
+ return hasSpendable ? "ready" : "needs_approval";
653
+ }
640
654
  var MCP_PROTOCOL_VERSION = "2025-06-18";
641
655
  var MCP_ACCEPT = "application/json, text/event-stream";
642
656
  var MCP_CLIENT_INFO = { name: "haven-sdk", version: "1" };
@@ -1003,6 +1017,32 @@ var HavenClient = class {
1003
1017
  chainId: raw.chain_id
1004
1018
  };
1005
1019
  }
1020
+ /**
1021
+ * One-shot "am I ready?" bootstrap: identity + live spend authority + a
1022
+ * readiness signal, in a single call. Folds {@link getAgent} and
1023
+ * {@link getAllowances} together and derives a {@link HavenAgentReadiness}
1024
+ * so an agent can answer "who am I and can I pay right now" at session start
1025
+ * without two round trips and manual assembly.
1026
+ */
1027
+ async getAgentSummary() {
1028
+ const [agent, allowanceSummary] = await Promise.all([
1029
+ this.getAgent(),
1030
+ this.getAllowances()
1031
+ ]);
1032
+ const allowances = allowanceSummary.allowances.map((a) => {
1033
+ const token = resolveTokenFromAddress(a.tokenAddress);
1034
+ const remainingDisplay = token ? `${formatAtomicAmount(safeBigInt(a.onchain.remaining), token.decimals)} ${a.tokenSymbol}` : `${a.onchain.remaining} ${a.tokenSymbol} (atomic; unknown decimals)`;
1035
+ return {
1036
+ tokenSymbol: a.tokenSymbol,
1037
+ remainingAtomic: a.onchain.remaining,
1038
+ remainingDisplay,
1039
+ configuredAmount: a.configuredAmount,
1040
+ resetPeriodMin: a.resetPeriodMin,
1041
+ isResetPending: a.onchain.isResetPending
1042
+ };
1043
+ });
1044
+ return { ...agent, readiness: deriveReadiness(agent.status, allowances), allowances };
1045
+ }
1006
1046
  /**
1007
1047
  * Sweep stranded USDC and ETH from the delegate EOA back to the originating Safe.
1008
1048
  *
@@ -1686,6 +1726,21 @@ var HavenClient = class {
1686
1726
  * accepted), threads the session + wallet headers, sets `X-PAYMENT`, and
1687
1727
  * collapses an SSE JSON-RPC response to its `result`.
1688
1728
  */
1729
+ /**
1730
+ * Wait for a payment's Safe→delegate funding tx to reach ≥1 on-chain
1731
+ * confirmation. The hosted x402 completion path MUST call this after funding
1732
+ * and before delivering the X-PAYMENT header, so the merchant's
1733
+ * balanceOf(delegate) / transferWithAuthorization verification sees the funded
1734
+ * balance — otherwise it rejects with "Payment verification failed". The
1735
+ * SDK's local path already does this (see authorizeStandardX402); the hosted
1736
+ * split flow regressed when the 5→3 collapse removed the incidental
1737
+ * inter-call latency that used to mask it. No-op when the funding tx hash or
1738
+ * a chain RPC (chainRpcs[chainId]) is unavailable.
1739
+ */
1740
+ async ensureFundingConfirmed(paymentId, fundingTxHash) {
1741
+ const status = await this.getPaymentStatus(paymentId);
1742
+ await this.waitForFundingTx(fundingTxHash ?? status.txHash ?? void 0, status.chainId);
1743
+ }
1689
1744
  async completeX402MerchantCall(input) {
1690
1745
  const evidenceContext = await this.resolveX402MerchantCompletionContext({
1691
1746
  paymentId: input.paymentId,
@@ -2961,8 +3016,9 @@ var toolDescriptions = {
2961
3016
  nextActionGuidance: ""
2962
3017
  },
2963
3018
  getAgent: {
2964
- summary: "Return the authenticated agent identity, Haven wallet, delegate address, chain, and status.",
2965
- behavior: "Read-only identity lookup. Useful for verifying which on-chain Safe and delegate the credential is bound to.",
3019
+ summary: "Return the authenticated agent identity AND its live spend authority in one call: Haven wallet, delegate, chain, raw status, a readiness signal, and per-token remaining allowance (atomic + human-readable). The recommended first call in a new session to confirm who you are and whether you can pay right now.",
3020
+ selectionGuidance: "Use this as the one-shot orientation/bootstrap at the start of a session, or whenever you need to confirm identity together with whether the agent can spend right now. For a detailed per-token breakdown (configured vs spent vs reset window) use haven_get_allowances.",
3021
+ behavior: 'Reads identity plus the on-chain AllowanceModule snapshot in one shot. readiness is "ready" when at least one token has remaining on-chain allowance, "needs_approval" when the agent is active but has no remaining allowance to auto-spend (payments will be queued for the wallet owner to approve in Haven), and "revoked" when the credential is not active. allowances[] carries remainingAtomic and remainingDisplay per token. Identity fields (id, name, status, safeAddress, delegateAddress, chainId) are unchanged from before.',
2966
3022
  nextActionGuidance: ""
2967
3023
  },
2968
3024
  getAllowances: {
@@ -3263,12 +3319,28 @@ the \`mcp__haven-signer__\` namespace and keep the delegate key on this machine.
3263
3319
  - A request returns HTTP 402 (x402): use the Haven pay tools to settle it,
3264
3320
  then retry the original request.
3265
3321
 
3266
- ## Identity and budget come from the tools \u2014 never assume them
3322
+ ## Identity and budget
3323
+
3324
+ Do not guess the wallet address, network, or budget.
3325
+
3326
+ For instant orientation at the start of a session, read the non-secret
3327
+ \`agent.json\` the connector wrote to your Haven credential directory (typically
3328
+ \`~/.haven/agents/<agent-id>/agent.json\` \u2014 if you don't know the agent id, list
3329
+ \`~/.haven/agents/\` to find the folder). It
3330
+ holds your agent id, Haven wallet address, network, and *configured* per-token
3331
+ budget, and contains no keys \u2014 the fastest way to answer "who am I and what may
3332
+ I spend" with no round trip. If that file is absent (some setups don't write
3333
+ it), use the tools below instead.
3267
3334
 
3268
- Do not guess the wallet address, network, or budget. Read them live:
3335
+ Before any payment, confirm the *live remaining* budget with the tools \u2014
3336
+ \`agent.json\` shows the configured budget, not what is left after recent
3337
+ spending:
3269
3338
 
3270
- - \`haven_get_agent\` \u2014 agent identity, Haven wallet address, network.
3271
- - \`haven_get_allowances\` \u2014 current per-token budgets and what remains.
3339
+ - \`haven_get_agent\` \u2014 the recommended first call: identity (wallet, network)
3340
+ plus a readiness signal (\`ready\` / \`needs_approval\` / \`revoked\`) and live
3341
+ remaining per-token allowance, in one shot.
3342
+ - \`haven_get_allowances\` \u2014 detailed per-token breakdown (configured, spent,
3343
+ reset window) when you need more than the summary.
3272
3344
 
3273
3345
  Budgets reset on a period the user chose. If a payment exceeds the remaining
3274
3346
  budget it is queued for the user to approve in the Haven dashboard \u2014 this is