agentfootprint 11.1.1 → 11.3.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.
Files changed (200) hide show
  1. package/AGENTS.md +1 -1
  2. package/CAPABILITIES.md +3 -0
  3. package/ai-instructions/claude-code/SKILL.md +1 -1
  4. package/dist/adapters/identity/verify/claims.js +3 -3
  5. package/dist/adapters/mcp/agentcoreRuntime/invoke.js +3 -2
  6. package/dist/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
  7. package/dist/adapters/mcp/agentcoreRuntime/sessionBusy.js +40 -8
  8. package/dist/adapters/mcp/agentcoreRuntime/sessionBusy.js.map +1 -1
  9. package/dist/adapters/mcp/agentcoreRuntime/transport.js +50 -22
  10. package/dist/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
  11. package/dist/core/RunnerBase.js +20 -1
  12. package/dist/core/RunnerBase.js.map +1 -1
  13. package/dist/core/agent/buildToolRegistry.js +1 -1
  14. package/dist/core/agent/buildToolRegistry.js.map +1 -1
  15. package/dist/core/agent/evidence/evidenceIndex.js +30 -2
  16. package/dist/core/agent/evidence/evidenceIndex.js.map +1 -1
  17. package/dist/core/agent/evidence/extract.js +34 -5
  18. package/dist/core/agent/evidence/extract.js.map +1 -1
  19. package/dist/core/agent/evidence/figures.js +31 -3
  20. package/dist/core/agent/evidence/figures.js.map +1 -1
  21. package/dist/core/agent/evidence/numberPrecision.js +58 -2
  22. package/dist/core/agent/evidence/numberPrecision.js.map +1 -1
  23. package/dist/core/agent/stages/route.js +2 -1
  24. package/dist/core/agent/stages/route.js.map +1 -1
  25. package/dist/core/agent/stages/toolCalls.js +14 -1
  26. package/dist/core/agent/stages/toolCalls.js.map +1 -1
  27. package/dist/core/slots/buildToolsSlot.js +1 -1
  28. package/dist/core/slots/buildToolsSlot.js.map +1 -1
  29. package/dist/esm/adapters/identity/jwks.d.ts +2 -2
  30. package/dist/esm/adapters/identity/verify/claims.d.ts +3 -3
  31. package/dist/esm/adapters/identity/verify/claims.js +3 -3
  32. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.d.ts +3 -2
  33. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js +3 -2
  34. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
  35. package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts +11 -6
  36. package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.js +40 -8
  37. package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.js.map +1 -1
  38. package/dist/esm/adapters/mcp/agentcoreRuntime/transport.d.ts +40 -12
  39. package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js +49 -21
  40. package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
  41. package/dist/esm/core/RunnerBase.d.ts +18 -0
  42. package/dist/esm/core/RunnerBase.js +20 -1
  43. package/dist/esm/core/RunnerBase.js.map +1 -1
  44. package/dist/esm/core/agent/buildToolRegistry.js +1 -1
  45. package/dist/esm/core/agent/buildToolRegistry.js.map +1 -1
  46. package/dist/esm/core/agent/evidence/evidenceIndex.d.ts +12 -2
  47. package/dist/esm/core/agent/evidence/evidenceIndex.js +30 -2
  48. package/dist/esm/core/agent/evidence/evidenceIndex.js.map +1 -1
  49. package/dist/esm/core/agent/evidence/extract.js +35 -6
  50. package/dist/esm/core/agent/evidence/extract.js.map +1 -1
  51. package/dist/esm/core/agent/evidence/figures.d.ts +6 -0
  52. package/dist/esm/core/agent/evidence/figures.js +32 -4
  53. package/dist/esm/core/agent/evidence/figures.js.map +1 -1
  54. package/dist/esm/core/agent/evidence/numberPrecision.d.ts +28 -1
  55. package/dist/esm/core/agent/evidence/numberPrecision.js +56 -1
  56. package/dist/esm/core/agent/evidence/numberPrecision.js.map +1 -1
  57. package/dist/esm/core/agent/stages/route.js +2 -1
  58. package/dist/esm/core/agent/stages/route.js.map +1 -1
  59. package/dist/esm/core/agent/stages/toolCalls.js +14 -1
  60. package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
  61. package/dist/esm/core/runner.d.ts +1 -0
  62. package/dist/esm/core/slots/buildToolsSlot.js +1 -1
  63. package/dist/esm/core/slots/buildToolsSlot.js.map +1 -1
  64. package/dist/esm/events/payloads.d.ts +185 -0
  65. package/dist/esm/events/registry.d.ts +3 -1
  66. package/dist/esm/events/registry.js +2 -0
  67. package/dist/esm/events/registry.js.map +1 -1
  68. package/dist/esm/hosting/doorGuard.d.ts +3 -3
  69. package/dist/esm/hosting/doorGuard.js +2 -2
  70. package/dist/esm/hosting/nodeHost.d.ts +1 -1
  71. package/dist/esm/lib/longTimeout.d.ts +34 -0
  72. package/dist/esm/lib/longTimeout.js +56 -0
  73. package/dist/esm/lib/longTimeout.js.map +1 -0
  74. package/dist/esm/lib/sleep.d.ts +2 -0
  75. package/dist/esm/lib/sleep.js +2 -0
  76. package/dist/esm/lib/sleep.js.map +1 -1
  77. package/dist/esm/mcp/backoff.d.ts +81 -0
  78. package/dist/esm/mcp/backoff.js +158 -0
  79. package/dist/esm/mcp/backoff.js.map +1 -0
  80. package/dist/esm/mcp/callLifetime.d.ts +49 -0
  81. package/dist/esm/mcp/callLifetime.js +99 -0
  82. package/dist/esm/mcp/callLifetime.js.map +1 -0
  83. package/dist/esm/mcp/mcpClient.d.ts +4 -1
  84. package/dist/esm/mcp/mcpClient.js +73 -29
  85. package/dist/esm/mcp/mcpClient.js.map +1 -1
  86. package/dist/esm/mcp/requestLedger.d.ts +97 -0
  87. package/dist/esm/mcp/requestLedger.js +192 -0
  88. package/dist/esm/mcp/requestLedger.js.map +1 -0
  89. package/dist/esm/mcp/seriesEvidence.d.ts +102 -0
  90. package/dist/esm/mcp/seriesEvidence.js +246 -0
  91. package/dist/esm/mcp/seriesEvidence.js.map +1 -0
  92. package/dist/esm/mcp/throttleRetry.d.ts +243 -38
  93. package/dist/esm/mcp/throttleRetry.js +562 -90
  94. package/dist/esm/mcp/throttleRetry.js.map +1 -1
  95. package/dist/esm/mcp/types.d.ts +28 -14
  96. package/dist/esm/redaction/knownStrings.js +29 -0
  97. package/dist/esm/redaction/knownStrings.js.map +1 -1
  98. package/dist/esm/security/PermissionPolicy.d.ts +1 -1
  99. package/dist/esm/security/PermissionPolicy.js +1 -1
  100. package/dist/esm/strategies/attach.js +3 -0
  101. package/dist/esm/strategies/attach.js.map +1 -1
  102. package/dist/esm/strategies/defaults/chatBubbleLiveStatus.d.ts +1 -1
  103. package/dist/esm/strategies/defaults/chatBubbleLiveStatus.js +1 -1
  104. package/dist/esm/strategies/flushDeadline.d.ts +47 -0
  105. package/dist/esm/strategies/flushDeadline.js +96 -0
  106. package/dist/esm/strategies/flushDeadline.js.map +1 -0
  107. package/dist/esm/tool-lint/analyze.d.ts +1 -1
  108. package/dist/esm/tool-lint/analyze.js +1 -1
  109. package/dist/esm/tool-lint/rules.d.ts +3 -3
  110. package/dist/esm/tool-lint/rules.js +3 -3
  111. package/dist/esm/tools/requestEvidence.d.ts +78 -0
  112. package/dist/esm/tools/requestEvidence.js +331 -0
  113. package/dist/esm/tools/requestEvidence.js.map +1 -0
  114. package/dist/events/registry.js +2 -0
  115. package/dist/events/registry.js.map +1 -1
  116. package/dist/hosting/doorGuard.js +2 -2
  117. package/dist/lib/longTimeout.js +60 -0
  118. package/dist/lib/longTimeout.js.map +1 -0
  119. package/dist/lib/sleep.js +2 -0
  120. package/dist/lib/sleep.js.map +1 -1
  121. package/dist/mcp/backoff.js +163 -0
  122. package/dist/mcp/backoff.js.map +1 -0
  123. package/dist/mcp/callLifetime.js +103 -0
  124. package/dist/mcp/callLifetime.js.map +1 -0
  125. package/dist/mcp/mcpClient.js +72 -28
  126. package/dist/mcp/mcpClient.js.map +1 -1
  127. package/dist/mcp/requestLedger.js +196 -0
  128. package/dist/mcp/requestLedger.js.map +1 -0
  129. package/dist/mcp/seriesEvidence.js +251 -0
  130. package/dist/mcp/seriesEvidence.js.map +1 -0
  131. package/dist/mcp/throttleRetry.js +568 -92
  132. package/dist/mcp/throttleRetry.js.map +1 -1
  133. package/dist/redaction/knownStrings.js +29 -0
  134. package/dist/redaction/knownStrings.js.map +1 -1
  135. package/dist/security/PermissionPolicy.js +1 -1
  136. package/dist/strategies/attach.js +3 -0
  137. package/dist/strategies/attach.js.map +1 -1
  138. package/dist/strategies/defaults/chatBubbleLiveStatus.js +1 -1
  139. package/dist/strategies/flushDeadline.js +102 -0
  140. package/dist/strategies/flushDeadline.js.map +1 -0
  141. package/dist/tool-lint/analyze.js +1 -1
  142. package/dist/tool-lint/rules.js +3 -3
  143. package/dist/tools/requestEvidence.js +337 -0
  144. package/dist/tools/requestEvidence.js.map +1 -0
  145. package/dist/types/adapters/identity/jwks.d.ts +2 -2
  146. package/dist/types/adapters/identity/verify/claims.d.ts +3 -3
  147. package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts +3 -2
  148. package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts.map +1 -1
  149. package/dist/types/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts +11 -6
  150. package/dist/types/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts.map +1 -1
  151. package/dist/types/adapters/mcp/agentcoreRuntime/transport.d.ts +40 -12
  152. package/dist/types/adapters/mcp/agentcoreRuntime/transport.d.ts.map +1 -1
  153. package/dist/types/core/RunnerBase.d.ts +18 -0
  154. package/dist/types/core/RunnerBase.d.ts.map +1 -1
  155. package/dist/types/core/agent/evidence/evidenceIndex.d.ts +12 -2
  156. package/dist/types/core/agent/evidence/evidenceIndex.d.ts.map +1 -1
  157. package/dist/types/core/agent/evidence/extract.d.ts.map +1 -1
  158. package/dist/types/core/agent/evidence/figures.d.ts +6 -0
  159. package/dist/types/core/agent/evidence/figures.d.ts.map +1 -1
  160. package/dist/types/core/agent/evidence/numberPrecision.d.ts +28 -1
  161. package/dist/types/core/agent/evidence/numberPrecision.d.ts.map +1 -1
  162. package/dist/types/core/agent/stages/route.d.ts.map +1 -1
  163. package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
  164. package/dist/types/core/runner.d.ts +1 -0
  165. package/dist/types/core/runner.d.ts.map +1 -1
  166. package/dist/types/events/payloads.d.ts +185 -0
  167. package/dist/types/events/payloads.d.ts.map +1 -1
  168. package/dist/types/events/registry.d.ts +3 -1
  169. package/dist/types/events/registry.d.ts.map +1 -1
  170. package/dist/types/hosting/doorGuard.d.ts +3 -3
  171. package/dist/types/hosting/nodeHost.d.ts +1 -1
  172. package/dist/types/lib/longTimeout.d.ts +35 -0
  173. package/dist/types/lib/longTimeout.d.ts.map +1 -0
  174. package/dist/types/lib/sleep.d.ts +2 -0
  175. package/dist/types/lib/sleep.d.ts.map +1 -1
  176. package/dist/types/mcp/backoff.d.ts +82 -0
  177. package/dist/types/mcp/backoff.d.ts.map +1 -0
  178. package/dist/types/mcp/callLifetime.d.ts +50 -0
  179. package/dist/types/mcp/callLifetime.d.ts.map +1 -0
  180. package/dist/types/mcp/mcpClient.d.ts +4 -1
  181. package/dist/types/mcp/mcpClient.d.ts.map +1 -1
  182. package/dist/types/mcp/requestLedger.d.ts +98 -0
  183. package/dist/types/mcp/requestLedger.d.ts.map +1 -0
  184. package/dist/types/mcp/seriesEvidence.d.ts +103 -0
  185. package/dist/types/mcp/seriesEvidence.d.ts.map +1 -0
  186. package/dist/types/mcp/throttleRetry.d.ts +243 -38
  187. package/dist/types/mcp/throttleRetry.d.ts.map +1 -1
  188. package/dist/types/mcp/types.d.ts +28 -14
  189. package/dist/types/mcp/types.d.ts.map +1 -1
  190. package/dist/types/redaction/knownStrings.d.ts.map +1 -1
  191. package/dist/types/security/PermissionPolicy.d.ts +1 -1
  192. package/dist/types/strategies/attach.d.ts.map +1 -1
  193. package/dist/types/strategies/defaults/chatBubbleLiveStatus.d.ts +1 -1
  194. package/dist/types/strategies/flushDeadline.d.ts +48 -0
  195. package/dist/types/strategies/flushDeadline.d.ts.map +1 -0
  196. package/dist/types/tool-lint/analyze.d.ts +1 -1
  197. package/dist/types/tool-lint/rules.d.ts +3 -3
  198. package/dist/types/tools/requestEvidence.d.ts +79 -0
  199. package/dist/types/tools/requestEvidence.d.ts.map +1 -0
  200. package/package.json +2 -2
