@haven_ai/sdk 0.2.1-alpha.0 → 0.4.0-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.d.ts CHANGED
@@ -84,12 +84,10 @@ interface SignData {
84
84
  };
85
85
  /** Breakdown of values that were hashed — useful for debugging */
86
86
  components: {
87
- /** @deprecated #2908 — same value as `payer_account`; the server drops it at #2914. */
88
- safe: string;
89
87
  /**
90
- * #2907 — the account-vocabulary twin of `safe`: the PAYER account
91
- * (the user's smart account). Not to be confused with `account`, which on
92
- * the funding shapes holds the DELEGATE account address.
88
+ * The PAYER account (the user's smart account). Not to be confused with
89
+ * `account`, which on the funding shapes holds the DELEGATE account
90
+ * address.
93
91
  */
94
92
  payer_account?: string;
95
93
  token: string;
@@ -411,6 +409,8 @@ interface X402Quote {
411
409
  request: X402RequestSnapshot;
412
410
  mcpTransport?: X402McpTransport;
413
411
  resourceUrl: string;
412
+ /** #3097: `resourceUrl` (the merchant's declaration) is not `request.url` (what was quoted). */
413
+ resourceUrlDiffersFromRequest: boolean;
414
414
  description: string | null;
415
415
  mimeType: string | null;
416
416
  amountAtomic: string;
@@ -475,16 +475,8 @@ interface HavenAgent {
475
475
  id: string;
476
476
  name: string;
477
477
  status: string;
478
- /**
479
- * The agent's Haven account (smart account) address — #2908, the
480
- * account-vocabulary name. Same value as {@link HavenAgent.safeAddress}.
481
- */
478
+ /** The agent's Haven account (smart account) address. */
482
479
  accountAddress: string;
483
- /**
484
- * @deprecated #2908 — same value as {@link HavenAgent.accountAddress}.
485
- * Removed in the release after the one carrying #2908 (#2914).
486
- */
487
- safeAddress: string;
488
480
  delegateAddress: string;
489
481
  chainId: number;
490
482
  /**
@@ -503,6 +495,14 @@ interface HavenAllowance {
503
495
  tokenSymbol: string;
504
496
  configuredAmount: string;
505
497
  resetPeriodMin: number;
498
+ /**
499
+ * #3128: human-readable `onchain.remaining`, e.g. "4.96 USDC" — the SAME
500
+ * string {@link HavenAgentAllowanceSummary.remainingDisplay} carries for
501
+ * this allowance, computed by one function from `onchain.remaining` and
502
+ * the token's decimals, so the two reads cannot disagree. Additive; the
503
+ * wire carries no display form (it is derived client-side).
504
+ */
505
+ remainingDisplay: string;
506
506
  onchain: {
507
507
  amount: string;
508
508
  spent: string;
@@ -525,13 +525,7 @@ interface HavenAllowance {
525
525
  }
526
526
  interface HavenAllowanceSummary {
527
527
  agentId: string;
528
- /** #2908 — the account-vocabulary name; same value as `safeAddress`. */
529
528
  accountAddress: string;
530
- /**
531
- * @deprecated #2908 — same value as {@link HavenAllowanceSummary.accountAddress}.
532
- * Removed in the release after the one carrying #2908 (#2914).
533
- */
534
- safeAddress: string;
535
529
  delegateAddress: string;
536
530
  chainId: number;
537
531
  allowances: HavenAllowance[];
@@ -564,6 +558,63 @@ interface PostPurchaseAllowanceSummary {
564
558
  reset_period?: number;
565
559
  source: 'allowance_module' | 'active_delegations';
566
560
  }
561
+ /**
562
+ * #3126 — the answer to "is there money actually HELD behind my budget?",
563
+ * asked as a sufficiency signal rather than a balance.
564
+ *
565
+ * Every other agent-readable figure in this package describes SPEND
566
+ * AUTHORITY — what the agent is PERMITTED to move this period
567
+ * ({@link HavenAllowanceSummary}). This shape answers the different question
568
+ * of whether the account HOLDS funds behind that authority, and deliberately
569
+ * answers it as `covered: boolean | null`, never as a figure: a constrained
570
+ * actor has no business reading the treasury total, and the boolean answers
571
+ * the only decision an agent has (attempt the payment, or tell the user
572
+ * funds are missing).
573
+ *
574
+ * The naming keeps the two concepts apart (the #3126 binding constraint):
575
+ * `budgetRemainingAtomic` is AUTHORITY — the same value
576
+ * {@link HavenAllowanceSummary} reports per token as `onchain.remaining` —
577
+ * while `covered` speaks only of HELD funds. Nothing here is named like the
578
+ * authority fields (`remaining`, `available`); nothing here returns a
579
+ * balance.
580
+ *
581
+ * `covered: null` means the chain read FAILED — unverifiable, never a
582
+ * guess. The same honesty rule `x402-funding-leg.ts`'s `delegateCanFund`
583
+ * established (#1521): treat null as "we do not know", not as "funded" or
584
+ * as absence; `coverageError` carries why.
585
+ */
586
+ interface HavenBalanceCoverage {
587
+ /**
588
+ * true: the chain reports the agent's account holds at least
589
+ * `checkedAmountAtomic` of the token. false: the chain read succeeded and
590
+ * reports LESS — tell the user funds are missing rather than retrying.
591
+ * null: the chain read failed — unverifiable, never treated as absence.
592
+ */
593
+ covered: boolean | null;
594
+ /** Present only when `covered` is null: why the chain read could not answer. */
595
+ coverageError?: string;
596
+ chainId: number;
597
+ tokenAddress: string;
598
+ tokenSymbol: string;
599
+ /** The amount the coverage question was asked about, in atomic units. */
600
+ checkedAmountAtomic: string;
601
+ /**
602
+ * Context, AUTHORITY not holdings: the agent's remaining spend authority
603
+ * for the requested token, in atomic units — the same derivation
604
+ * {@link HavenAllowanceSummary} reports (`onchain.remaining`; the #1090
605
+ * derivation, the #1145 enforcer read). Zero when no active budget row
606
+ * names the token. Compare it with `covered`, never instead of it.
607
+ */
608
+ budgetRemainingAtomic: string;
609
+ /**
610
+ * Provenance of `budgetRemainingAtomic` (#1319, same semantics as
611
+ * {@link HavenAllowance.onchain.remainingIsFromChain}): true when the
612
+ * budget figure came from a live enforcer read, false when it fell back
613
+ * to the configured budget. Absent when no budget row existed for the
614
+ * token (nothing was read).
615
+ */
616
+ budgetRemainingIsFromChain?: boolean;
617
+ }
567
618
  /**
568
619
  * Affirmative spend-readiness for the authenticated agent, derived from the raw
569
620
  * agent status plus the remaining spend authority the backend reports per rail
@@ -588,9 +639,24 @@ interface PostPurchaseAllowanceSummary {
588
639
  * funding surfaces at pay time as INSUFFICIENT_FUNDS.
589
640
  */
590
641
  type HavenAgentReadiness = 'ready' | 'needs_approval' | 'revoked';
591
- /** Compact, agent-facing per-token spend authority for the bootstrap summary. */
642
+ /**
643
+ * Compact, agent-facing per-token spend authority for the bootstrap summary.
644
+ *
645
+ * #3128: a deliberately DIFFERENT view of the same allowance as
646
+ * {@link HavenAllowance} — flat, no `onchain` block, no spent/nonce/reset-time
647
+ * detail — but never a disjoint one: every field here is present on or
648
+ * derived from the {@link HavenAllowance} with the same `id`, and
649
+ * `remainingAtomic` / `remainingDisplay` equal that allowance's
650
+ * `onchain.remaining` / `remainingDisplay` byte for byte (pinned by test). A
651
+ * client that wants the id AND a display amount can therefore use either
652
+ * read alone.
653
+ */
592
654
  interface HavenAgentAllowanceSummary {
655
+ /** #3128: the {@link HavenAllowance.id} this row summarises. */
656
+ id: string;
593
657
  tokenSymbol: string;
658
+ /** #3128: the {@link HavenAllowance.tokenAddress}. */
659
+ tokenAddress: string;
594
660
  /** Live on-chain remaining allowance in atomic units. */
595
661
  remainingAtomic: string;
596
662
  /** Human-readable remaining, e.g. "4.96 USDC". */
@@ -683,6 +749,25 @@ interface HavenPaymentReceipt {
683
749
  selectedPayment?: Record<string, unknown> | null;
684
750
  paymentProofHeaderName: string | null;
685
751
  protocolReceiptHeaderName: string | null;
752
+ /**
753
+ * #3125 — the merchant's `PAYMENT-RESPONSE` object relayed VERBATIM:
754
+ * opaque, unvalidated, unverified, MERCHANT-CONTROLLED third-party data.
755
+ * Haven neither authors nor verifies anything inside it, including
756
+ * `protocolReceiptPayload.payer` —
757
+ * that `payer` is the merchant's claim, NOT Haven's record, and is not
758
+ * {@link payerAddress} (Haven's own, authoritative; field observation
759
+ * 2026-09-18: the two held different addresses on every row read). For who
760
+ * paid, read `parties` ({@link PaymentParties}) — `treasuryAccount`,
761
+ * `delegate`, `delegateAccount`, `merchant` are Haven-derived and
762
+ * authoritative; anything inside this object is not.
763
+ *
764
+ * Deliberately NOT namespaced or key-prefixed on the wire (#3125): the
765
+ * relay must stay the merchant's object verbatim (its `transaction` key
766
+ * feeds `settlementTxHash`), and prefixing the envelope could not prefix
767
+ * the merchant-controlled keys inside it — the `payer` collision lives
768
+ * there, so provenance is made legible at the read surfaces instead (this
769
+ * comment and the tool descriptions).
770
+ */
686
771
  protocolReceiptPayload?: Record<string, unknown> | null;
687
772
  merchantStatus: number | null;
688
773
  confirmedAt: string | null;
@@ -851,12 +936,12 @@ declare const AgentPaymentNextAction: {
851
936
  * the agent's per-token allowance needs to be raised before the payment
852
937
  * can succeed. A user approval will not fix this state on its own.
853
938
  *
854
- * #2908: the wire twin `fund_account_or_raise_allowance`
855
- * ({@link AgentPaymentNextActionAccountAlias}) means the same thing; the
856
- * server keeps emitting THIS value until #2914. Compare via
857
- * {@link canonicalAgentPaymentNextAction}.
939
+ * #2914: the account-vocabulary spelling, and the only one — the
940
+ * pre-#2907 `fund_safe_or_raise_allowance` wire value (and the
941
+ * `AgentPaymentNextActionAccountAlias` seam #2908 added to bridge it) are
942
+ * retired along with the rest of the #2908 compatibility window.
858
943
  */
859
- readonly FundSafeOrRaiseAllowance: "fund_safe_or_raise_allowance";
944
+ readonly FundAccountOrRaiseAllowance: "fund_account_or_raise_allowance";
860
945
  /**
861
946
  * The delegate wallet may hold funds that were sent from the Safe but never
862
947
  * settled to the merchant. The wallet owner should initiate a sweep to
@@ -884,39 +969,6 @@ declare const AgentPaymentNextAction: {
884
969
  readonly AwaitingSettlementEvidence: "awaiting_settlement_evidence";
885
970
  };
886
971
  type AgentPaymentNextAction = (typeof AgentPaymentNextAction)[keyof typeof AgentPaymentNextAction];
887
- /**
888
- * #2908 (naming epic #2906): the account-vocabulary twin of
889
- * {@link AgentPaymentNextAction.FundSafeOrRaiseAllowance}. The server ACCEPTS
890
- * and DOCUMENTS this value from #2907 but keeps EMITTING the old one through
891
- * the compatibility window; the emitted value flips at #2914.
892
- *
893
- * Deliberately declared beside `AgentPaymentNextAction` rather than inside
894
- * it: the backend keeps a hand-mirror of that const, parity-pinned key-for-key
895
- * and value-for-value (`agent-payment-taxonomy.parity.test.ts`), and the
896
- * served `x-enumDescriptions` are the SDK's strings verbatim. Both consts
897
- * move together at #2914; until then this alias is how a client handles both
898
- * wire values without forking the taxonomy.
899
- */
900
- declare const AgentPaymentNextActionAccountAlias: {
901
- /** Account-vocabulary twin of `fund_safe_or_raise_allowance`; same meaning. */
902
- readonly FundAccountOrRaiseAllowance: "fund_account_or_raise_allowance";
903
- };
904
- type AgentPaymentNextActionAccountAlias = (typeof AgentPaymentNextActionAccountAlias)[keyof typeof AgentPaymentNextActionAccountAlias];
905
- /** Every `next_action` value a server may put on the wire during the #2908 window. */
906
- type AgentPaymentNextActionWire = AgentPaymentNextAction | AgentPaymentNextActionAccountAlias;
907
- /**
908
- * Collapse the #2908 account-vocabulary alias onto its canonical taxonomy
909
- * value, and pass every other value through untouched.
910
- *
911
- * This is the one seam a `switch` over `AgentPaymentNextAction` needs: a
912
- * case on `FundSafeOrRaiseAllowance` matches a server that emits either
913
- * spelling, and no case falls through because the alias arrived. Unknown
914
- * strings are returned as-is (the SDK never invents a value), so the return
915
- * type is exactly the input type widened by the canonical value.
916
- */
917
- declare function canonicalAgentPaymentNextAction<T extends string | null | undefined>(value: T): Exclude<T, AgentPaymentNextActionAccountAlias> | typeof AgentPaymentNextAction.FundSafeOrRaiseAllowance;
918
- /** True for EITHER spelling of the fund-or-raise-allowance next action (#2908). */
919
- declare function isFundAccountOrRaiseAllowance(value: string | null | undefined): boolean;
920
972
  declare const AgentPaymentFailureCode: {
921
973
  /** A merchant-authoritative x402 price exceeds the caller's pre-funding max_amount cap. */
922
974
  readonly PriceExceedsMax: "PRICE_EXCEEDS_MAX";
@@ -1008,7 +1060,7 @@ type AgentPaymentRail = (typeof AgentPaymentRail)[keyof typeof AgentPaymentRail]
1008
1060
  type PaymentPhase = AgentPaymentPhase;
1009
1061
  type PaymentNextAction = AgentPaymentNextAction;
1010
1062
  declare const AGENT_PAYMENT_PHASE_VALUES: ("rejected" | "expired" | "failed" | "agent_signature_required" | "payment_submitted" | "payment_confirmed" | "user_approval_required" | "user_execution_required" | "waiting_for_additional_approvals" | "funding_sent" | "insufficient_funds" | "funded_but_unsettled")[];
1011
- declare const AGENT_PAYMENT_NEXT_ACTION_VALUES: ("sign_and_submit_payment" | "check_status_later" | "none" | "wait_for_user_approval" | "wait_for_user_to_complete_payment" | "retry_original_x402_request" | "stop_and_tell_user" | "request_again_if_user_still_wants_it" | "retry_with_explicit_context" | "payment_window_expired" | "fund_safe_or_raise_allowance" | "sweep_stranded_funds" | "awaiting_settlement_evidence")[];
1063
+ declare const AGENT_PAYMENT_NEXT_ACTION_VALUES: ("sign_and_submit_payment" | "check_status_later" | "none" | "wait_for_user_approval" | "wait_for_user_to_complete_payment" | "retry_original_x402_request" | "stop_and_tell_user" | "request_again_if_user_still_wants_it" | "retry_with_explicit_context" | "payment_window_expired" | "fund_account_or_raise_allowance" | "sweep_stranded_funds" | "awaiting_settlement_evidence")[];
1012
1064
  declare const AGENT_PAYMENT_FAILURE_CODE_VALUES: ("PRICE_EXCEEDS_MAX" | "PAYMENT_WINDOW_EXPIRED" | "MERCHANT_REJECTED_AFTER_FUNDING" | "MERCHANT_UNRESPONSIVE_AFTER_FUNDING" | "MERCHANT_CALL_CONTEXT_UNAVAILABLE" | "AMBIGUOUS_MAX_AMOUNT" | "MAX_AMOUNT_UNCONVERTIBLE" | "MERCHANT_NOT_READY")[];
1013
1065
  declare const AGENT_PAYMENT_RAIL_VALUES: ("x402" | "mpp_demo" | "mpp_crypto" | "stripe_deposit" | "spt" | "direct" | "mpp")[];
1014
1066
  declare const AgentPaymentPhaseDescriptions: Record<AgentPaymentPhase, string>;
@@ -1082,15 +1134,8 @@ interface AgentPaymentWarning {
1082
1134
  * (payment_required) are named in `reason` and taken from the SAME response.
1083
1135
  */
1084
1136
  interface AgentNextStep {
1085
- /**
1086
- * From `AgentPaymentNextAction`, widened by the #2908 account-vocabulary
1087
- * alias for the compatibility window: the hosted server keeps emitting
1088
- * `fund_safe_or_raise_allowance` until #2914, but a client compiled against
1089
- * this type must not reject `fund_account_or_raise_allowance` when the flip
1090
- * lands. Compare through {@link canonicalAgentPaymentNextAction} or
1091
- * {@link isFundAccountOrRaiseAllowance}, never by one literal.
1092
- */
1093
- next_action: AgentPaymentNextActionWire;
1137
+ /** From `AgentPaymentNextAction`. */
1138
+ next_action: AgentPaymentNextAction;
1094
1139
  /**
1095
1140
  * Claude-family namespaced tool name for the next call
1096
1141
  * (`mcp__<server>__<tool>`), when one exists.
@@ -1121,6 +1166,12 @@ interface AgentNextStep {
1121
1166
  next_tool_server_role?: 'hosted' | 'signer';
1122
1167
  /** Small literal arguments for next_tool. Bulky fields are referenced by reason. */
1123
1168
  next_arguments?: Record<string, unknown>;
1169
+ /**
1170
+ * #3101 (epic #3105, decision 3): present exactly when `next_tool` is
1171
+ * absent — why no tool is named (the payment id is unknown, nothing is left
1172
+ * to do, the arguments could not be built). `next_tool` is never null.
1173
+ */
1174
+ next_tool_omitted_reason?: string;
1124
1175
  /** False when the agent should stop and involve the user before continuing. */
1125
1176
  safe_to_continue: boolean;
1126
1177
  reason: string;
@@ -1283,6 +1334,37 @@ interface HavenCatalogEntry {
1283
1334
  * 'verified' })` filters on this field, not on `source`.
1284
1335
  */
1285
1336
  verifiedPayable: boolean;
1337
+ /**
1338
+ * The merchant this entry belongs to (#3078). OPTIONAL on purpose: an
1339
+ * installed SDK may face a backend that predates the merchant layer, and
1340
+ * `discoverTools` must keep working against it — the field is absent, not
1341
+ * null, in that case.
1342
+ */
1343
+ merchant?: HavenCatalogMerchant;
1344
+ }
1345
+ /** A catalog entry's merchant as the wire carries it (#3078). */
1346
+ interface HavenCatalogMerchant {
1347
+ id: string;
1348
+ slug: string;
1349
+ name: string;
1350
+ /** `coming_soon` never reaches an entry in practice (a prospect has no offers). */
1351
+ listingStatus: 'live' | 'coming_soon';
1352
+ /** Haven-run test content: the demo store and the stranded-funds fixture. */
1353
+ isTestMerchant: boolean;
1354
+ }
1355
+ /**
1356
+ * #3128: one page of receipts. `total` is the count Haven holds for the
1357
+ * agent (an empty page with `total: 0` means no receipt exists — there is no
1358
+ * indexing delay behind this list); `hasMore` says the page was cut at the
1359
+ * limit; `nextCursor` is fed back as `cursor` for the next page. Against a
1360
+ * backend older than #3128 the three are `null` — "unknown", never a
1361
+ * fabricated 0 / false.
1362
+ */
1363
+ interface HavenPaymentReceiptsPage {
1364
+ receipts: HavenPaymentReceipt[];
1365
+ total: number | null;
1366
+ hasMore: boolean | null;
1367
+ nextCursor: string | null;
1286
1368
  }
1287
1369
  /** @internal */
1288
1370
  /** Wire shape of POST /catalog/submit (#1717, #1716). */
@@ -1481,18 +1563,13 @@ interface PaymentReceipt {
1481
1563
  amount: string;
1482
1564
  amountSek: string | null;
1483
1565
  recipient: string;
1484
- /** @deprecated since #2907 — read `account`; removed in #2914 (the release after the naming window). Same value as `account`. */
1485
- safe: string;
1566
+ /** The payer's smart-account address. */
1567
+ account: string;
1486
1568
  /**
1487
- * The payer's smart-account address (#2907 twin of `safe`). Optional for
1488
- * the window: a server from before the twin emits `safe` only.
1489
- */
1490
- account?: string;
1491
- /**
1492
- * #2960: one party vocabulary for "who paid", additive alongside `safe`/
1493
- * `account` above (which are `parties.treasury_account` only). Optional
1494
- * for the window: a server from before #2960 emits neither. Ignored by
1495
- * `verifyPaymentReceipt`, which reads only `authorization`.
1569
+ * #2960: one party vocabulary for "who paid", additive alongside `account`
1570
+ * above (which is `parties.treasury_account` only). Optional: a server
1571
+ * from before #2960 emits neither. Ignored by `verifyPaymentReceipt`,
1572
+ * which reads only `authorization`.
1496
1573
  */
1497
1574
  parties?: RawPaymentParties;
1498
1575
  chainId: number;
@@ -1931,6 +2008,52 @@ declare class HavenClient {
1931
2008
  * Get configured and on-chain allowances for the authenticated agent.
1932
2009
  */
1933
2010
  getAllowances(): Promise<HavenAllowanceSummary>;
2011
+ /**
2012
+ * #3126 — is the checked amount of the token actually HELD on the
2013
+ * agent's own account?
2014
+ *
2015
+ * This is the companion to {@link getAllowances}, not a variant of it:
2016
+ * allowances answer what the agent is PERMITTED to spend this period;
2017
+ * this answers whether the account HOLDS funds behind that permission,
2018
+ * as a sufficiency signal — `covered: true | false | null` — never as a
2019
+ * balance. `covered: null` means the chain read failed: treat it as
2020
+ * unverifiable, not as absence (`coverageError` says why). The account's
2021
+ * balance itself is deliberately not returned.
2022
+ */
2023
+ checkFunds(input: {
2024
+ token: string;
2025
+ amountAtomic: string;
2026
+ }): Promise<HavenBalanceCoverage>;
2027
+ /**
2028
+ * `POST /machine-payments/budget-precheck` (#3054): ask Haven to decide —
2029
+ * server-side — whether `amountAtomic` of `token` fits the agent's
2030
+ * remaining delegation budget, the same compare the guided prepare used to
2031
+ * run locally over its allowances read.
2032
+ *
2033
+ * On insufficiency Haven refuses (403, `delegation_budget_exceeded`) and
2034
+ * the refusal reaches the `payment_refusals` ledger with
2035
+ * `source: 'hosted_prepare'` — the point of the endpoint. This method
2036
+ * surfaces that decision as a thrown {@link HavenApiError}; it does NOT
2037
+ * swallow it, because swallowing would turn a decided refusal into the
2038
+ * degrade-to-warning path and the ledger row would still land while the
2039
+ * purchase proceeded.
2040
+ *
2041
+ * camelCase body like the route family; the response mirrors the wire
2042
+ * (`sufficient`, `remaining_atomic`). `resourceUrl` is the merchant
2043
+ * resource being bought — the ledger dedupe window's discriminating
2044
+ * column — never this request's own URL.
2045
+ */
2046
+ precheckBudget(input: {
2047
+ chainId?: number;
2048
+ token: string;
2049
+ amountAtomic: string;
2050
+ merchantTo?: string;
2051
+ resourceUrl?: string;
2052
+ }): Promise<{
2053
+ sufficient: boolean;
2054
+ remaining_atomic: string;
2055
+ remaining_is_from_chain?: boolean;
2056
+ }>;
1934
2057
  /**
1935
2058
  * Post-purchase allowance/budget summary for a settled payment (#1310).
1936
2059
  *
@@ -2057,6 +2180,11 @@ declare class HavenClient {
2057
2180
  listReceipts(options?: {
2058
2181
  limit?: number;
2059
2182
  }): Promise<HavenPaymentReceipt[]>;
2183
+ /** #3128: one page of receipts with `total`, `hasMore` and `nextCursor`. */
2184
+ listReceiptsPage(options?: {
2185
+ limit?: number;
2186
+ cursor?: string;
2187
+ }): Promise<HavenPaymentReceiptsPage>;
2060
2188
  /**
2061
2189
  * Fetch the verifiable receipt bundle for a settled payment and verify it
2062
2190
  * locally. The server's own verification is ignored — the receipt is verified
@@ -2485,21 +2613,27 @@ declare const toolDescriptions: {
2485
2613
  readonly nextActionGuidance: "";
2486
2614
  };
2487
2615
  readonly getAgent: {
2488
- readonly summary: "Return the authenticated agent identity AND its live spend authority in one call: Haven wallet, delegate, chain, raw status, spend_authority_readiness, and per-token remaining allowance (atomic + human-readable). The recommended first call in a new session to confirm who you are and whether Haven will let you spend right now.";
2489
- readonly 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.";
2490
- readonly behavior: "Reads identity plus the live spend-authority snapshot in one shot — the agent's active on-chain budget delegation. spend_authority_readiness (readiness is a deprecated alias, same value) is \"ready\" when at least one token has remaining spend authority, \"needs_approval\" when the agent is active but has none, and \"revoked\" when the credential is not active. It covers hosted identity + on-chain spend authority ONLY — the hosted server cannot see the LOCAL signer, so \"ready\" does not mean the signer can start; verify the signer with a signer tool call or connect --doctor. An over-budget payment is declined before any money moves: there is no approval queue, so ask the owner to grant or raise the budget in Haven rather than waiting for an approval. allowances[] carries remainingAtomic and remainingDisplay per token. Identity fields: id, name, status, accountAddress (safeAddress: deprecated alias, same value), delegateAddress, chainId.";
2616
+ readonly summary: "Return the authenticated agent identity AND its live spend authority in one call: Haven wallet, delegate, chain, raw status, spend_authority_readiness, per-token remaining allowance (atomic + human-readable). The recommended first call in a new session.";
2617
+ readonly selectionGuidance: "Use this as the session bootstrap, or to confirm identity together with whether the agent can spend right now. For per-token detail (configured vs spent vs reset window) use haven_get_allowances.";
2618
+ readonly behavior: "Reads identity plus the live spend-authority snapshot — the active on-chain budget delegation. spend_authority_readiness (readiness is a deprecated alias, same value) is \"ready\" when at least one token has remaining spend authority, \"needs_approval\" when the agent is active but has none, and \"revoked\" when the credential is not active. It covers hosted identity + on-chain spend authority ONLY — the hosted server cannot see the LOCAL signer, so \"ready\" does not mean the signer can start; verify the signer with a signer tool call or connect --doctor. An over-budget payment is declined before any money moves; there is no approval queue — ask the owner to grant or raise the budget in Haven. allowances[] carries id, tokenAddress, remainingAtomic, remainingDisplay per token. Identity fields: id, name, status, accountAddress, delegateAddress, chainId.";
2491
2619
  readonly nextActionGuidance: "";
2492
2620
  };
2493
2621
  readonly getAllowances: {
2494
2622
  readonly summary: "Return configured and on-chain allowance state for the authenticated agent. On-chain allowance is the real spend gate.";
2495
- readonly selectionGuidance: "Use this when the user asks about allowance, budget, spend limit, remaining amount, remaining allowance, remaining budget, daily limit, reset period, what can I spend, or what the agent can still spend.";
2496
- readonly behavior: "Returns the per-token spend authority for the account: the active budget delegation (remaining = the period budget, which re-arms natively at the period boundary). An over-budget payment is declined before any money moves; nothing queues. Configured amounts from Haven are returned alongside.";
2623
+ readonly selectionGuidance: "Use this when the user asks about allowance, budget, spend limit, remaining amount, remaining allowance, remaining budget, daily limit, reset period, what can I spend, or what the agent can still spend. For whether the account actually HOLDS funds behind the budget use haven_check_funds.";
2624
+ readonly behavior: "Returns the per-token spend authority for the account: the active budget delegation (remaining = the period budget, which re-arms natively at the period boundary), each with id, onchain.remaining, remainingDisplay. An over-budget payment is declined before any money moves; nothing queues. Configured amounts from Haven are returned alongside.";
2497
2625
  readonly nextActionGuidance: "";
2498
2626
  };
2627
+ readonly checkFunds: {
2628
+ readonly summary: "Check whether the agent's account actually holds at least the given amount of a token — funds held, not spend permitted.";
2629
+ readonly selectionGuidance: "Use this before attempting a payment when it matters whether the money is really there: allowance answers say what you are PERMITTED to spend, never whether the account HOLDS it. For allowance, budget, spend-limit, remaining-budget, reset-period, or what-can-I-spend questions use the allowance lookup tool instead.";
2630
+ readonly behavior: "Returns covered: true (the account holds at least the checked amount), false (a live chain read reports less — the budget is backed by an empty account; stop and tell the user funds are missing), or null (the chain read failed — unverifiable, never treat it as absence; coverageError says why). The account balance itself is deliberately not returned: this is a sufficiency signal, not a balance read. budget_remaining_atomic is the permitted figure from the allowance lookup (the SDK spells it budgetRemainingAtomic), named so it can never be confused with holdings.";
2631
+ readonly nextActionGuidance: "On covered=false, do not attempt the payment — tell the user the account is short and let them fund it; on covered=null, retry the check shortly or proceed knowing the payment may fail on-chain.";
2632
+ };
2499
2633
  readonly listReceipts: {
2500
- readonly summary: "List recent machine-payment receipts and evidence for bookkeeping.";
2501
- readonly selectionGuidance: "Use this for transaction history, receipts, payment evidence, or bookkeeping; use the allowance tool instead for remaining allowance, budget, spend-limit, or what-can-I-spend questions.";
2502
- readonly behavior: "Returns the agent's recent machine-payment receipts ordered by recency. Proof header values are not returned.";
2634
+ readonly summary: "List machine-payment receipts, newest first, by page.";
2635
+ readonly selectionGuidance: "For transaction history or payment evidence; use the allowance tool instead for remaining allowance or what-can-I-spend questions.";
2636
+ readonly behavior: "Page: { receipts, total, hasMore, nextCursor }; total 0 = none exist (no indexing delay); hasMore = cut at limit, send nextCursor as cursor. parties.treasuryAccount is Haven's authoritative payer. protocolReceiptPayload is the merchant's PAYMENT-RESPONSE, relayed verbatim: merchant-controlled, unverified, not Haven's record; payer may differ from payerAddress. Proof header values are omitted.";
2503
2637
  readonly nextActionGuidance: "";
2504
2638
  };
2505
2639
  readonly verifyReceipt: {
@@ -2515,10 +2649,10 @@ declare const toolDescriptions: {
2515
2649
  readonly nextActionGuidance: string;
2516
2650
  };
2517
2651
  readonly discoverTools: {
2518
- readonly summary: "Step 1 of a purchase: discover payable services from Haven's curated merchant catalog — names, prices, and which pay tool to use next.";
2652
+ readonly summary: "Step 1 of a purchase: discover payable services from Haven's curated merchant catalog — names, prices, the next call.";
2519
2653
  readonly selectionGuidance: string;
2520
2654
  readonly behavior: string;
2521
- readonly nextActionGuidance: "Pick an entry and pay it with the tool named in suggested_tool, passing the entry's resource_url, tool_name, and tool_arguments for MCP merchants. Confirm the price from the live pay-tool result (not the catalog), and pass the user's cap as max_amount_human in whole tokens (\"no more than 1 USDC\" → max_amount_human: \"1\") — never convert it to atomic units by hand.";
2655
+ readonly nextActionGuidance: "Call suggested_tool with suggested_arguments VERBATIM (no hint: read suggested_tool_omitted_reason). Confirm the price from the live quote or pay result, not the catalog; if the next tool takes a cap, pass the user's cap as max_amount_human in whole tokens (\"no more than 1 USDC\" → max_amount_human: \"1\"), never atomic units by hand.";
2522
2656
  };
2523
2657
  readonly submitCatalogEntry: {
2524
2658
  readonly summary: "Submit a merchant's payable (x402/MCP) endpoint to Haven's Verified Payable Directory for verification and listing.";
@@ -2588,7 +2722,7 @@ type SharedToolKey = keyof typeof toolDescriptions;
2588
2722
  * live sibling constant not pulled in here; if it ever is, this applies to it
2589
2723
  * too (design review, #2537).
2590
2724
  */
2591
- declare const HAVEN_SKILL_MD = "---\nname: haven-pay\ndescription: Pay for things from the user's Haven wallet within their agent rules, and set Haven up when it is not yet connected. Use when the user asks to send, pay, tip, or transfer crypto; when a request hits an HTTP 402 (x402) paywall; or when they ask to create a Haven account, create an agent, or connect one.\n---\n\n# Haven: pay from a Haven wallet\n\nThis skill lets the agent make payments from the user's Haven wallet through\nthe Haven MCP tools. Every payment is checked against the agent's on-chain\nbudget before money moves; a payment above the remaining budget is declined \u2014\nnothing is paid past the rules the user set.\n\nHosted tools run in the `mcp__haven__` namespace. Local signing tools run in\nthe `mcp__haven-signer__` namespace and keep the delegate key on this machine.\nThat namespacing is Claude-family; other runtimes name the servers by their\nown config keys (Codex: `haven`, `haven_signer`). Tool results carry the\nexact next step (`next_action`, `next_tool`, `next_arguments`, plus the\nruntime-neutral `next_tool_server` + `next_tool_name` \u2014 the bare tool name\non that logical server, whatever your runtime calls it).\nFollow those fields first; the prose below is fallback and orientation, not\nthe source of truth.\n\n## When to use this skill\n\n- The user asks to send money, pay someone, tip, donate, or transfer tokens.\n- A request returns HTTP 402 (x402): use the Haven pay tools to settle it,\n then retry the original request.\n\n## Onboarding and setup\n\nYou are in this mode when there is no Haven agent credential on this machine,\nor when your user asks you to create a Haven account, create an agent, or\nconnect one \u2014 for themselves or for someone else.\n\n**None of the tools below creates authority.** They spend a budget a human\nalready signed. There is no tool here that opens an account, mints a\ncredential, or approves a budget, so reaching for one of them to \"set Haven\nup\" cannot work; the steps are the ones in this section instead.\n\nStart by reading `/for-agents.md` on the Haven host \u2014 the origin of the\n`api_url` in your `agent.json` if you have one, otherwise the host your user\nnames. It is the full runbook: six steps, which four are your user's, and what\nto say at each hand-off.\n\nTwo of those steps you can do yourself, from the shell with `@haven_ai/cli`\n(installs the `haven` command):\n\n- `haven login` \u2014 a device-code browser flow. It prints a code and a link\n for your user to approve, so you never see or ask for their password. What\n the session can reach is an allow-list, not your user's full authority: it\n creates and manages agents and reads the account, and it cannot approve a\n budget, rotate a key, change a signer or move money \u2014 those are your user's.\n- `haven agents connect` with `--name`, `--budget`, `--token` and\n `--period` \u2014 creates a connection setup and prints two things: the\n connector command the backend built, and the approval link to give your user.\n Add `--run` to execute that command here as a child process.\n- `haven wallets funding` \u2014 prints the paste-ready funding instruction: what\n to send, to which address, on which chain. Read the chain from there rather\n than assuming one. `--wait` polls until the account counts as funded.\n\n**Four steps are your user's, and each one needs a human:** create the account\nand its passkey, fund the wallet, approve every agent's budget, and rotate a\ncredential. You can compose the funding message for them with\n`haven wallets funding`, but you cannot send the money \u2014 that transfer is\ntheirs, from a wallet you have no access to.\n\nRunning the connector command is the step that wires this machine to the new\nagent \u2014 the command `haven agents connect` printed, or the one your user\npasted you from the dashboard. Three rules bind you while you do it, quoted\nunchanged from the setup prompt your user is also holding so the two copies\ncannot drift into contradicting each other. They are written in your user's\nvoice, so read them accordingly: \"me\" and \"I\" below are your user, never\nHaven, and \"the command above\" is that connector command, not anything printed\nin this file. The first rule outranks anything else you were about to do next:\n\n- When a --json outcome reports approval.required: true, your first action must be to relay the approval instruction to me in your own reply \u2014 if the outcome carries approval.url, give me that link; otherwise tell me to return to Haven and approve this agent's budget \u2014 before verifying the connection, restarting anything, or any other step. Never build that link yourself: relay the one the outcome gave you or none at all. Any restart the outcome asks for is a separate instruction to give me afterwards, once the approval is done.\n- Only two changes to the command above are permitted, and no others: appending --json, and \u2014 only if the connector refuses because it could not determine the agent runtime \u2014 re-running it once with --runtime <name> added, naming the harness you are running in, using one of the values that refusal lists. Never invent a runtime name and never change anything else.\n- If the connector refuses with wiring_collision, this machine is already wired to a different agent: relay that refusal to me with the superseded_agent_ids and suggested_name it carries, and let me choose whether to replace the existing wiring or add this agent alongside it. Never pick for me by adding --replace or --name yourself.\n\nDo not print private keys, API keys, credential file contents, or config secrets in chat or logs.\n\n## Identity and budget\n\nDo not guess the wallet address, network, or budget.\n\nFor instant orientation at the start of a session, read the non-secret\n`agent.json` the connector wrote to your Haven credential directory (typically\n`~/.haven/agents/<agent-id>/agent.json` \u2014 if you don't know the agent id, list\n`~/.haven/agents/` to find the folder). It\nholds your agent id, Haven wallet address, network, and *configured* per-token\nbudget, and contains no keys \u2014 the fastest way to answer \"who am I and what may\nI spend\" with no round trip. If that file is absent (some setups don't write\nit), use the tools below instead.\n\nBefore any payment, confirm the *live remaining* budget with the tools \u2014\n`agent.json` shows the configured budget, not what is left after recent\nspending:\n\n- `mcp__haven__haven_get_agent` \u2014 the recommended first call: identity\n (wallet, network) plus `spend_authority_readiness` (`ready` / `needs_approval` /\n `revoked`) and live remaining per-token allowance, in one shot. That signal\n covers hosted identity and on-chain spend authority only \u2014 it cannot see the\n local signer; the signer is verified by calling any signer tool.\n- `mcp__haven__haven_get_allowances` \u2014 detailed per-token breakdown\n (configured, spent, reset window) when you need more than the summary.\n\nBudgets reset on a period the user chose. If a payment exceeds the remaining\nbudget it is declined before any money moves \u2014 tell the user; they can raise\nthe budget in the Haven dashboard, or wait for the period reset.\n\n## Paying\n\n**Catalog purchases \u2014 the primary path for MCP merchants:**\n\n1. `mcp__haven__haven_discover_tools` to find a payable service and its\n `catalog_id`.\n2. If the user needs the live price before authorizing a cap, call\n `mcp__haven__haven_quote_catalog_purchase` with `catalog_id`. It is\n read-only and informational only: it never reserves a price or creates a\n payment. Tell the user its `amount` / `amount_atomic`, then choose a cap.\n3. `mcp__haven__haven_prepare_catalog_purchase` with `catalog_id` and a\n spending cap. A cap is REQUIRED on this tool and is best practice on every\n paid call below too \u2014 it caps what the LIVE merchant quote may charge,\n checked before any funding intent is created. Write it the way the user\n said it: `max_amount_human` is whole tokens, so \"no more than 1 USDC\" is\n `max_amount_human: \"1\"`. (`max_amount` is the atomic-unit form, where\n \"1\" means 0.000001 USDC \u2014 do not convert by hand, and never send both.)\n4. Then FOLLOW THE RESPONSE'S GUIDANCE FIELDS: `next_action`, `next_tool`,\n and `next_arguments` name the exact next call \u2014 act on those first; the\n prose in this section is fallback and debugging detail. If the catalog\n entry is missing or degraded, the response instead names\n `mcp__haven__haven_pay_mcp_tool` (merchant URL, tool name, arguments) as\n the manual fallback.\n\n**Signing:** `mcp__haven-signer__haven_sign_x402` with `payment_id` ONLY \u2014\nthe local signer fetches the exact signing bytes AND `payment_required`\nitself, so never relay `typed_data` or the 402 blob yourself. If the signer\nreports its fetched context carried no `payment_required` (older backend),\nre-call with `payment_required` added verbatim. Fallback for an older signer\nor backend: re-run the quote/prepare tool with the SAME `idempotency_key`\nplus `include_signing_payload=true`, then pass `payload_hash`,\n`x402_expected` (the nested `x402.expected` object), and\n`typed_data`/`typed_data_b64` through unchanged.\n\n**Settle:** `mcp__haven__haven_settle_mcp_tool` with `payment_id`,\n`signature`, and `payment_header` ONLY \u2014 Haven rehydrates the merchant call\ncontext (`merchant_url`, `tool_name`, `arguments`, `mcp_transport`)\nserver-side from `payment_id`. Pass those four fields explicitly only as a\nversion-skew fallback when Haven has no stored context for the id \u2014 both or\nnone together, never just one. If the settle result carries `settled: false`,\nfunding has not confirmed \u2014 follow the result's guidance fields and check\nstatus later, do not re-pay.\n\nStep-by-step alternative (also key-safe; for an older signer or backend, or\nwhen you already have a merchant URL and tool name instead of a\n`catalog_id`): if the user needs the live price before choosing a cap, first\ncall `mcp__haven__haven_quote_mcp_tool` with that merchant URL, tool name,\nand arguments. It is informational only; then call\n`mcp__haven__haven_pay_mcp_tool` with the same inputs and the explicit cap.\nThe paid call always obtains a fresh quote before it creates any intent. Then\ncontinue `mcp__haven__haven_pay_mcp_tool` \u2192\n`mcp__haven-signer__haven_sign` \u2192 `mcp__haven__haven_submit` \u2192\n`mcp__haven-signer__haven_x402_sign_header` \u2192\n`mcp__haven__haven_complete_mcp_tool`. Call that last step with\n`payment_id` and the signer's `payment_header` ONLY. It does not take\n`payment_required`: Haven rehydrates the merchant call context\n(`merchant_url`, `tool_name`, `arguments`, `mcp_transport`) and the\n402 server-side from `payment_id`, exactly as at settle. Pass that context\nexplicitly only as a version-skew fallback when Haven has no stored context\nfor the id \u2014 `merchant_url` and `tool_name` both or none together, never\njust one.\nThe returned `expires_at` is the signing window; if a tool returns\n`PAYMENT_WINDOW_EXPIRED`, re-run the same quote/prepare tool with the same\n`idempotency_key`. Do not call the merchant yourself \u2014 Haven completes the\nmerchant leg for you.\n\n**Direct transfer / non-MCP paywall:** `mcp__haven__haven_pay` with\n`to`, `amount`, and `token` for a plain transfer. For an arbitrary,\nnon-MCP x402 paywall: `mcp__haven__haven_quote_x402` to get a quote, then\n`mcp__haven__haven_pay_x402_quote` \u2014 follow the result's guidance fields\nfirst and sign in the local Haven signer. On THIS path Haven does not talk to\nthe merchant: `mcp__haven-signer__haven_sign_x402` returns both\n`signature` and `payment_header`; relay `signature` with\n`mcp__haven__haven_submit`, then retry the paywalled URL yourself with\n`payment_header`. Do not pass that call's `x402_binding` to\n`mcp__haven-signer__haven_x402_sign_header` \u2014 the one-shot already spent it\nbuilding the header, so the call can only refuse. Then tell Haven what the\nmerchant answered: `mcp__haven__haven_report_x402_outcome` with the\n`payment_id`, `outcome` (`\"accepted\"` for a 2xx, else `\"rejected\"`)\nand the `merchant_status` you got. Because Haven never contacted that\nmerchant, this is the only way it can learn the purchase failed \u2014 without it a\nfailed purchase reads as complete for fifteen minutes. (The SDK's own\n`haven_pay_x402` tool does perform the merchant retry itself; that tool is\nnot part of the hosted MCP surface.) If the process\ncrashes after payment, a later `mcp__haven__haven_get_payment_status` call\nmay report `nextAction: 'retry_original_x402_request'` \u2014 only then call\n`mcp__haven__haven_resume_x402_payment` with the preserved resume state or\npayment id, instead of paying again.\n\n**Catalog tool arguments:** when `haven_discover_tools` returns\n`tool_arguments`, pass that object unchanged as the pay tool's\n`arguments` field (for example\n`tool_arguments: { \"tier\": \"50gb\" }` -> `arguments: { \"tier\": \"50gb\" }`).\n\n**Prices:** show the user the live price from a read-only quote or the pay-tool\nresult, never a catalog price. `haven_discover_tools` prices are indicative\n(`price_is_indicative`) and can be stale. A read-only quote is informational\nonly and does not reserve a price; the later paid call re-quotes and enforces\nthe cap. The pay-tool result's `amount` / `amount_atomic` is the merchant's\nown quoted price for that call \u2014 a ceiling the merchant settles at or below \u2014\nso present it as the most the user will pay. It is a price, not an approval:\nthe payment goes through only if it also fits the cap you set and the on-chain\nbudget the user signed, which is enforced on-chain rather than by Haven.\n\n**Status:** `mcp__haven__haven_get_payment_status` with a `payment_id` to\ncheck on in-flight payments. Do not poll in a tight loop.\n\n## Declines and stop signals\n\n- A payment outside the agent's rules \u2014 above the remaining budget, wrong\n recipient, or expired budget \u2014 is declined before any money moves. Nothing\n is queued; tell the user, who can raise the budget in Haven.\n- `safe_to_continue: false` on a guidance block is a stop signal in\n machine-readable form: stop and involve the user before calling anything\n else for this payment.\n- Never ask the user for private keys. Signing happens only in the local Haven\n signer; the hosted Haven tools never receive the signing key. If a tool\n reports a missing or invalid credential, tell the user to re-run the Haven\n connector command.\n\n## Failure handling\n\nHaven tool failures are shaped like `{ success: false, code, message, ... }`\nor older `{ error, status, details? }` responses. Branch on `code` when\npresent and surface `message` or `error` verbatim. Common cases:\n\n- `insufficient_funds`: the Haven wallet doesn't hold enough of that token.\n Suggest the user add funds in the Haven dashboard.\n- `PRICE_EXCEEDS_MAX`: the live merchant price exceeded your cap. No funds\n moved; ask the user before retrying with a higher one.\n- `AMBIGUOUS_MAX_AMOUNT`: you sent both `max_amount` and\n `max_amount_human`. Nothing was contacted or spent \u2014 re-send with exactly\n one (`max_amount_human` for a cap the user stated in tokens).\n- `MAX_AMOUNT_UNCONVERTIBLE`: `max_amount_human` does not fit this quote's\n asset \u2014 unknown decimals, or more decimal places than the asset supports.\n Round the cap, or send an exact atomic `max_amount`.\n- `PAYMENT_WINDOW_EXPIRED`: re-run the quote/prepare tool with the same\n `idempotency_key`, then sign the fresh payload.\n- `MERCHANT_NOT_READY`: the merchant refused the quote with its own\n \"cannot settle right now\" signal (a 503 `merchant_not_ready` with a\n `reason_code`) instead of a 402. No payment was created. Tell the user;\n retry later (the message carries `retry_after_s` when the merchant gave\n one) \u2014 this is not a wrong or broken endpoint.\n- `MERCHANT_REJECTED_AFTER_FUNDING`: the merchant refused the paid retry.\n On eip3009 (`rail` not `erc7710`): Stop-and-sweep \u2014 stop retrying the\n merchant and use `mcp__haven__haven_sweep_delegate` to recover stranded\n delegate funds. On erc7710 there is no funding leg and nothing to sweep:\n follow the message \u2014 it says whether the merchant declined to settle\n (re-quote later) or whether to check `haven_get_payment_status` after\n the payment window first.\n- `MERCHANT_UNRESPONSIVE_AFTER_FUNDING`: the merchant never answered the paid\n retry. This is NOT proof of rejection \u2014 the merchant may still settle late.\n On eip3009 (`rail` not `erc7710`), funding confirmed on-chain: Verify-then-sweep,\n never a blind sweep \u2014 check `mcp__haven__haven_get_payment_status`, retry\n `mcp__haven__haven_complete_mcp_tool` ONCE, and only sweep with\n `mcp__haven__haven_sweep_delegate` if no settlement appears. On erc7710\n there is no funding leg and nothing to sweep, and\n `mcp__haven__haven_complete_mcp_tool` has no erc7710 branch (it refuses a\n submitted intent) \u2014 do not retry it: the merchant may still redeem the\n settlement authorization within the payment window, so check\n `mcp__haven__haven_get_payment_status` after that window and re-quote only\n if it shows no settlement.\n- Budget exceeded: tell the user how much remains (from\n `mcp__haven__haven_get_allowances`) and that they can raise the budget in\n Haven.\n\n## Reporting after a purchase\n\nA settled `mcp__haven__haven_settle_mcp_tool` response carries\n`agent_summary.purchase_summary` and the remaining post-purchase allowance\nin `allowance` \u2014 report the product, Haven-derived payment/transaction\nfields, and what is left from those fields directly. `result` is optional\nraw merchant evidence; never use it to decide whether the purchase was paid.\nDo not call `haven_get_agent` or `haven_get_allowances` again just to\nreport a purchase you already made.\n\n## Revoke\n\nIf this agent's credential may have leaked, tell the user to pause or revoke\nthe agent in the Haven dashboard under Agents. New requests stop immediately\nfor that credential.\n";
2725
+ declare const HAVEN_SKILL_MD = "---\nname: haven-pay\ndescription: Pay for things from the user's Haven wallet within their agent rules, and set Haven up when it is not yet connected. Use when the user asks to send, pay, tip, or transfer crypto; when a request hits an HTTP 402 (x402) paywall; or when they ask to create a Haven account, create an agent, or connect one.\n---\n\n# Haven: pay from a Haven wallet\n\nThis skill lets the agent make payments from the user's Haven wallet through\nthe Haven MCP tools. Every payment is checked against the agent's on-chain\nbudget before money moves; a payment above the remaining budget is declined \u2014\nnothing is paid past the rules the user set.\n\nHosted tools run in the `mcp__haven__` namespace. Local signing tools run in\nthe `mcp__haven-signer__` namespace and keep the delegate key on this machine.\nThat namespacing is Claude-family; other runtimes name the servers by their\nown config keys (Codex: `haven`, `haven_signer`). Tool results carry the\nexact next step (`next_action`, `next_tool`, `next_arguments`, plus the\nruntime-neutral `next_tool_server` + `next_tool_name` + `next_tool_server_role`\n\u2014 the bare tool name on that logical server, whatever your runtime calls it).\nWhen no tool follows, `next_tool` is absent and `next_tool_omitted_reason`\nsays why; that is a complete answer.\nFollow those fields first; the prose below is fallback and orientation, not\nthe source of truth.\n\n## When to use this skill\n\n- The user asks to send money, pay someone, tip, donate, or transfer tokens.\n- A request returns HTTP 402 (x402): use the Haven pay tools to settle it,\n then retry the original request.\n\n## Onboarding and setup\n\nYou are in this mode when there is no Haven agent credential on this machine,\nor when your user asks you to create a Haven account, create an agent, or\nconnect one \u2014 for themselves or for someone else.\n\n**None of the tools below creates authority.** They spend a budget a human\nalready signed. There is no tool here that opens an account, mints a\ncredential, or approves a budget, so reaching for one of them to \"set Haven\nup\" cannot work; the steps are the ones in this section instead.\n\nStart by reading `/for-agents.md` on the Haven host \u2014 the origin of the\n`api_url` in your `agent.json` if you have one, otherwise the host your user\nnames. It is the full runbook: six steps, which four are your user's, and what\nto say at each hand-off.\n\nTwo of those steps you can do yourself, from the shell with `@haven_ai/cli`\n(installs the `haven` command):\n\n- `haven login` \u2014 a device-code browser flow. It prints a code and a link\n for your user to approve, so you never see or ask for their password. What\n the session can reach is an allow-list, not your user's full authority: it\n creates and manages agents and reads the account, and it cannot approve a\n budget, rotate a key, change a signer or move money \u2014 those are your user's.\n- `haven agents connect` with `--name`, `--budget`, `--token` and\n `--period` \u2014 creates a connection setup and prints two things: the\n connector command the backend built, and the approval link to give your user.\n Add `--run` to execute that command here as a child process.\n- `haven wallets funding` \u2014 prints the paste-ready funding instruction: what\n to send, to which address, on which chain. Read the chain from there rather\n than assuming one. `--wait` polls until the account counts as funded.\n\n**Four steps are your user's, and each one needs a human:** create the account\nand its passkey, fund the wallet, approve every agent's budget, and rotate a\ncredential. You can compose the funding message for them with\n`haven wallets funding`, but you cannot send the money \u2014 that transfer is\ntheirs, from a wallet you have no access to.\n\nRunning the connector command is the step that wires this machine to the new\nagent \u2014 the command `haven agents connect` printed, or the one your user\npasted you from the dashboard. Three rules bind you while you do it, quoted\nunchanged from the setup prompt your user is also holding so the two copies\ncannot drift into contradicting each other. They are written in your user's\nvoice, so read them accordingly: \"me\" and \"I\" below are your user, never\nHaven, and \"the command above\" is that connector command, not anything printed\nin this file. The first rule outranks anything else you were about to do next:\n\n- When a --json outcome reports approval.required: true, your first action must be to relay the approval instruction to me in your own reply \u2014 if the outcome carries approval.url, give me that link; otherwise tell me to return to Haven and approve this agent's budget \u2014 before verifying the connection, restarting anything, or any other step. Never build that link yourself: relay the one the outcome gave you or none at all. Any restart the outcome asks for is a separate instruction to give me afterwards, once the approval is done.\n- Only two changes to the command above are permitted, and no others: appending --json, and \u2014 only if the connector refuses because it could not determine the agent runtime \u2014 re-running it once with --runtime <name> added, naming the harness you are running in, using one of the values that refusal lists. Never invent a runtime name and never change anything else.\n- If the connector refuses with wiring_collision, this machine is already wired to a different agent: relay that refusal to me with the superseded_agent_ids and suggested_name it carries, and let me choose whether to replace the existing wiring or add this agent alongside it. Never pick for me by adding --replace or --name yourself.\n\nDo not print private keys, API keys, credential file contents, or config secrets in chat or logs.\n\n## Identity and budget\n\nDo not guess the wallet address, network, or budget.\n\nFor instant orientation at the start of a session, read the non-secret\n`agent.json` the connector wrote to your Haven credential directory (typically\n`~/.haven/agents/<agent-id>/agent.json` \u2014 if you don't know the agent id, list\n`~/.haven/agents/` to find the folder). It\nholds your agent id, Haven wallet address, network, and *configured* per-token\nbudget, and contains no keys \u2014 the fastest way to answer \"who am I and what may\nI spend\" with no round trip. If that file is absent (some setups don't write\nit), use the tools below instead.\n\nBefore any payment, confirm the *live remaining* budget with the tools \u2014\n`agent.json` shows the configured budget, not what is left after recent\nspending:\n\n- `mcp__haven__haven_get_agent` \u2014 the recommended first call: identity\n (wallet, network) plus `spend_authority_readiness` (`ready` / `needs_approval` /\n `revoked`) and live remaining per-token allowance, in one shot. That signal\n covers hosted identity and on-chain spend authority only \u2014 it cannot see the\n local signer; the signer is verified by calling any signer tool.\n- `mcp__haven__haven_get_allowances` \u2014 detailed per-token breakdown\n (configured, spent, reset window) when you need more than the summary.\n- `mcp__haven__haven_check_funds` \u2014 whether the account actually HOLDS at\n least a given amount of a token. Allowance answers above say what you are\n permitted to spend; this one says whether the money is really there,\n answered as `covered` true/false/null \u2014 never as a balance. On\n `covered: false`, stop and tell the user the account is short; on\n `covered: null` (the chain read failed), treat it as unverifiable rather\n than as absence.\n\nBudgets reset on a period the user chose. If a payment exceeds the remaining\nbudget it is declined before any money moves \u2014 tell the user; they can raise\nthe budget in the Haven dashboard, or wait for the period reset.\n\n## Paying\n\n**Catalog purchases \u2014 the primary path for MCP merchants:**\n\n1. `mcp__haven__haven_discover_tools` to find a payable service and its\n `catalog_id`.\n2. If the user needs the live price before authorizing a cap, call\n `mcp__haven__haven_quote_catalog_purchase` with `catalog_id`. It is\n read-only and informational only: it never reserves a price or creates a\n payment. Tell the user its `amount` / `amount_atomic`, then choose a cap.\n3. `mcp__haven__haven_prepare_catalog_purchase` with `catalog_id` and a\n spending cap. A cap is REQUIRED on this tool and is best practice on every\n paid call below too \u2014 it caps what the LIVE merchant quote may charge,\n checked before any funding intent is created. Write it the way the user\n said it: `max_amount_human` is whole tokens, so \"no more than 1 USDC\" is\n `max_amount_human: \"1\"`. (`max_amount` is the atomic-unit form, where\n \"1\" means 0.000001 USDC \u2014 do not convert by hand, and never send both.)\n4. Then FOLLOW THE RESPONSE'S GUIDANCE FIELDS: `next_action`, `next_tool`,\n and `next_arguments` name the exact next call \u2014 act on those first; the\n prose in this section is fallback and debugging detail. If the catalog\n entry is missing or degraded, the response instead names\n `mcp__haven__haven_pay_mcp_tool` (merchant URL, tool name, arguments) as\n the manual fallback.\n\n**Signing:** `mcp__haven-signer__haven_sign_x402` with `payment_id` ONLY \u2014\nthe local signer fetches the exact signing bytes AND `payment_required`\nitself, so never relay `typed_data` or the 402 blob yourself. If the signer\nreports its fetched context carried no `payment_required` (older backend),\nre-call with `payment_required` added verbatim. Fallback for an older signer\nor backend: re-run the quote/prepare tool with the SAME `idempotency_key`\nplus `include_signing_payload=true`, then pass `payload_hash`,\n`x402_expected` (the nested `x402.expected` object), and\n`typed_data`/`typed_data_b64` through unchanged.\n\n**Settle:** `mcp__haven__haven_settle_mcp_tool` with `payment_id`,\n`signature`, and `payment_header` ONLY \u2014 Haven rehydrates the merchant call\ncontext (`merchant_url`, `tool_name`, `arguments`, `mcp_transport`)\nserver-side from `payment_id`. Pass those four fields explicitly only as a\nversion-skew fallback when Haven has no stored context for the id \u2014 both or\nnone together, never just one. If the settle result carries `settled: false`,\nfunding has not confirmed \u2014 follow the result's guidance fields and check\nstatus later, do not re-pay.\n\nStep-by-step alternative (also key-safe; for an older signer or backend, or\nwhen you already have a merchant URL and tool name instead of a\n`catalog_id`): if the user needs the live price before choosing a cap, first\ncall `mcp__haven__haven_quote_mcp_tool` with that merchant URL, tool name,\nand arguments. It is informational only; then call\n`mcp__haven__haven_pay_mcp_tool` with the same inputs and the explicit cap.\nThe paid call always obtains a fresh quote before it creates any intent. Then\ncontinue `mcp__haven__haven_pay_mcp_tool` \u2192\n`mcp__haven-signer__haven_sign` \u2192 `mcp__haven__haven_submit` \u2192\n`mcp__haven-signer__haven_x402_sign_header` \u2192\n`mcp__haven__haven_complete_mcp_tool`. Call that last step with\n`payment_id` and the signer's `payment_header` ONLY. It does not take\n`payment_required`: Haven rehydrates the merchant call context\n(`merchant_url`, `tool_name`, `arguments`, `mcp_transport`) and the\n402 server-side from `payment_id`, exactly as at settle. Pass that context\nexplicitly only as a version-skew fallback when Haven has no stored context\nfor the id \u2014 `merchant_url` and `tool_name` both or none together, never\njust one.\nThe returned `expires_at` is the signing window; if a tool returns\n`PAYMENT_WINDOW_EXPIRED`, re-run the same quote/prepare tool with the same\n`idempotency_key`. Do not call the merchant yourself \u2014 Haven completes the\nmerchant leg for you.\n\n**Direct transfer / non-MCP paywall:** `mcp__haven__haven_pay` with\n`to`, `amount`, and `token` for a plain transfer. For an arbitrary,\nnon-MCP x402 paywall: `mcp__haven__haven_quote_x402` to get a quote, then\n`mcp__haven__haven_pay_x402_quote` \u2014 follow the result's guidance fields\nfirst and sign in the local Haven signer. On THIS path Haven does not talk to\nthe merchant: `mcp__haven-signer__haven_sign_x402` returns both\n`signature` and `payment_header`; relay `signature` with\n`mcp__haven__haven_submit`, then retry the paywalled URL yourself with\n`payment_header`. Do not pass that call's `x402_binding` to\n`mcp__haven-signer__haven_x402_sign_header` \u2014 the one-shot already spent it\nbuilding the header, so the call can only refuse. Then tell Haven what the\nmerchant answered: `mcp__haven__haven_report_x402_outcome` with the\n`payment_id`, `outcome` (`\"accepted\"` for a 2xx, else `\"rejected\"`)\nand the `merchant_status` you got. Because Haven never contacted that\nmerchant, this is the only way it can learn the purchase failed \u2014 without it a\nfailed purchase reads as complete for fifteen minutes. (The SDK's own\n`haven_pay_x402` tool does perform the merchant retry itself; that tool is\nnot part of the hosted MCP surface.) If the process\ncrashes after payment, a later `mcp__haven__haven_get_payment_status` call\nmay report `nextAction: 'retry_original_x402_request'` \u2014 only then call\n`mcp__haven__haven_resume_x402_payment` with the preserved resume state or\npayment id, instead of paying again.\n\n**Catalog tool arguments:** when `haven_discover_tools` returns\n`tool_arguments`, pass that object unchanged as the pay tool's\n`arguments` field (for example\n`tool_arguments: { \"tier\": \"50gb\" }` -> `arguments: { \"tier\": \"50gb\" }`).\n\n**Prices:** show the user the live price from a read-only quote or the pay-tool\nresult, never a catalog price. `haven_discover_tools` prices are indicative\n(`price_is_indicative`) and can be stale. A read-only quote is informational\nonly and does not reserve a price; the later paid call re-quotes and enforces\nthe cap. The pay-tool result's `amount` / `amount_atomic` is the merchant's\nown quoted price for that call \u2014 a ceiling the merchant settles at or below \u2014\nso present it as the most the user will pay. It is a price, not an approval:\nthe payment goes through only if it also fits the cap you set and the on-chain\nbudget the user signed, which is enforced on-chain rather than by Haven.\n\n**Status:** `mcp__haven__haven_get_payment_status` with a `payment_id` to\ncheck on in-flight payments. Do not poll in a tight loop.\n\n## Declines and stop signals\n\n- A payment outside the agent's rules \u2014 above the remaining budget, wrong\n recipient, or expired budget \u2014 is declined before any money moves. Nothing\n is queued; tell the user, who can raise the budget in Haven.\n- `safe_to_continue: false` on a guidance block is a stop signal in\n machine-readable form: stop and involve the user before calling anything\n else for this payment.\n- Never ask the user for private keys. Signing happens only in the local Haven\n signer; the hosted Haven tools never receive the signing key. If a tool\n reports a missing or invalid credential, tell the user to re-run the Haven\n connector command.\n\n## Failure handling\n\nHaven tool failures are shaped like `{ success: false, code, message, ... }`\nor older `{ error, status, details? }` responses. A failure carries the same\n`next_action` / `next_tool` / `next_arguments` / `next_tool_omitted_reason`\nfields a success does; follow them first, then branch on `code` and surface\n`message` or `error` verbatim. Common cases:\n\n- `insufficient_funds`: the Haven wallet doesn't hold enough of that token.\n Suggest the user add funds in the Haven dashboard.\n- `PRICE_EXCEEDS_MAX`: the live merchant price exceeded your cap. No funds\n moved; ask the user before retrying with a higher one.\n- `AMBIGUOUS_MAX_AMOUNT`: you sent both `max_amount` and\n `max_amount_human`. Nothing was contacted or spent \u2014 re-send with exactly\n one (`max_amount_human` for a cap the user stated in tokens).\n- `MAX_AMOUNT_UNCONVERTIBLE`: `max_amount_human` does not fit this quote's\n asset \u2014 unknown decimals, or more decimal places than the asset supports.\n Round the cap, or send an exact atomic `max_amount`.\n- `PAYMENT_WINDOW_EXPIRED`: re-run the quote/prepare tool with the same\n `idempotency_key`, then sign the fresh payload.\n- `MERCHANT_NOT_READY`: the merchant refused the quote with its own\n \"cannot settle right now\" signal (a 503 `merchant_not_ready` with a\n `reason_code`) instead of a 402. No payment was created. Tell the user;\n retry later (the message carries `retry_after_s` when the merchant gave\n one) \u2014 this is not a wrong or broken endpoint.\n- `MERCHANT_REJECTED_AFTER_FUNDING`: the merchant refused the paid retry.\n On eip3009 (`rail` not `erc7710`): Stop-and-sweep \u2014 stop retrying the\n merchant and use `mcp__haven__haven_sweep_delegate` to recover stranded\n delegate funds. On erc7710 there is no funding leg and nothing to sweep:\n follow the message \u2014 it says whether the merchant declined to settle\n (re-quote later) or whether to check `haven_get_payment_status` after\n the payment window first.\n- `MERCHANT_UNRESPONSIVE_AFTER_FUNDING`: the merchant never answered the paid\n retry. This is NOT proof of rejection \u2014 the merchant may still settle late.\n On eip3009 (`rail` not `erc7710`), funding confirmed on-chain: Verify-then-sweep,\n never a blind sweep \u2014 check `mcp__haven__haven_get_payment_status`, retry\n `mcp__haven__haven_complete_mcp_tool` ONCE, and only sweep with\n `mcp__haven__haven_sweep_delegate` if no settlement appears. On erc7710\n there is no funding leg and nothing to sweep, and\n `mcp__haven__haven_complete_mcp_tool` has no erc7710 branch (it refuses a\n submitted intent) \u2014 do not retry it: the merchant may still redeem the\n settlement authorization within the payment window, so check\n `mcp__haven__haven_get_payment_status` after that window and re-quote only\n if it shows no settlement.\n- Budget exceeded: tell the user how much remains (from\n `mcp__haven__haven_get_allowances`) and that they can raise the budget in\n Haven.\n\n## Reporting after a purchase\n\nA settled `mcp__haven__haven_settle_mcp_tool` response carries\n`agent_summary.purchase_summary` and the remaining post-purchase allowance\nin `allowance` \u2014 report the product, Haven-derived payment/transaction\nfields, and what is left from those fields directly. `result` is optional\nraw merchant evidence; never use it to decide whether the purchase was paid.\nDo not call `haven_get_agent` or `haven_get_allowances` again just to\nreport a purchase you already made.\n\n## Revoke\n\nIf this agent's credential may have leaked, tell the user to pause or revoke\nthe agent in the Haven dashboard under Agents. New requests stop immediately\nfor that credential.\n";
2592
2726
  /** Directory name for the installed skill folder. */
2593
2727
  declare const SKILL_FOLDER_NAME = "haven-pay";
2594
2728
  /**
@@ -2801,6 +2935,104 @@ declare const HAVEN_AGENT_RUNBOOK_MD = "# Haven for agents \u2014 set your user
2801
2935
  */
2802
2936
  declare const AGENT_ONBOARDING_PROMPT = "I have a Haven account and I am signed in at {{HAVEN_ORIGIN}}. Please set up Haven so you can pay for things within a budget I approve.\n\nStart by reading {{HAVEN_ORIGIN}}/for-agents.md \u2014 it is written for you and explains which steps are mine.\n\nThen:\n\n1. Run `npx @haven_ai/cli@<channel> login`. The `<channel>` in that command is the tag your deployment names \u2014 read it from `/.well-known/haven.json` (`packages.cli.channel`), never a tag you pick. It prints a link and a code and does not need my password \u2014 it must never ask for it. Give me the link straight away and wait for me to approve it in my browser.\n2. Once I have approved, run `haven agents connect --name <a name you choose> --budget <amount> --token USDC --period <minutes>` with the budget I tell you. If I have not given you one, ask me before running it. Add `--run` to complete the connection in the same step.\n3. When a --json outcome reports approval.required: true, your first action must be to relay the approval instruction to me in your own reply \u2014 if the outcome carries approval.url, give me that link; otherwise tell me to return to Haven and approve this agent's budget \u2014 before verifying the connection, restarting anything, or any other step. Never build that link yourself: relay the one the outcome gave you or none at all. Any restart the outcome asks for is a separate instruction to give me afterwards, once the approval is done.\n4. Once I have approved the budget, verify with the `haven_get_agent` tool: `ready` means you can pay, `needs_approval` means my approval has not landed yet.\n\nTwo things only I can do: approving that budget with my passkey, and funding the account with USDC on Base \u2014 no ETH, Haven sponsors the gas. Tell me if either is missing rather than working around it.\n\nDo not print private keys, API keys, credential file contents, or config secrets in chat or logs.";
2803
2937
 
2938
+ /**
2939
+ * #3101 (epic #3105, slice 2/5): the typed next-step builder.
2940
+ *
2941
+ * Every hosted payment tool ends by naming the agent's next tool and its
2942
+ * arguments (#1308). Until this module, the tool was a free string and the
2943
+ * arguments a `Record<string, unknown>`, so nothing tied the keys to the tool
2944
+ * named beside them — three sites handed `{ payment_id: null }` to a tool
2945
+ * whose `payment_id` is a required string, and the compiler could not see it.
2946
+ *
2947
+ * The builder is generic over a TARGET MAP the caller supplies: bare tool
2948
+ * name → { role, validate }. It is deliberately schema-library-agnostic (the
2949
+ * SDK carries no zod): the hosted server derives each target's argument type
2950
+ * from its own zod shape and passes a `validate` closure; this module only
2951
+ * needs to know the role (to render `mcp__<server>__<tool>`) and how to say
2952
+ * whether arguments parse. Keyed on the bare name + role (decision 1) so the
2953
+ * namespaced string is rendered in exactly one place and the runtime-neutral
2954
+ * `next_tool_server` / `next_tool_name` / `next_tool_server_role` fields are
2955
+ * derived from the same input rather than parsed back out of a literal.
2956
+ *
2957
+ * Decisions 3 and 8: `nextTool` is REQUIRED on the input and may be `null` —
2958
+ * a site that forgets it is a compile error; a site with no next tool says
2959
+ * why, and the wire omits `next_tool` and carries `next_tool_omitted_reason`.
2960
+ * `next_tool` is never null on the wire.
2961
+ */
2962
+ type NextToolServerRole = 'hosted' | 'signer';
2963
+ /** The DEFAULT server name each role is wired under (#1588, #2550). */
2964
+ declare const NEXT_TOOL_SERVER_NAMES: Record<NextToolServerRole, string>;
2965
+ /** Default server name → role. An unknown server yields no role rather than a guess (#2550). */
2966
+ declare const NEXT_TOOL_SERVER_ROLES: Record<string, NextToolServerRole>;
2967
+ /** Renders the Claude-family namespaced tool name — the one string clients have followed since #1308. */
2968
+ declare function renderNextTool(role: NextToolServerRole, name: string): string;
2969
+ /** Parses a namespaced literal back into its parts; `role` is absent for an unknown server. */
2970
+ declare function parseNextTool(literal: string): {
2971
+ server: string;
2972
+ name: string;
2973
+ role?: NextToolServerRole;
2974
+ } | null;
2975
+ /**
2976
+ * One target the builder may hand off to. `TArgs` is the argument type the
2977
+ * caller derived from the tool's declared schema; `validate` is the runtime
2978
+ * twin of that type and returns `null` when the arguments parse, else why not.
2979
+ */
2980
+ interface NextStepTarget<TArgs> {
2981
+ role: NextToolServerRole;
2982
+ validate: (input: unknown) => string | null;
2983
+ /** Phantom carrier for the argument type; never read at runtime. */
2984
+ readonly _args?: TArgs;
2985
+ }
2986
+ type NextStepTargets = Record<string, NextStepTarget<unknown>>;
2987
+ /** The argument type a target carries. */
2988
+ type NextStepArguments<Targets extends NextStepTargets, T extends keyof Targets> = Targets[T] extends NextStepTarget<infer A> ? A : never;
2989
+ /**
2990
+ * The handoff half of a next step: a registered tool with arguments that
2991
+ * tool accepts, or no tool with the reason. A discriminated union over the
2992
+ * target map's keys, so a wrong key, a missing required key, an unregistered
2993
+ * tool name and an omitted `nextTool` are each a compile error at the site.
2994
+ */
2995
+ type NextStepHandoff<Targets extends NextStepTargets> = {
2996
+ [T in keyof Targets & string]: {
2997
+ nextTool: T;
2998
+ nextArguments: NextStepArguments<Targets, T>;
2999
+ };
3000
+ }[keyof Targets & string] | {
3001
+ nextTool: null;
3002
+ nextToolOmittedReason: string;
3003
+ };
3004
+ type NextStepInput<Targets extends NextStepTargets> = NextStepHandoff<Targets> & {
3005
+ nextAction: AgentPaymentNextAction;
3006
+ safeToContinue: boolean;
3007
+ reason: string;
3008
+ };
3009
+ /** The wire shape: `AgentNextStep` (its `next_tool` family) — never a null `next_tool`. */
3010
+ type NextStep = AgentNextStep;
3011
+ /**
3012
+ * Per-`next_action` default tool (decision 9): the tool a site names unless it
3013
+ * has a reason to override. Only actions with ONE sensible target are listed;
3014
+ * `retry_original_x402_request` is absent because its only live emitter names
3015
+ * no tool on purpose (the agent's own HTTP retry); `sign_and_submit_payment`
3016
+ * is absent because the signer tool
3017
+ * depends on the settlement scheme (`haven_sign` for erc7710 delegations,
3018
+ * `haven_sign_x402` for the EIP-3009 bridge) and a wrong default there would be
3019
+ * worse than none.
3020
+ */
3021
+ declare const DEFAULT_NEXT_TOOL_BY_ACTION: {
3022
+ readonly check_status_later: "haven_get_payment_status";
3023
+ readonly sweep_stranded_funds: "haven_sweep_delegate";
3024
+ };
3025
+ declare function defaultNextToolFor(action: AgentPaymentNextAction): string | undefined;
3026
+ /**
3027
+ * Builds a `nextStep` function bound to a target map. The returned function
3028
+ * renders the wire fields from the bare name + role, and re-validates the
3029
+ * arguments at runtime: on a mismatch it FAILS SAFE — omits the tool and says
3030
+ * why in `next_tool_omitted_reason` — rather than throwing out of a handler
3031
+ * that has already moved money. The compile-time twin makes that branch
3032
+ * unreachable from typed sites; it exists for callers that bypass the types.
3033
+ */
3034
+ declare function createNextStepBuilder<Targets extends NextStepTargets>(targets: Targets): (input: NextStepInput<Targets>) => NextStep;
3035
+
2804
3036
  /**
2805
3037
  * The npm dist-tag the published Haven packages tell a user to re-run (#2423,
2806
3038
  * slice 3 of epic #2420).
@@ -2969,55 +3201,27 @@ interface UnsupportedNodeVersionMessageOptions {
2969
3201
  declare function unsupportedNodeVersionMessage(options: UnsupportedNodeVersionMessageOptions): string;
2970
3202
 
2971
3203
  /**
2972
- * #2908 (naming epic #2906, phase 1): the account-vocabulary reads and the
2973
- * dual-name emissions every published package shares during the one-release
2974
- * compatibility window.
3204
+ * #2914 (naming epic #2906, phase 5 — the CONTRACTION): the compatibility
3205
+ * window #2908 opened (read both server-response names, prefer the new;
3206
+ * emit both camelCase names; write only the new) closed with the
3207
+ * `0.2.0-alpha.0` release reaching `main` on 2026-09-14 and a further
3208
+ * promotion on 2026-09-16. The account-vocabulary name is now the ONLY name
3209
+ * on every wire shape this module touches; `safe_address` / `safe_id` /
3210
+ * `sign_data.components.safe` are no longer read from a server response.
2975
3211
  *
2976
- * The rule, stated once: READ both names and prefer the new; EMIT both names
2977
- * with the same value; WRITE only the new. The old names on server responses
2978
- * are removed by #2914, one release after the one that carries this module.
2979
- * The credential-FILE fallbacks (`safe_address` / `safeAddress` in a file on
2980
- * disk) are NOT part of that window — they are permanent, because a file that
2981
- * was written before this release never rewrites itself.
3212
+ * `readAccountAddress` and `readAccountId` collapsed to a single field read
3213
+ * once the fallback was removed, so they are gone — read `raw.account_address`
3214
+ * / `raw.account_id` directly. `accountAddressTwins` is gone too: the SDK's
3215
+ * public shapes carry `accountAddress` only, never a `safeAddress` twin.
2982
3216
  *
2983
- * Kept as tiny pure functions so a reader has exactly one fallback chain per
2984
- * shape and a test can mutate it: dropping the new name fails the new-shape
2985
- * test, dropping the old name fails the old-shape test.
2986
- */
2987
- /**
2988
- * The account address off a snake_case server shape, new name first.
2989
- *
2990
- * `account_address` is the P0 (#2907) twin the server emits beside
2991
- * `safe_address`; an older server emits only `safe_address`. A missing pair
2992
- * resolves to `undefined` rather than an empty string so callers can tell
2993
- * "absent" from "blank".
2994
- */
2995
- declare function readAccountAddress(raw: {
2996
- account_address?: string | null;
2997
- safe_address?: string | null;
2998
- }): string | undefined;
2999
- /**
3000
- * The account id off a snake_case server shape, new name first
3001
- * (`account_id`, the #2907 twin of `safe_id`).
3002
- */
3003
- declare function readAccountId(raw: {
3004
- account_id?: string | null;
3005
- safe_id?: string | null;
3006
- }): string | undefined;
3007
- /**
3008
- * Both camelCase names for one address, for the SDK's public shapes (and the
3009
- * hosted MCP outputs that spread them). Same value under both keys; the
3010
- * `safeAddress` key is the deprecated one and goes at #2914.
3217
+ * `readX402ReceiptPayer` survives because it still has a real multi-step
3218
+ * chain (`payer`, then the top-level account address, then the nested
3219
+ * `sign_data.components` twin) once the old names are dropped from it.
3011
3220
  */
3012
- declare function accountAddressTwins(address: string | undefined): {
3013
- accountAddress: string;
3014
- safeAddress: string;
3015
- };
3016
3221
  /**
3017
- * The x402 receipt's `payer` off a funding-authorization response, in the
3018
- * order the issue pins (#2908): the explicit `payer`, then the top-level
3019
- * account address (new name, then old), then the `sign_data.components`
3020
- * twins — `payer_account` (the #2907 twin) before `safe`.
3222
+ * The x402 receipt's `payer` off a funding-authorization response: the
3223
+ * explicit `payer`, then the top-level `account_address`, then
3224
+ * `sign_data.components.payer_account`.
3021
3225
  *
3022
3226
  * `components.account` is deliberately NOT in this chain: on the funding
3023
3227
  * shapes it holds the DELEGATE account address, a different address, and
@@ -3026,11 +3230,9 @@ declare function accountAddressTwins(address: string | undefined): {
3026
3230
  declare function readX402ReceiptPayer(raw: {
3027
3231
  payer?: string;
3028
3232
  account_address?: string;
3029
- safe_address?: string;
3030
3233
  sign_data?: {
3031
3234
  components?: {
3032
3235
  payer_account?: string;
3033
- safe?: string;
3034
3236
  account?: string;
3035
3237
  };
3036
3238
  };
@@ -3073,9 +3275,10 @@ declare class X402PaymentHeaderValidationError extends Error {
3073
3275
  * challenge — without a cap, a malicious or sloppy merchant can request a
3074
3276
  * year-long window and a leaked signed authorization stays spendable that
3075
3277
  * whole time. 600 s is generous for any facilitator settle (typical is
3076
- * 30–60 s); we CLAMP rather than reject so payments keep flowing while
3077
- * exposure stays bounded. `validBefore` is a deadline, not a demand —
3078
- * settling earlier is always valid.
3278
+ * 30–60 s). This cap applies only to the signed authorization, never to the
3279
+ * advertised requirements echoed in `accepted`. A merchant requiring more
3280
+ * than the bounded lifetime can still reject at verification; preserving its
3281
+ * offer does not widen Haven's signing policy.
3079
3282
  */
3080
3283
  declare const X402_MAX_AUTHORIZATION_WINDOW_SECONDS = 600;
3081
3284
  /**
@@ -3318,6 +3521,58 @@ declare function resolveTokenFromAddress(address: string, network?: string): {
3318
3521
  decimals: number;
3319
3522
  } | null;
3320
3523
 
3524
+ /**
3525
+ * Where the PAID retry goes — and whether it may go there at all (#3097).
3526
+ *
3527
+ * A merchant's 402 challenge declares `resource.url`. Haven records that
3528
+ * declaration as the resource's identity (the binding message, the intent
3529
+ * row, the resume checks all compare against it), but the paid request —
3530
+ * the one carrying `PAYMENT-SIGNATURE` — must go to the URL the CALLER
3531
+ * actually asked for whenever one exists. The declaration is the merchant's
3532
+ * word about itself, not an instruction to the client: the Ampersend
3533
+ * sandbox declares `http://` for a resource it serves over `https` (live,
3534
+ * 2026-09-17; its `http://` answers 308 → https), and a client that adopted
3535
+ * it sent the signed header in clear on the first hop.
3536
+ *
3537
+ * Two rules, both pure, both pinned by tests:
3538
+ *
3539
+ * - `resolveX402RetryTarget`: the caller's request URL wins; the merchant's
3540
+ * `resource.url` is the fallback for callers that only hold the challenge
3541
+ * (the hosted pay-from-quote path). The result says which one it chose and
3542
+ * whether the two disagree, so a quote can surface the disagreement.
3543
+ * - `isSecureX402RetryTarget`: `https` always; `http` only to a target that
3544
+ * cannot leave the machine or the test bench — loopback addresses and the
3545
+ * RFC 2606/6761 reserved names (`.test`, `.localhost`, `.invalid`,
3546
+ * `.example`), which every fixture in this repo uses. A public `http://`
3547
+ * target is refused BEFORE a signed header is handed to a transport.
3548
+ */
3549
+ interface X402RetryTarget {
3550
+ /** The URL the paid request goes to. */
3551
+ url: string;
3552
+ /** Which input produced it. */
3553
+ source: 'request' | 'resource';
3554
+ /**
3555
+ * True when the merchant's declared `resource.url` is not the caller's URL.
3556
+ * Absent (undefined) when nothing was compared — the caller named no URL
3557
+ * and the declaration was adopted as-is — so a consumer never reads
3558
+ * "false" as "the merchant agrees with what you quoted".
3559
+ */
3560
+ resourceUrlDiffersFromRequest?: boolean;
3561
+ }
3562
+ declare function resolveX402RetryTarget(input: {
3563
+ requestUrl?: string | null;
3564
+ resourceUrl: string;
3565
+ }): X402RetryTarget;
3566
+ /** True when a retry carrying a payment header may be sent to `url`. */
3567
+ declare function isSecureX402RetryTarget(url: string): boolean;
3568
+ declare const INSECURE_RETRY_TARGET_CODE = "INSECURE_RETRY_TARGET";
3569
+ /** Refused before any signed header leaves: the paid retry would travel in clear. */
3570
+ declare class HavenInsecureRetryTargetError extends HavenError {
3571
+ readonly url: string;
3572
+ constructor(url: string);
3573
+ }
3574
+ declare function assertSecureX402RetryTarget(url: string): void;
3575
+
3321
3576
  /**
3322
3577
  * Runtime-agnostic base64 helpers — the single source of truth for the wire
3323
3578
  * encoding shared by the SDK and the edge signer (#325).
@@ -3384,4 +3639,4 @@ declare function discoverMerchantMcpUrl(inputUrl: string): Promise<string | null
3384
3639
  /** Trailing-slash/percent-case echoes compare equal; unparseable never does. */
3385
3640
  declare function sameUrl(a: string, b: string): boolean;
3386
3641
 
3387
- export { AGENT_APPROVAL_RELAY_JSON_SENTENCE, AGENT_APPROVAL_RELAY_PROSE_SENTENCE, AGENT_COMMAND_MODIFICATION_SENTENCE, AGENT_JSON_MODE_SENTENCE, AGENT_LOCAL_KEY_SENTENCE, AGENT_NETWORK_ACCESS_SENTENCE, AGENT_ONBOARDING_PROMPT, AGENT_PAYMENT_FAILURE_CODE_VALUES, AGENT_PAYMENT_NEXT_ACTION_VALUES, AGENT_PAYMENT_PHASE_VALUES, AGENT_PAYMENT_RAIL_VALUES, AGENT_README_SECTION_MD, AGENT_SECRET_HYGIENE_SENTENCE, AGENT_WIRING_COLLISION_RELAY_SENTENCE, type AgentNextStep, type AgentPaymentEnumSchema, AgentPaymentFailureCode, AgentPaymentFailureCodeDescriptions, AgentPaymentFailureCodeSchema, AgentPaymentNextAction, AgentPaymentNextActionAccountAlias, AgentPaymentNextActionDescriptions, AgentPaymentNextActionSchema, type AgentPaymentNextActionWire, AgentPaymentPhase, AgentPaymentPhaseDescriptions, AgentPaymentPhaseSchema, AgentPaymentRail, AgentPaymentRailDescriptions, AgentPaymentRailSchema, type AgentPaymentSummary, type AgentPaymentWarning, AgentPaymentWarningCode, type AgentPurchaseSummary, CONNECTOR_PACKAGE_NAME, type CatalogSubmissionAccepted, type ClaudeTool, DEFAULT_CONFIRMATION_TIMEOUT_MS, DISCOVERY_MAX_BYTES, ERC7710_ASSET_TRANSFER_METHOD, type EvidenceReportOutcome, HAVEN_AGENT_RUNBOOK_MD, HAVEN_CONNECTOR_CHANNEL, HAVEN_MINIMUM_NODE_VERSION, HAVEN_SKILL_BODY_MD, HAVEN_SKILL_MD, type HavenAgent, type HavenAgentAllowanceSummary, type HavenAgentReadiness, type HavenAgentSummary, type HavenAllowance, type HavenAllowanceSummary, HavenApiError, type HavenCatalogEntry, type HavenCatalogSubmission, HavenClient, type HavenClientConfig, HavenError, type HavenPaymentReceipt, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, HavenUnsupportedSignerVersionError, HavenZeroSettlementHashError, MERCHANT_DISCOVERY_PATHS, type MachinePaymentRail, MerchantTimeoutError, type OpenAITool, type PaymentFee, type PaymentIntent, type PaymentNextAction, type PaymentPhase, type PaymentReceipt, type PaymentRequest, type PaymentResult, type PaymentResumeState, type PaymentStatus, type PaymentStatusResult, type PostPurchaseAllowanceSummary, RECEIPT_VERSION, type ReceiptVerification, type ResumeAuthorizedX402Input, type ResumeX402PaymentInput, SIGNER_UPDATE_FALLBACK, SKILL_FOLDER_NAME, SWEEP_BASE_CHAIN_ID, SWEEP_BASE_SEPOLIA_CHAIN_ID, SWEEP_BASE_SEPOLIA_USDC_ADDRESS, SWEEP_BASE_USDC_ADDRESS, type SharedToolKey, type SignData, SignerRefusalCode, type SweepAuthorization, type SweepConfirmation, type SweepEip712Domain, type SweepEntry, type SweepExpectedAuth, type SweepPreparation, type SweepPrepareResponse, type SweepResult, type SweepSubmitResponse, type SweepSubmitResult, type SweepTypedData, TRANSFER_WITH_AUTHORIZATION_TYPES, type ToolDescription, type UnsupportedNodeVersionMessageOptions, X402AlreadySettledError, type X402AuthorizationOptions, type X402Erc7710Settlement, type X402ExpectedAuth, type X402ExpectedContext, type X402Intent, type X402McpCallContext, type X402McpTransport, type X402MerchantCallContext, type X402MerchantOutcome, type X402MerchantOutcomeReport, type X402PaymentHeaderContext, X402PaymentHeaderValidationError, type X402PaymentOption, type X402PaymentRequired, type X402Quote, type X402Receipt, type X402RequestSnapshot, type X402ResumeState, type X402SchemeSelection, X402UnexpectedStatusError, X402_LEGACY_PAYMENT_HEADER_NAME, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_PAYMENT_HEADER_NAME, X402_PAYMENT_HEADER_NAMES_SENT, X402_PAYMENT_REQUIRED_HEADER_NAME, X402_PAYMENT_RESPONSE_HEADER_NAME, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, accountAddressTwins, addressFromKey, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, canonicalAgentPaymentNextAction, compareNodeVersions, composeDescription, connectorRerunCommand, connectorSpec, decodeBase64Json, decodeBase64Utf8, discoverMerchantMcpUrl, encodeBase64Json, encodeBase64Utf8, encodePaymentProof, havenTools, isConnectorChannel, isErc7710Option, isFundAccountOrRaiseAllowance, isSupportedNodeVersion, isSweepableChain, isZeroSettlementTxHash, normalizePaymentRequired, parsePaymentRequired, parsePaymentRequiredResponse, readAccountAddress, readAccountId, readX402ReceiptPayer, resolveConnectorChannel, resolveTokenFromAddress, sameUrl, selectErc7710PaymentOption, selectPaymentOption, selectStandardPaymentOption, selectX402SettlementScheme, signHash, signUserOpTypedDataForDelegation, signerUpdateFallback, sweepUsdcAddress, sweepUsdcDomain, toStandardPaymentRequirements, toolDescriptions, unsupportedNodeVersionMessage, validateStandardX402PaymentHeader, verifyPaymentReceipt, verifySignature, x402AssetTransferMethod, x402AuthorizationAmount, x402FacilitatorAddresses, x402V2PaymentEnvelope };
3642
+ export { AGENT_APPROVAL_RELAY_JSON_SENTENCE, AGENT_APPROVAL_RELAY_PROSE_SENTENCE, AGENT_COMMAND_MODIFICATION_SENTENCE, AGENT_JSON_MODE_SENTENCE, AGENT_LOCAL_KEY_SENTENCE, AGENT_NETWORK_ACCESS_SENTENCE, AGENT_ONBOARDING_PROMPT, AGENT_PAYMENT_FAILURE_CODE_VALUES, AGENT_PAYMENT_NEXT_ACTION_VALUES, AGENT_PAYMENT_PHASE_VALUES, AGENT_PAYMENT_RAIL_VALUES, AGENT_README_SECTION_MD, AGENT_SECRET_HYGIENE_SENTENCE, AGENT_WIRING_COLLISION_RELAY_SENTENCE, type AgentNextStep, type AgentPaymentEnumSchema, AgentPaymentFailureCode, AgentPaymentFailureCodeDescriptions, AgentPaymentFailureCodeSchema, AgentPaymentNextAction, AgentPaymentNextActionDescriptions, AgentPaymentNextActionSchema, AgentPaymentPhase, AgentPaymentPhaseDescriptions, AgentPaymentPhaseSchema, AgentPaymentRail, AgentPaymentRailDescriptions, AgentPaymentRailSchema, type AgentPaymentSummary, type AgentPaymentWarning, AgentPaymentWarningCode, type AgentPurchaseSummary, CONNECTOR_PACKAGE_NAME, type CatalogSubmissionAccepted, type ClaudeTool, DEFAULT_CONFIRMATION_TIMEOUT_MS, DEFAULT_NEXT_TOOL_BY_ACTION, DISCOVERY_MAX_BYTES, ERC7710_ASSET_TRANSFER_METHOD, type EvidenceReportOutcome, HAVEN_AGENT_RUNBOOK_MD, HAVEN_CONNECTOR_CHANNEL, HAVEN_MINIMUM_NODE_VERSION, HAVEN_SKILL_BODY_MD, HAVEN_SKILL_MD, type HavenAgent, type HavenAgentAllowanceSummary, type HavenAgentReadiness, type HavenAgentSummary, type HavenAllowance, type HavenAllowanceSummary, HavenApiError, type HavenBalanceCoverage, type HavenCatalogEntry, type HavenCatalogMerchant, type HavenCatalogSubmission, HavenClient, type HavenClientConfig, HavenError, HavenInsecureRetryTargetError, type HavenPaymentReceipt, type HavenPaymentReceiptsPage, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, HavenUnsupportedSignerVersionError, HavenZeroSettlementHashError, INSECURE_RETRY_TARGET_CODE, MERCHANT_DISCOVERY_PATHS, type MachinePaymentRail, MerchantTimeoutError, NEXT_TOOL_SERVER_NAMES, NEXT_TOOL_SERVER_ROLES, type NextStep, type NextStepArguments, type NextStepHandoff, type NextStepInput, type NextStepTarget, type NextStepTargets, type NextToolServerRole, type OpenAITool, type PaymentFee, type PaymentIntent, type PaymentNextAction, type PaymentPhase, type PaymentReceipt, type PaymentRequest, type PaymentResult, type PaymentResumeState, type PaymentStatus, type PaymentStatusResult, type PostPurchaseAllowanceSummary, RECEIPT_VERSION, type ReceiptVerification, type ResumeAuthorizedX402Input, type ResumeX402PaymentInput, SIGNER_UPDATE_FALLBACK, SKILL_FOLDER_NAME, SWEEP_BASE_CHAIN_ID, SWEEP_BASE_SEPOLIA_CHAIN_ID, SWEEP_BASE_SEPOLIA_USDC_ADDRESS, SWEEP_BASE_USDC_ADDRESS, type SharedToolKey, type SignData, SignerRefusalCode, type SweepAuthorization, type SweepConfirmation, type SweepEip712Domain, type SweepEntry, type SweepExpectedAuth, type SweepPreparation, type SweepPrepareResponse, type SweepResult, type SweepSubmitResponse, type SweepSubmitResult, type SweepTypedData, TRANSFER_WITH_AUTHORIZATION_TYPES, type ToolDescription, type UnsupportedNodeVersionMessageOptions, X402AlreadySettledError, type X402AuthorizationOptions, type X402Erc7710Settlement, type X402ExpectedAuth, type X402ExpectedContext, type X402Intent, type X402McpCallContext, type X402McpTransport, type X402MerchantCallContext, type X402MerchantOutcome, type X402MerchantOutcomeReport, type X402PaymentHeaderContext, X402PaymentHeaderValidationError, type X402PaymentOption, type X402PaymentRequired, type X402Quote, type X402Receipt, type X402RequestSnapshot, type X402ResumeState, type X402RetryTarget, type X402SchemeSelection, X402UnexpectedStatusError, X402_LEGACY_PAYMENT_HEADER_NAME, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_PAYMENT_HEADER_NAME, X402_PAYMENT_HEADER_NAMES_SENT, X402_PAYMENT_REQUIRED_HEADER_NAME, X402_PAYMENT_RESPONSE_HEADER_NAME, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, addressFromKey, assertSecureX402RetryTarget, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, compareNodeVersions, composeDescription, connectorRerunCommand, connectorSpec, createNextStepBuilder, decodeBase64Json, decodeBase64Utf8, defaultNextToolFor, discoverMerchantMcpUrl, encodeBase64Json, encodeBase64Utf8, encodePaymentProof, havenTools, isConnectorChannel, isErc7710Option, isSecureX402RetryTarget, isSupportedNodeVersion, isSweepableChain, isZeroSettlementTxHash, normalizePaymentRequired, parseNextTool, parsePaymentRequired, parsePaymentRequiredResponse, readX402ReceiptPayer, renderNextTool, resolveConnectorChannel, resolveTokenFromAddress, resolveX402RetryTarget, sameUrl, selectErc7710PaymentOption, selectPaymentOption, selectStandardPaymentOption, selectX402SettlementScheme, signHash, signUserOpTypedDataForDelegation, signerUpdateFallback, sweepUsdcAddress, sweepUsdcDomain, toStandardPaymentRequirements, toolDescriptions, unsupportedNodeVersionMessage, validateStandardX402PaymentHeader, verifyPaymentReceipt, verifySignature, x402AssetTransferMethod, x402AuthorizationAmount, x402FacilitatorAddresses, x402V2PaymentEnvelope };