@@ -0,0 +1,98 @@
1
+ /**
2
+ * requestLedger — which dispatched tool call an MCP request belongs to, so the
3
+ * retry series that sends it files its attempts into THAT call's run; and when
4
+ * the MCP SDK cancels a request, so the series sending it stops.
5
+ *
6
+ * Pattern: a per-connection ledger + the SDK transport's `send`, watched in place.
7
+ * Role: The middle of the evidence seam (`tools/requestEvidence.ts` is its
8
+ * door). The retry series runs inside the transport's `fetch`, which
9
+ * the MCP SDK calls with a serialized body and nothing else — no tool
10
+ * call, no run. Three hops carry the call down to it, each by an
11
+ * identity the hop already holds:
12
+ *
13
+ * 1. call → params `issue`: the MCP tool keys its ticket by the request's
14
+ * params OBJECT. The SDK puts that very object into the
15
+ * JSON-RPC message it hands the transport.
16
+ * 2. params → id the watched `send` finds the ticket by `message.params`
17
+ * and keys it by the JSON-RPC `id` the SDK assigned, until
18
+ * that send settles.
19
+ * 3. id → series `claim`: the series reads the `id` back out of the body
20
+ * it is about to send.
21
+ *
22
+ * CANCELLATION DOES NOT WAIT ON ATTRIBUTION. Every `tools/call` in flight gets
23
+ * an entry, ticket or not, and the SDK says when it gives a request up: it sends
24
+ * `notifications/cancelled` naming the request's id — on its own timeout, or
25
+ * when the call's signal fires — through this same `send`. The ledger aborts
26
+ * that request's series there and then, so a request nobody waits for is never
27
+ * asked again, even when its params could not be matched to a call.
28
+ *
29
+ * Nothing is added to the wire: the request the server receives is
30
+ * byte-identical, and the SDK's own options keep their meanings. Ids are the
31
+ * client's, one ledger per connection, so concurrent calls — and concurrent
32
+ * runs sharing one client — can never claim each other's request. A request
33
+ * that is not a `tools/call` (a `tools/list`, a notification, a response)
34
+ * claims nothing.
35
+ *
36
+ * `send` is installed as an OWN property of the transport instance — the same
37
+ * object, its own `send` bound to it, so a transport class with `#private`
38
+ * fields works as it always did. Assigning `send` again afterwards THROWS: a
39
+ * send that bypassed the ledger would quietly lose every call's attempts.
40
+ *
41
+ * What it does NOT do: retry, wait, or decide anything. The series is the one
42
+ * retry owner; this only tells it whose attempts it is making, and when the SDK
43
+ * has stopped waiting for them.
44
+ */
45
+ import type { RequestEvidenceSink } from '../tools/requestEvidence.js';
46
+ /** One call's claim on the request it sends. */
47
+ export interface RequestTicket {
48
+ /** Where the request's attempts are filed. */
49
+ readonly sink: RequestEvidenceSink;
50
+ /** What cancels the call's series — the call's own signal, the client's, the call settling. */
51
+ readonly signal?: AbortSignal;
52
+ }
53
+ /** What a series claims for the `tools/call` request it sends. */
54
+ export interface ClaimedRequest {
55
+ /** The ticket a dispatched call issued for this request — absent when none was matched. */
56
+ readonly ticket?: RequestTicket;
57
+ /** Fires when the MCP SDK cancels this request (`notifications/cancelled`). */
58
+ readonly cancelled: AbortSignal;
59
+ }
60
+ /** Per connection: the tickets issued and not yet sent, and the requests being sent. */
61
+ export declare class RequestLedger {
62
+ /** Issued, not yet sent — keyed by the request's params object. Collected with it. */
63
+ private readonly issued;
64
+ /** Tickets a request was bound to. */
65
+ private readonly bound;
66
+ /** Every `tools/call` sent and not yet settled — keyed by its JSON-RPC id. */
67
+ private readonly sending;
68
+ private calls;
69
+ private unboundNamed;
70
+ /** The call about to send `params` files its attempts through `ticket`. */
71
+ issue(params: object, ticket: RequestTicket): void;
72
+ /** Whether a request the transport sent was bound to `ticket`. */
73
+ wasBound(ticket: RequestTicket): boolean;
74
+ /** How many `tools/call` requests the watched transport has sent — matched to a call or not. */
75
+ get toolCallsSent(): number;
76
+ /** `true` the first time it is asked, then never again: an unmatched request is named once per connection. */
77
+ firstUnbound(): boolean;
78
+ /**
79
+ * Watch `transport`'s `send`: install a wrapped `send` as its OWN property, the
80
+ * original bound to the instance itself. Returns the SAME object — or
81
+ * `undefined` when it has no `send` to watch or refuses the property, and
82
+ * then nothing is watched and no call should expect its attempts filed.
83
+ */
84
+ watch<T extends object>(transport: T): T | undefined;
85
+ /**
86
+ * The `tools/call` request `body` carries, while its send runs — its ticket
87
+ * when a call issued one, and the signal its cancellation fires. `undefined`
88
+ * for any other body. Parses only while some request is being sent.
89
+ */
90
+ claim(body: unknown): ClaimedRequest | undefined;
91
+ /** One message through the watched transport. */
92
+ private send;
93
+ /** Register a `tools/call` in flight, with the ticket its params were issued — if any. */
94
+ private bind;
95
+ /** The SDK gave a request up: stop the series still sending it. */
96
+ private cancelIfAsked;
97
+ }
98
+ //# sourceMappingURL=requestLedger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requestLedger.d.ts","sourceRoot":"","sources":["../../../src/mcp/requestLedger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAEvE,gDAAgD;AAChD,MAAM,WAAW,aAAa;IAC5B,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,+FAA+F;IAC/F,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC7B,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,+EAA+E;IAC/E,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC;CACjC;AAgBD,wFAAwF;AACxF,qBAAa,aAAa;IACxB,sFAAsF;IACtF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwC;IAC/D,sCAAsC;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IACtD,8EAA8E;IAC9E,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;IAC1D,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,YAAY,CAAS;IAE7B,2EAA2E;IAC3E,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI;IAIlD,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO;IAIxC,gGAAgG;IAChG,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,8GAA8G;IAC9G,YAAY,IAAI,OAAO;IAMvB;;;;;OAKG;IACH,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IAwBpD;;;;OAIG;IACH,KAAK,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,GAAG,SAAS;IAiBhD,iDAAiD;IACjD,OAAO,CAAC,IAAI;IAgBZ,0FAA0F;IAC1F,OAAO,CAAC,IAAI;IAgBZ,mEAAmE;IACnE,OAAO,CAAC,aAAa;CAQtB"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * seriesEvidence — one MCP request's retry series, written down for its run.
3
+ *
4
+ * Pattern: a collector over footprintjs's attempt records, filed once.
5
+ * Role: The series (`throttleRetry.ts` · `Series`) is the one retry owner and
6
+ * the attempt runner makes one record per try; this turns each record
7
+ * into an allow-listed row and files the request's whole story — its
8
+ * rows, how many were not listed, and how it ended — to the call's sink
9
+ * (`tools/requestEvidence.ts`) exactly ONCE.
10
+ *
11
+ * WHAT A ROW MAY SAY. Numbers and the library's own words; never the server's
12
+ * answer, the call's arguments or an error's text. A failure is a fixed sentence
13
+ * and its category — a network or SDK error message can carry a URL with a token
14
+ * in it, a host's internal name or a server's reply.
15
+ *
16
+ * A RESPONSE IS NOT A SUCCESS. The runner records an attempt that returned a
17
+ * response as `ok` with the reason `succeeded`; here it is `answered`, with the
18
+ * status the server sent — a 503 delivered is `answered` + `503`, never success.
19
+ *
20
+ * EVERY REQUEST SENT IS COUNTED. Each attempt the series started is a row — or,
21
+ * past the cap, one more in `omitted` — so `rows + omitted` is the number of
22
+ * requests the series sent. An attempt a cancellation cuts in flight is a row
23
+ * too (`cut`), exactly as an attempt the deadline cuts is (`timed-out`). A
24
+ * request the series never sent — the next one after a cancelled wait — has no
25
+ * row.
26
+ *
27
+ * A CUT IS NOT A "NOT RUN". An attempt that ended without an answer — cut,
28
+ * timed out, or failed — was sent, and the server may have received it and run
29
+ * it. Its row says so (`remote: 'unknown'`); nothing here records it as not run.
30
+ *
31
+ * WHEN IT FILES. When the series ends — and, for a cancellation, at the moment the
32
+ * signal fires: a cancelled run stops waiting for its stage at once, so a record
33
+ * filed when the series later unwinds would land after the run was saved. The
34
+ * runner makes no record for an attempt it abandons at that moment or for a wait
35
+ * it was cut out of, so those are written here: the cut attempt's row and
36
+ * `during: 'request'`, or `during: 'wait'`. Anything the series reports after it
37
+ * has filed is not part of the request's story any more and is ignored.
38
+ */
39
+ import type { AttemptRecord } from 'footprintjs';
40
+ import type { ToolRequestAttempt, ToolRequestReason } from '../events/payloads.js';
41
+ import { type RequestEvidence, type RequestEvidenceSink } from '../tools/requestEvidence.js';
42
+ /** Where the request went, as a row may say it: the app's label for it, or its origin. */
43
+ export type RequestWhere = Pick<RequestEvidence, 'endpoint' | 'origin'>;
44
+ /** What the series saw of one attempt that its record does not hold. */
45
+ export interface AttemptSeen {
46
+ /** The response's status, when a response arrived. */
47
+ readonly status?: number;
48
+ /** The refusal a rule recognised in that response, when one did. */
49
+ readonly refusal?: {
50
+ readonly kind: 'throttle' | 'session-busy';
51
+ readonly retryAfterMs?: number;
52
+ };
53
+ }
54
+ /** Why the series' `retryOn` said no — the reasons the runner calls `declined`. */
55
+ export type DeclineReason = Extract<ToolRequestReason, 'exhausted' | 'wait-limit' | 'no-time-left' | 'not-replayable' | 'not-retryable'>;
56
+ /** One request's evidence, collected as its series runs and filed once. */
57
+ export declare class SeriesEvidence {
58
+ private readonly sink;
59
+ private readonly where;
60
+ private readonly rows;
61
+ private omitted;
62
+ private last;
63
+ private filed;
64
+ constructor(sink: RequestEvidenceSink, where: RequestWhere);
65
+ /** One attempt as the runner recorded it. */
66
+ attempt(record: AttemptRecord, seen: AttemptSeen | undefined, declined?: DeclineReason): void;
67
+ /**
68
+ * The caller's cancellation cut attempt `n` in flight. It was sent — the
69
+ * server may have it, and may have run it — so it is a row, `cut`, with the
70
+ * remote outcome `unknown`; then the request's end says the same.
71
+ */
72
+ cutInFlight(n: number): void;
73
+ /**
74
+ * The caller's cancellation landed with NO request in flight: between two —
75
+ * `during: 'wait'`, the next request never sent — or before the first, when
76
+ * nothing was sent and there is no `during`. No row is added: there is no
77
+ * request to account for. A request that had already ended keeps its end.
78
+ */
79
+ cancelled(): void;
80
+ /**
81
+ * The series delivered a response. It is the last attempt's — an answer, or a
82
+ * refusal it will not ask again after. A refusal it MEANT to ask again after
83
+ * is delivered when the deadline lands inside the wait: the runner's wait
84
+ * ends early, the series stops, and the end says so (`no-time-left`, during
85
+ * the `wait`).
86
+ */
87
+ delivered(): void;
88
+ /**
89
+ * The series threw. The end is the last attempt's when that attempt ended it
90
+ * (a failure, a timed-out request). The rest is defensive — footprintjs 10.6's
91
+ * runner never throws without a record but for a cancellation, which is filed
92
+ * as one: a deadline that had passed before the first request (`timed-out`,
93
+ * no `during`, nothing sent) or one a future runner reports from inside a wait
94
+ * (`during: 'wait'`); anything else is filed as a failure the record cannot
95
+ * account for, so a request is never left unfiled.
96
+ */
97
+ threw(outOfTime: boolean): void;
98
+ private add;
99
+ private file;
100
+ }
101
+ /** One record as a row — see the module note for what a row may say. */
102
+ export declare function rowOf(record: AttemptRecord, seen: AttemptSeen | undefined, declined?: DeclineReason): ToolRequestAttempt;
103
+ //# sourceMappingURL=seriesEvidence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seriesEvidence.d.ts","sourceRoot":"","sources":["../../../src/mcp/seriesEvidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,KAAK,EACV,kBAAkB,EAGlB,iBAAiB,EAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACzB,MAAM,6BAA6B,CAAC;AAErC,0FAA0F;AAC1F,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,EAAE,UAAU,GAAG,QAAQ,CAAC,CAAC;AAExE,wEAAwE;AACxE,MAAM,WAAW,WAAW;IAC1B,sDAAsD;IACtD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,cAAc,CAAC;QAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACnG;AAED,mFAAmF;AACnF,MAAM,MAAM,aAAa,GAAG,OAAO,CACjC,iBAAiB,EACjB,WAAW,GAAG,YAAY,GAAG,cAAc,GAAG,gBAAgB,GAAG,eAAe,CACjF,CAAC;AAOF,2EAA2E;AAC3E,qBAAa,cAAc;IAMb,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAuB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAL9E,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA4B;IACjD,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,IAAI,CAAiC;IAC7C,OAAO,CAAC,KAAK,CAAS;gBAEO,IAAI,EAAE,mBAAmB,EAAmB,KAAK,EAAE,YAAY;IAE5F,6CAA6C;IAC7C,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,WAAW,GAAG,SAAS,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,IAAI;IAK7F;;;;OAIG;IACH,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAM5B;;;;;OAKG;IACH,SAAS,IAAI,IAAI;IAajB;;;;;;OAMG;IACH,SAAS,IAAI,IAAI;IAajB;;;;;;;;OAQG;IACH,KAAK,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAmB/B,OAAO,CAAC,GAAG;IAMX,OAAO,CAAC,IAAI;CASb;AAcD,wEAAwE;AACxE,wBAAgB,KAAK,CACnB,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,WAAW,GAAG,SAAS,EAC7B,QAAQ,CAAC,EAAE,aAAa,GACvB,kBAAkB,CAqBpB"}
@@ -1,5 +1,6 @@
1
1
  /**
2
- * throttleRetry — when an MCP server says "too many requests", wait and ask again.
2
+ * throttleRetry — when an MCP server refuses a request with a response the
3
+ * retry policy recognises (HTTP 429), wait and ask again.
3
4
  *
4
5
  * ── Why this exists ──────────────────────────────────────────────────────────
5
6
  * Managed MCP gateways enforce per-principal rate limits. A throttled
@@ -9,20 +10,24 @@
9
10
  * tool, or invents an answer. A designed, transient, self-clearing condition
10
11
  * was being turned into a wrong answer.
11
12
  *
12
- * ── Why retrying a 429 is safe, and why the policy is 429-ONLY ───────────────
13
- * **A 429 is a pre-execution rejection.** The rate limiter refused the request
14
- * at the edge; the server never ran the tool. Retrying therefore cannot
15
- * double-execute anything — which is exactly what is NOT true of a 500 or a
13
+ * ── What retrying a 429 assumes, and why the policy is 429-ONLY ─────────────
14
+ * **Automatic 429 retries assume the server rejected the request before
15
+ * executing it.** A rate limiter that refuses at the edge has not run the tool —
16
+ * but HTTP 429 says only that the request was rate-limited (RFC 6585 §4), so the
17
+ * saved response records the assumption's basis (the server's 429), not proof
18
+ * that nothing ran. There is no side-effect guard here: a tool with side
19
+ * effects is retried on 429 like any other today, and `retryOnThrottle: false`
20
+ * turns that off per server. What is certain is the contrast with a 500 or a
16
21
  * timeout, where the call may have half-run and a retry could charge a card
17
22
  * twice.
18
23
  *
19
- * That asymmetry is the whole license for this module, so the policy must never
20
- * widen. Only HTTP 429 retries here. Not 5xx, not network errors, not timeouts
24
+ * That assumption is the whole license for this module, so the policy must
25
+ * never widen. Only HTTP 429 retries here. Not 5xx, not network errors, not timeouts
21
26
  * — those belong to a caller who knows whether the specific tool is idempotent,
22
27
  * and this seam does not. A property test pins the boundary.
23
28
  *
24
29
  * The loop takes its question as a {@link RetryDecision}, so the one other
25
- * refusal a service DOCUMENTS as pre-execution — AgentCore Runtime's "session
30
+ * refusal a service documents as one to retry — AgentCore Runtime's "session
26
31
  * operation in progress" — reuses this loop rather than growing a second one.
27
32
  * That decision is applied only by that vendor's own transport; what
28
33
  * `mcpClient` and `retryingFetch` retry is still a 429 and nothing else.
@@ -43,8 +48,49 @@
43
48
  * that would have died during the wait is simply never the one reused. The
44
49
  * gateway secrecy invariant is untouched: each attempt vends, applies, drops.
45
50
  *
51
+ * ── The loop is footprintjs's attempt runner, one series per call ────────────
52
+ * Each call runs ONE `attempt()` series (footprintjs, used as it ships). Its
53
+ * runner makes an attempt record per try. `onRetry`, before each wait, is what
54
+ * reaches a caller; the RUN gets the records: for a call the agent dispatched,
55
+ * the series files every attempt and how the request ended into that call's
56
+ * run (`seriesEvidence.ts`, through the connection's `requestLedger.ts`). An
57
+ * attempt sends the request once, and an attempt that got a RESPONSE is not an
58
+ * operation that succeeded: a 503 is delivered as the answer it was, never
59
+ * retried — and written down as `answered` with its status, never success.
60
+ * A response a rule's decision recognises is thrown as a refusal that names
61
+ * its kind, and the policy's `retryOn` accepts those refusals and nothing
62
+ * else — so a 5xx, a dropped connection or a timeout ends the series on the
63
+ * attempt it happened in, as it always did. When the
64
+ * series ends on a refusal (attempts spent, a ceiling reached, no time left),
65
+ * the refusal's response is delivered as the server sent it: the caller sees
66
+ * the 429, never an error of ours.
67
+ *
68
+ * ── A fetch that already retries is JOINED, never wrapped ────────────────────
69
+ * A transport whose own fetch runs a series (AgentCore Runtime's session-busy
70
+ * retry) says how to rebuild itself with one more rule (`joinableRetry`).
71
+ * `retryingFetch` over such a fetch — what `mcpClient` applies to every http
72
+ * transport — adds its 429 rule to THAT series instead of starting a second
73
+ * one around it. One series means one attempt count, one waiting total and one
74
+ * deadline per call, by construction: the layers can never multiply requests.
75
+ * The series' FIRST rule holds the call's budget — its `maxAttempts`,
76
+ * `maxWaitMs` and `maxElapsedMs` bound every attempt and wait, whatever the
77
+ * reason. A rule that joins keeps its own values as limits on its own kind:
78
+ * they can stop its retries sooner, never make the call longer.
79
+ *
80
+ * ── The wait: a stated one wins, whole ───────────────────────────────────────
81
+ * Each retry's wait is `statedWaitFirst(retry-after, exponentialBackoff({ …,
82
+ * maxDelayMs }))`: the server's `Retry-After` when it sent one, else our
83
+ * jittered backoff, whose CEILING is capped at `maxDelayMs` before the draw
84
+ * (so capped waits keep their jitter). The cap is on the SCHEDULE only —
85
+ * never on a stated wait — so the footprintjs policy's `maxBackoffMs`,
86
+ * which would cut every wait and send the request again before the server
87
+ * said it may, is left unset. A stated wait too long for `maxWaitMs` or the
88
+ * deadline is never shortened either: the series stops, and the 429 is
89
+ * delivered as the server sent it.
90
+ *
46
91
  * Pattern: Decorator over `fetch`. Role: Layer-3 tool transport.
47
92
  */
93
+ import type { RequestLedger } from './requestLedger.js';
48
94
  /**
49
95
  * The fetch shape the MCP SDK's `fetch` hook uses — deliberately NARROWER
50
96
  * than `gatewayTransport`'s `FetchLike` (no `Request` input), because that is
@@ -54,22 +100,50 @@
54
100
  * supplies fewer.
55
101
  */
56
102
  export type ThrottleFetch = (input: string | URL, init?: RequestInit) => Promise<Response>;
103
+ /**
104
+ * Which refusal a retry answers: HTTP 429 (`'throttle'`), or AgentCore
105
+ * Runtime's "session operation in progress" (`'session-busy'`).
106
+ */
107
+ export type RetryKind = 'throttle' | 'session-busy';
57
108
  /** Reported to {@link ThrottleRetryOptions.onRetry} before each wait. */
58
109
  export interface ThrottleRetryInfo {
110
+ /** Which refusal this retry answers. */
111
+ readonly kind: RetryKind;
59
112
  /** The attempt about to START. `2` is the first retry. */
60
113
  readonly attempt: number;
61
- /** Ceiling in force for this call, including the first attempt. */
114
+ /** Ceiling in force for this refusal, including the first attempt. */
62
115
  readonly maxAttempts: number;
63
116
  /** How long we are about to wait, in milliseconds. */
64
117
  readonly waitMs: number;
65
118
  /** What the server's `Retry-After` asked for, when it sent one. Absent
66
119
  * means the wait below is our own jittered backoff. */
67
120
  readonly retryAfterMs?: number;
68
- /** The endpoint being retried. Carries no credential: the URL is the URL
69
- * the transport was built with, never a signed or tokenised variant. */
121
+ /**
122
+ * The ORIGIN of the endpoint being retried — scheme, host and port, nothing
123
+ * else. Never its path, user info (`user:pass@`), query or fragment: a
124
+ * token, a credential or a customer id can ride in any of them. The empty
125
+ * string when the URL has no origin (a relative one).
126
+ */
70
127
  readonly url: string;
128
+ /**
129
+ * The {@link ThrottleRetryOptions.endpointLabel} you declared for this
130
+ * endpoint — absent when you declared none. Never derived from the URL.
131
+ */
132
+ readonly endpoint?: string;
71
133
  }
72
- /** Fine-tuning for {@link McpClientOptions.retryOnThrottle}. */
134
+ /**
135
+ * Fine-tuning for {@link McpClientOptions.retryOnThrottle}, and — with its own
136
+ * defaults — for `agentCoreRuntimeMcpTransport`'s `retry`. The defaults below
137
+ * are `retryOnThrottle`'s.
138
+ *
139
+ * Every limit here is the CALL's — unless this retry joins a series a
140
+ * transport already runs (an AgentCore Runtime transport under `mcpClient`).
141
+ * Then the transport's own values are the call's limits, and these limit only
142
+ * the 429 retries inside them: each can stop a 429 retry sooner (a 429 is
143
+ * retried only while the call has made fewer attempts than `maxAttempts`, has
144
+ * waited less than `maxWaitMs`, …), never make the call longer. The deadline
145
+ * that cuts a request in flight is the transport's `maxElapsedMs`.
146
+ */
73
147
  export interface ThrottleRetryOptions {
74
148
  /** Total attempts including the first. Default 3. Minimum 1. */
75
149
  readonly maxAttempts?: number;
@@ -84,15 +158,65 @@ export interface ThrottleRetryOptions {
84
158
  */
85
159
  readonly maxWaitMs?: number;
86
160
  /**
87
- * Called before each wait. The per-attempt visibility hook, matching the
88
- * contract `withRetry` and `withCredentialRetry` already use — a decorator
89
- * at a transport boundary reports to its consumer, and emits no events of
90
- * its own.
161
+ * A deadline for the whole call, in milliseconds from its start — requests
162
+ * included, not just waits. A wait that would end past it is never begun
163
+ * (the refusal is delivered at once), and a request still waiting for its
164
+ * answer when it passes is cut: the call fails with the deadline's error.
165
+ * Default: none — `maxWaitMs` is the default rail.
166
+ */
167
+ readonly maxElapsedMs?: number;
168
+ /**
169
+ * The ceiling of the first wait our own backoff draws, in milliseconds, when
170
+ * the server stated none. Default 200.
171
+ */
172
+ readonly baseDelayMs?: number;
173
+ /** How much each backoff ceiling grows over the last. Default 2. At least 1. */
174
+ readonly multiplier?: number;
175
+ /**
176
+ * How a backoff wait is drawn below its ceiling: `'equal'` (the default)
177
+ * waits between half the ceiling and all of it, `'full'` anywhere from zero
178
+ * up to it, `'none'` exactly it. Jitter is what keeps clients refused at the
179
+ * same moment from asking again at the same moment.
180
+ */
181
+ readonly jitter?: 'none' | 'equal' | 'full';
182
+ /**
183
+ * The most one of OUR backoff waits may last, in milliseconds. Default: none.
184
+ *
185
+ * It caps the scheduled wait's ceiling before the jittered draw, so capped
186
+ * waits still spread between half the cap and the cap. It never caps a
187
+ * server's `Retry-After` — unlike footprintjs's `RetryPolicy.maxBackoffMs`,
188
+ * which caps every wait. A stated wait is waited whole; asking sooner than
189
+ * the server said would only spend an attempt on a refusal it announced.
190
+ */
191
+ readonly maxDelayMs?: number;
192
+ /**
193
+ * A name for this endpoint, declared by you, that `onRetry` reports as
194
+ * `endpoint` — so a log line can say which server was retried without
195
+ * carrying any part of its URL past the origin. A dispatched call's saved
196
+ * attempts name the endpoint by it too, in place of the origin. 1–128
197
+ * characters, none of them control characters. Absent, `onRetry` has no
198
+ * `endpoint` field; the library never makes one up from the URL.
199
+ */
200
+ readonly endpointLabel?: string;
201
+ /**
202
+ * A notification before each wait. It is told the refusal's kind, the
203
+ * attempt about to start, the wait, the endpoint's origin and the label you
204
+ * declared for it (`endpointLabel`) — never the URL's path, the request's
205
+ * arguments or the server's answer. It is not told how the call ended. The
206
+ * contract matches what `withRetry` and `withCredentialRetry` already use: a
207
+ * decorator at a transport boundary reports to its consumer.
208
+ *
209
+ * What the RUN keeps is separate and needs no hook: for a call the agent
210
+ * dispatched, the series files every attempt — its outcome, its reason, its
211
+ * wait — and how the request ended, as `agentfootprint.tools.request_attempts`
212
+ * (the label is reported there as `endpoint`).
91
213
  *
92
214
  * A retried call is not invisible without this: the wait lands inside the
93
215
  * tool's `stream.tool_end` `durationMs`, and an exhausted retry still
94
216
  * reaches the model with `error: true`. This hook is what turns "that call
95
217
  * was slow" into "that call was throttled twice".
218
+ *
219
+ * A throw from it is isolated: the call goes on as if it had returned.
96
220
  */
97
221
  readonly onRetry?: (info: ThrottleRetryInfo) => void;
98
222
  }
@@ -116,19 +240,74 @@ export interface RetryVerdict {
116
240
  * The one question the loop asks of each response.
117
241
  *
118
242
  * ── The license every decision must hold ─────────────────────────────────────
119
- * A decision may answer "again" ONLY for a refusal the server made BEFORE it
120
- * ran anything — the property that makes a 429 safe to repeat (see the module
121
- * note). A response that could be the record of half-done work is never one.
243
+ * A decision may answer "again" ONLY for a response the library treats as a
244
+ * refusal made before anything ran — the assumption a 429 retry rests on (see
245
+ * the module note: the 429 is its basis, not proof). A response that could be
246
+ * the record of half-done work is never one.
122
247
  * The library holds exactly two such decisions: {@link throttled} below, and
123
248
  * AgentCore Runtime's documented "session operation in progress" refusal,
124
249
  * which lives with that vendor's adapter (`adapters/mcp/agentcoreRuntime/`).
125
250
  * Each stays ONE small function, so a retry has exactly one place it is
126
- * decided — and one place to route it when retries are written down as
127
- * attempts.
251
+ * decided — and each attempt is written down as one footprintjs attempt
252
+ * record.
253
+ */
254
+ export type RetryDecision = (response: Response,
255
+ /**
256
+ * The request's signal. It fires when the caller cancels or the call's
257
+ * deadline passes; a decision that reads the body must stop reading then,
258
+ * and release what it read from.
128
259
  */
129
- export type RetryDecision = (response: Response) => RetryVerdict | undefined | Promise<RetryVerdict | undefined>;
260
+ signal?: AbortSignal) => RetryVerdict | undefined | Promise<RetryVerdict | undefined>;
130
261
  /** HTTP 429, with the server's own `Retry-After` when it sent one. */
131
262
  export declare function throttled(response: Response): RetryVerdict | undefined;
263
+ /**
264
+ * @internal What a rule's options fall back to. `Infinity` means none: no
265
+ * deadline (`maxElapsedMs`), no cap on the scheduled wait (`maxDelayMs`).
266
+ */
267
+ export interface RetryDefaults {
268
+ readonly maxAttempts: number;
269
+ readonly maxWaitMs: number;
270
+ readonly maxElapsedMs: number;
271
+ readonly baseDelayMs: number;
272
+ readonly multiplier: number;
273
+ readonly jitter: 'none' | 'equal' | 'full';
274
+ readonly maxDelayMs: number;
275
+ }
276
+ /**
277
+ * `retryOnThrottle`'s defaults — unchanged since 8.11.0: 3 attempts, a 200 ms
278
+ * backoff doubling with equal jitter (100–200 ms, then 200–400 ms), never more
279
+ * than 10 s of waiting in total. No deadline and no cap on one wait.
280
+ */
281
+ export declare const THROTTLE_RETRY_DEFAULTS: RetryDefaults;
282
+ /**
283
+ * @internal One refusal a series may retry: the decision that recognises it,
284
+ * the kind it reports as, and the limits and backoff it retries by.
285
+ */
286
+ export interface RetryRule {
287
+ readonly kind: RetryKind;
288
+ readonly decide: RetryDecision;
289
+ /** Total attempts while this refusal is the reason to go on. ≥ 1; `Infinity` is no count. */
290
+ readonly maxAttempts: number;
291
+ readonly maxWaitMs: number;
292
+ readonly maxElapsedMs: number;
293
+ readonly maxDelayMs: number;
294
+ readonly baseDelayMs: number;
295
+ readonly multiplier: number;
296
+ readonly jitter: 'none' | 'equal' | 'full';
297
+ /** The caller's own name for the endpoint, reported as `endpoint`. */
298
+ readonly endpointLabel?: string;
299
+ readonly onRetry?: (info: ThrottleRetryInfo) => void;
300
+ }
301
+ /**
302
+ * @internal A rule from a caller's options — `undefined` when retry is off
303
+ * (`false`). An option field left out, or set to `undefined`, takes its
304
+ * default. `maxAttempts` and `maxWaitMs` keep the clamps they always had (below
305
+ * 1 reads as 1, below 0 as 0).
306
+ *
307
+ * @throws TypeError, when the rule is BUILT, for a value the schedule cannot
308
+ * mean — named by option, never echoing a value that is not a number.
309
+ */
310
+ export declare function retryRule(kind: RetryKind, decide: RetryDecision, config: RetryOnThrottle | undefined, defaults: RetryDefaults, where: string): RetryRule | undefined;
132
311
  /**
133
312
  * Wrap a `fetch` so HTTP 429 responses are retried, honouring `Retry-After`.
134
313
  *
@@ -136,6 +315,10 @@ export declare function throttled(response: Response): RetryVerdict | undefined;
136
315
  * so a transport that passed no custom fetch keeps passing none and its
137
316
  * behaviour is byte-identical to before this existed.
138
317
  *
318
+ * When `inner` already runs a retry series of its own (an AgentCore Runtime
319
+ * transport's fetch), the 429 rule JOINS that series rather than wrapping it,
320
+ * so the two can never multiply requests — see the module note.
321
+ *
139
322
  * ── Why this is public ───────────────────────────────────────────────────────
140
323
  * `mcpClient({ transport })` applies it for you, ON by default. `mcpClient({
141
324
  * connection })` cannot: the library builds no transport on that arm, so there
@@ -157,26 +340,48 @@ export declare function throttled(response: Response): RetryVerdict | undefined;
157
340
  * @param inner the fetch to wrap. `undefined` means the global `fetch`,
158
341
  * resolved at CALL time so a later polyfill still wins.
159
342
  * @param config `true` / `undefined` for the defaults, `false` to get `inner`
160
- * back unchanged, or an object to tune the ceilings.
343
+ * back unchanged, or an object to tune the ceilings and the backoff.
344
+ * @throws TypeError when an option is outside its range — here, when the fetch
345
+ * is built, never at the first call.
161
346
  */
162
347
  export declare function retryingFetch(inner: ThrottleFetch | undefined, config: RetryOnThrottle | undefined): ThrottleFetch | undefined;
163
348
  /**
164
- * The bounded loop itself, asking `decide` of every response.
165
- *
166
- * {@link retryingFetch} is this loop asking {@link throttled}. A vendor adapter
167
- * whose service documents a refusal of its own — one made before anything ran —
168
- * passes its decision here instead of writing a second loop, so the ceilings,
169
- * the `Retry-After` rail, the replay check, the abort and the `onRetry` report
170
- * stay one implementation.
171
- *
172
- * `decide` is asked only when a retry could actually follow — attempts left, a
173
- * body that can be sent again, no abort — so a decision that has to read the
174
- * response pays for that only when its answer can matter.
175
- *
176
- * @internal Public to adapters, not to the door: the decision is the vendor's
177
- * fact, and each one is reviewed against the license on {@link RetryDecision}.
349
+ * @internal What one call's series is built from: the rules it asks, in order,
350
+ * and the connection's ledger — which tool call each request belongs to, so the
351
+ * series can file its attempts into that call's run (`requestLedger.ts`).
352
+ */
353
+ export interface SeriesSpec {
354
+ readonly rules: readonly RetryRule[];
355
+ readonly ledger?: RequestLedger;
356
+ }
357
+ /** @internal What a joinable fetch's series can be rebuilt with: one more rule, or a ledger. */
358
+ export type SeriesJoin = {
359
+ readonly rule: RetryRule;
360
+ } | {
361
+ readonly ledger: RequestLedger;
362
+ };
363
+ /** @internal `spec` with `join` in it. */
364
+ export declare function joinedSpec(spec: SeriesSpec, join: SeriesJoin): SeriesSpec;
365
+ /**
366
+ * @internal Declare that `fetch` runs its retries in ONE series, and how to
367
+ * rebuild it with one more rule — or with a ledger — in that same series.
368
+ * `retryingFetch` joins such a fetch instead of wrapping it. A transport whose
369
+ * public fetch wraps its series (a session applied around it, its answers
370
+ * rewritten after it) uses this so the rule lands INSIDE that wrapping.
371
+ */
372
+ export declare function joinableRetry(fetch: ThrottleFetch, rebuild: (join: SeriesJoin) => ThrottleFetch): ThrottleFetch;
373
+ /**
374
+ * @internal `fetch` rebuilt so its series files each request's attempts through
375
+ * `ledger` — or `undefined` when `fetch` runs no series (retry off), so there
376
+ * is nothing to file and the caller keeps `fetch` as it is.
377
+ */
378
+ export declare function ledgeredFetch(fetch: ThrottleFetch, ledger: RequestLedger): ThrottleFetch | undefined;
379
+ /**
380
+ * @internal The one series per call over `inner`, asking `spec.rules` in order —
381
+ * `inner` itself when there are none. The first rule holds the call's budget;
382
+ * see the module note. The result is joinable.
178
383
  */
179
- export declare function retryingFetchWhen(inner: ThrottleFetch | undefined, config: RetryOnThrottle | undefined, decide: RetryDecision): ThrottleFetch | undefined;
384
+ export declare function retryingFetchFor(inner: ThrottleFetch, spec: SeriesSpec): ThrottleFetch;
180
385
  /**
181
386
  * `Retry-After` in either legal form: delta-seconds (`"2"`) or an HTTP-date
182
387
  * (`"Wed, 21 Oct 2026 07:28:00 GMT"`). Anything else is treated as absent so a
@@ -1 +1 @@
1
- {"version":3,"file":"throttleRetry.d.ts","sourceRoot":"","sources":["../../../src/mcp/throttleRetry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAIH;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAI3F,yEAAyE;AACzE,MAAM,WAAW,iBAAiB;IAChC,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mEAAmE;IACnE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;4DACwD;IACxD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;6EACyE;IACzE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,gEAAgE;AAChE,MAAM,WAAW,oBAAoB;IACnC,gEAAgE;IAChE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;;;OAQG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,CAAC;CACtD;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,oBAAoB,CAAC;AA4B7D;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,aAAa,GAAG,CAC1B,QAAQ,EAAE,QAAQ,KACf,YAAY,GAAG,SAAS,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAAC;AAElE,sEAAsE;AACtE,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,YAAY,GAAG,SAAS,CAItE;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,aAAa,GAAG,SAAS,EAChC,MAAM,EAAE,eAAe,GAAG,SAAS,GAClC,aAAa,GAAG,SAAS,CAE3B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,aAAa,GAAG,SAAS,EAChC,MAAM,EAAE,eAAe,GAAG,SAAS,EACnC,MAAM,EAAE,aAAa,GACpB,aAAa,GAAG,SAAS,CA2C3B;AAID;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAOpF"}
1
+ {"version":3,"file":"throttleRetry.d.ts","sourceRoot":"","sources":["../../../src/mcp/throttleRetry.ts"],"names":[],"mappings":"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"}