agentfootprint 11.2.0 → 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 (157) hide show
  1. package/AGENTS.md +1 -1
  2. package/CAPABILITIES.md +2 -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 +6 -5
  8. package/dist/adapters/mcp/agentcoreRuntime/sessionBusy.js.map +1 -1
  9. package/dist/adapters/mcp/agentcoreRuntime/transport.js +8 -6
  10. package/dist/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
  11. package/dist/core/agent/buildToolRegistry.js +1 -1
  12. package/dist/core/agent/buildToolRegistry.js.map +1 -1
  13. package/dist/core/agent/evidence/evidenceIndex.js +30 -2
  14. package/dist/core/agent/evidence/evidenceIndex.js.map +1 -1
  15. package/dist/core/agent/evidence/extract.js +34 -5
  16. package/dist/core/agent/evidence/extract.js.map +1 -1
  17. package/dist/core/agent/evidence/figures.js +31 -3
  18. package/dist/core/agent/evidence/figures.js.map +1 -1
  19. package/dist/core/agent/evidence/numberPrecision.js +58 -2
  20. package/dist/core/agent/evidence/numberPrecision.js.map +1 -1
  21. package/dist/core/agent/stages/route.js +2 -1
  22. package/dist/core/agent/stages/route.js.map +1 -1
  23. package/dist/core/agent/stages/toolCalls.js +14 -1
  24. package/dist/core/agent/stages/toolCalls.js.map +1 -1
  25. package/dist/core/slots/buildToolsSlot.js +1 -1
  26. package/dist/core/slots/buildToolsSlot.js.map +1 -1
  27. package/dist/esm/adapters/identity/jwks.d.ts +2 -2
  28. package/dist/esm/adapters/identity/verify/claims.d.ts +3 -3
  29. package/dist/esm/adapters/identity/verify/claims.js +3 -3
  30. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.d.ts +3 -2
  31. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js +3 -2
  32. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
  33. package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts +6 -5
  34. package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.js +6 -5
  35. package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.js.map +1 -1
  36. package/dist/esm/adapters/mcp/agentcoreRuntime/transport.d.ts +3 -1
  37. package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js +9 -7
  38. package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
  39. package/dist/esm/core/agent/buildToolRegistry.js +1 -1
  40. package/dist/esm/core/agent/buildToolRegistry.js.map +1 -1
  41. package/dist/esm/core/agent/evidence/evidenceIndex.d.ts +12 -2
  42. package/dist/esm/core/agent/evidence/evidenceIndex.js +30 -2
  43. package/dist/esm/core/agent/evidence/evidenceIndex.js.map +1 -1
  44. package/dist/esm/core/agent/evidence/extract.js +35 -6
  45. package/dist/esm/core/agent/evidence/extract.js.map +1 -1
  46. package/dist/esm/core/agent/evidence/figures.d.ts +6 -0
  47. package/dist/esm/core/agent/evidence/figures.js +32 -4
  48. package/dist/esm/core/agent/evidence/figures.js.map +1 -1
  49. package/dist/esm/core/agent/evidence/numberPrecision.d.ts +28 -1
  50. package/dist/esm/core/agent/evidence/numberPrecision.js +56 -1
  51. package/dist/esm/core/agent/evidence/numberPrecision.js.map +1 -1
  52. package/dist/esm/core/agent/stages/route.js +2 -1
  53. package/dist/esm/core/agent/stages/route.js.map +1 -1
  54. package/dist/esm/core/agent/stages/toolCalls.js +14 -1
  55. package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
  56. package/dist/esm/core/slots/buildToolsSlot.js +1 -1
  57. package/dist/esm/core/slots/buildToolsSlot.js.map +1 -1
  58. package/dist/esm/events/payloads.d.ts +185 -0
  59. package/dist/esm/events/registry.d.ts +3 -1
  60. package/dist/esm/events/registry.js +2 -0
  61. package/dist/esm/events/registry.js.map +1 -1
  62. package/dist/esm/hosting/doorGuard.d.ts +3 -3
  63. package/dist/esm/hosting/doorGuard.js +2 -2
  64. package/dist/esm/hosting/nodeHost.d.ts +1 -1
  65. package/dist/esm/mcp/callLifetime.d.ts +49 -0
  66. package/dist/esm/mcp/callLifetime.js +99 -0
  67. package/dist/esm/mcp/callLifetime.js.map +1 -0
  68. package/dist/esm/mcp/mcpClient.d.ts +4 -1
  69. package/dist/esm/mcp/mcpClient.js +70 -28
  70. package/dist/esm/mcp/mcpClient.js.map +1 -1
  71. package/dist/esm/mcp/requestLedger.d.ts +97 -0
  72. package/dist/esm/mcp/requestLedger.js +192 -0
  73. package/dist/esm/mcp/requestLedger.js.map +1 -0
  74. package/dist/esm/mcp/seriesEvidence.d.ts +102 -0
  75. package/dist/esm/mcp/seriesEvidence.js +246 -0
  76. package/dist/esm/mcp/seriesEvidence.js.map +1 -0
  77. package/dist/esm/mcp/throttleRetry.d.ts +70 -35
  78. package/dist/esm/mcp/throttleRetry.js +181 -54
  79. package/dist/esm/mcp/throttleRetry.js.map +1 -1
  80. package/dist/esm/mcp/types.d.ts +12 -7
  81. package/dist/esm/redaction/knownStrings.js +29 -0
  82. package/dist/esm/redaction/knownStrings.js.map +1 -1
  83. package/dist/esm/security/PermissionPolicy.d.ts +1 -1
  84. package/dist/esm/security/PermissionPolicy.js +1 -1
  85. package/dist/esm/strategies/defaults/chatBubbleLiveStatus.d.ts +1 -1
  86. package/dist/esm/strategies/defaults/chatBubbleLiveStatus.js +1 -1
  87. package/dist/esm/tool-lint/analyze.d.ts +1 -1
  88. package/dist/esm/tool-lint/analyze.js +1 -1
  89. package/dist/esm/tool-lint/rules.d.ts +3 -3
  90. package/dist/esm/tool-lint/rules.js +3 -3
  91. package/dist/esm/tools/requestEvidence.d.ts +78 -0
  92. package/dist/esm/tools/requestEvidence.js +331 -0
  93. package/dist/esm/tools/requestEvidence.js.map +1 -0
  94. package/dist/events/registry.js +2 -0
  95. package/dist/events/registry.js.map +1 -1
  96. package/dist/hosting/doorGuard.js +2 -2
  97. package/dist/mcp/callLifetime.js +103 -0
  98. package/dist/mcp/callLifetime.js.map +1 -0
  99. package/dist/mcp/mcpClient.js +69 -27
  100. package/dist/mcp/mcpClient.js.map +1 -1
  101. package/dist/mcp/requestLedger.js +196 -0
  102. package/dist/mcp/requestLedger.js.map +1 -0
  103. package/dist/mcp/seriesEvidence.js +251 -0
  104. package/dist/mcp/seriesEvidence.js.map +1 -0
  105. package/dist/mcp/throttleRetry.js +184 -55
  106. package/dist/mcp/throttleRetry.js.map +1 -1
  107. package/dist/redaction/knownStrings.js +29 -0
  108. package/dist/redaction/knownStrings.js.map +1 -1
  109. package/dist/security/PermissionPolicy.js +1 -1
  110. package/dist/strategies/defaults/chatBubbleLiveStatus.js +1 -1
  111. package/dist/tool-lint/analyze.js +1 -1
  112. package/dist/tool-lint/rules.js +3 -3
  113. package/dist/tools/requestEvidence.js +337 -0
  114. package/dist/tools/requestEvidence.js.map +1 -0
  115. package/dist/types/adapters/identity/jwks.d.ts +2 -2
  116. package/dist/types/adapters/identity/verify/claims.d.ts +3 -3
  117. package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts +3 -2
  118. package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts.map +1 -1
  119. package/dist/types/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts +6 -5
  120. package/dist/types/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts.map +1 -1
  121. package/dist/types/adapters/mcp/agentcoreRuntime/transport.d.ts +3 -1
  122. package/dist/types/adapters/mcp/agentcoreRuntime/transport.d.ts.map +1 -1
  123. package/dist/types/core/agent/evidence/evidenceIndex.d.ts +12 -2
  124. package/dist/types/core/agent/evidence/evidenceIndex.d.ts.map +1 -1
  125. package/dist/types/core/agent/evidence/extract.d.ts.map +1 -1
  126. package/dist/types/core/agent/evidence/figures.d.ts +6 -0
  127. package/dist/types/core/agent/evidence/figures.d.ts.map +1 -1
  128. package/dist/types/core/agent/evidence/numberPrecision.d.ts +28 -1
  129. package/dist/types/core/agent/evidence/numberPrecision.d.ts.map +1 -1
  130. package/dist/types/core/agent/stages/route.d.ts.map +1 -1
  131. package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
  132. package/dist/types/events/payloads.d.ts +185 -0
  133. package/dist/types/events/payloads.d.ts.map +1 -1
  134. package/dist/types/events/registry.d.ts +3 -1
  135. package/dist/types/events/registry.d.ts.map +1 -1
  136. package/dist/types/hosting/doorGuard.d.ts +3 -3
  137. package/dist/types/hosting/nodeHost.d.ts +1 -1
  138. package/dist/types/mcp/callLifetime.d.ts +50 -0
  139. package/dist/types/mcp/callLifetime.d.ts.map +1 -0
  140. package/dist/types/mcp/mcpClient.d.ts +4 -1
  141. package/dist/types/mcp/mcpClient.d.ts.map +1 -1
  142. package/dist/types/mcp/requestLedger.d.ts +98 -0
  143. package/dist/types/mcp/requestLedger.d.ts.map +1 -0
  144. package/dist/types/mcp/seriesEvidence.d.ts +103 -0
  145. package/dist/types/mcp/seriesEvidence.d.ts.map +1 -0
  146. package/dist/types/mcp/throttleRetry.d.ts +70 -35
  147. package/dist/types/mcp/throttleRetry.d.ts.map +1 -1
  148. package/dist/types/mcp/types.d.ts +12 -7
  149. package/dist/types/mcp/types.d.ts.map +1 -1
  150. package/dist/types/redaction/knownStrings.d.ts.map +1 -1
  151. package/dist/types/security/PermissionPolicy.d.ts +1 -1
  152. package/dist/types/strategies/defaults/chatBubbleLiveStatus.d.ts +1 -1
  153. package/dist/types/tool-lint/analyze.d.ts +1 -1
  154. package/dist/types/tool-lint/rules.d.ts +3 -3
  155. package/dist/types/tools/requestEvidence.d.ts +79 -0
  156. package/dist/types/tools/requestEvidence.d.ts.map +1 -0
  157. package/package.json +1 -1
@@ -0,0 +1,246 @@
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 { MAX_REQUEST_ATTEMPT_ROWS, } from '../tools/requestEvidence.js';
40
+ const FAILED = 'The request failed before an answer arrived. Its error is not kept.';
41
+ const OUT_OF_TIME = 'The call ran out of time before an answer arrived.';
42
+ /** One request's evidence, collected as its series runs and filed once. */
43
+ export class SeriesEvidence {
44
+ sink;
45
+ where;
46
+ rows = [];
47
+ omitted = 0;
48
+ last;
49
+ filed = false;
50
+ constructor(sink, where) {
51
+ this.sink = sink;
52
+ this.where = where;
53
+ }
54
+ /** One attempt as the runner recorded it. */
55
+ attempt(record, seen, declined) {
56
+ if (this.filed)
57
+ return;
58
+ this.add(rowOf(record, seen, declined));
59
+ }
60
+ /**
61
+ * The caller's cancellation cut attempt `n` in flight. It was sent — the
62
+ * server may have it, and may have run it — so it is a row, `cut`, with the
63
+ * remote outcome `unknown`; then the request's end says the same.
64
+ */
65
+ cutInFlight(n) {
66
+ if (this.filed)
67
+ return;
68
+ this.add({ attempt: n, outcome: 'cut', reason: 'cancelled', remote: 'unknown' });
69
+ this.file({ outcome: 'cut', reason: 'cancelled', during: 'request', remote: 'unknown' });
70
+ }
71
+ /**
72
+ * The caller's cancellation landed with NO request in flight: between two —
73
+ * `during: 'wait'`, the next request never sent — or before the first, when
74
+ * nothing was sent and there is no `during`. No row is added: there is no
75
+ * request to account for. A request that had already ended keeps its end.
76
+ */
77
+ cancelled() {
78
+ const last = this.last;
79
+ if (last !== undefined && last.reason !== 'retryable') {
80
+ this.file(endOf(last));
81
+ return;
82
+ }
83
+ this.file({
84
+ outcome: 'cancelled',
85
+ reason: 'cancelled',
86
+ ...(last !== undefined && { during: 'wait' }),
87
+ });
88
+ }
89
+ /**
90
+ * The series delivered a response. It is the last attempt's — an answer, or a
91
+ * refusal it will not ask again after. A refusal it MEANT to ask again after
92
+ * is delivered when the deadline lands inside the wait: the runner's wait
93
+ * ends early, the series stops, and the end says so (`no-time-left`, during
94
+ * the `wait`).
95
+ */
96
+ delivered() {
97
+ const last = this.last;
98
+ if (last === undefined) {
99
+ this.file(UNACCOUNTED);
100
+ return;
101
+ }
102
+ this.file(last.reason === 'retryable'
103
+ ? { ...endOf(last), reason: 'no-time-left', during: 'wait' }
104
+ : endOf(last));
105
+ }
106
+ /**
107
+ * The series threw. The end is the last attempt's when that attempt ended it
108
+ * (a failure, a timed-out request). The rest is defensive — footprintjs 10.6's
109
+ * runner never throws without a record but for a cancellation, which is filed
110
+ * as one: a deadline that had passed before the first request (`timed-out`,
111
+ * no `during`, nothing sent) or one a future runner reports from inside a wait
112
+ * (`during: 'wait'`); anything else is filed as a failure the record cannot
113
+ * account for, so a request is never left unfiled.
114
+ */
115
+ threw(outOfTime) {
116
+ const last = this.last;
117
+ if (last !== undefined && last.reason !== 'retryable') {
118
+ this.file(endOf(last));
119
+ return;
120
+ }
121
+ if (!outOfTime) {
122
+ this.file(UNACCOUNTED);
123
+ return;
124
+ }
125
+ this.file({
126
+ outcome: 'timed-out',
127
+ reason: 'no-time-left',
128
+ failure: 'timeout',
129
+ ...(last !== undefined && { during: 'wait' }),
130
+ error: { message: OUT_OF_TIME, code: 'timeout' },
131
+ });
132
+ }
133
+ add(row) {
134
+ this.last = row;
135
+ if (this.rows.length < MAX_REQUEST_ATTEMPT_ROWS)
136
+ this.rows.push(row);
137
+ else
138
+ this.omitted += 1;
139
+ }
140
+ file(end) {
141
+ if (this.filed)
142
+ return;
143
+ this.filed = true;
144
+ try {
145
+ this.sink.file({ ...this.where, attempts: [...this.rows], omitted: this.omitted, end });
146
+ }
147
+ catch {
148
+ // The library's sink never throws; one that does must not fail the call.
149
+ }
150
+ }
151
+ }
152
+ /**
153
+ * An end no attempt accounts for — never seen; kept so a request is never left
154
+ * unfiled, and never claiming more than is known.
155
+ */
156
+ const UNACCOUNTED = {
157
+ outcome: 'failed',
158
+ reason: 'not-retryable',
159
+ failure: 'unknown',
160
+ error: { message: FAILED, code: 'unknown' },
161
+ remote: 'unknown',
162
+ };
163
+ /** One record as a row — see the module note for what a row may say. */
164
+ export function rowOf(record, seen, declined) {
165
+ const outcome = outcomeOf(record, seen);
166
+ const reason = reasonOf(record, declined);
167
+ const refusal = outcome === 'refused' ? seen?.refusal : undefined;
168
+ return {
169
+ attempt: record.attempt,
170
+ outcome,
171
+ reason,
172
+ ...((outcome === 'answered' || outcome === 'refused') &&
173
+ seen?.status !== undefined && { status: seen.status }),
174
+ ...(refusal !== undefined && { kind: refusal.kind }),
175
+ ...(outcome !== 'answered' &&
176
+ outcome !== 'cut' &&
177
+ record.category !== undefined && { failure: record.category }),
178
+ ...(reason === 'retryable' && { waitMs: record.delayMs ?? 0 }),
179
+ ...(refusal?.retryAfterMs !== undefined && { retryAfterMs: refusal.retryAfterMs }),
180
+ ...((outcome === 'failed' || outcome === 'timed-out') && {
181
+ error: errorOf(outcome, record.category),
182
+ }),
183
+ ...(noAnswer(outcome) && { remote: 'unknown' }),
184
+ };
185
+ }
186
+ /** An attempt that ended without an answer — the server may have run it, or not. */
187
+ function noAnswer(outcome) {
188
+ return outcome === 'failed' || outcome === 'timed-out' || outcome === 'cut';
189
+ }
190
+ function outcomeOf(record, seen) {
191
+ switch (record.outcome) {
192
+ case 'ok':
193
+ return 'answered';
194
+ case 'timeout':
195
+ return 'timed-out';
196
+ case 'failed':
197
+ return seen?.refusal !== undefined ? 'refused' : 'failed';
198
+ case 'aborted':
199
+ // Cut in flight by the series' cancellation. The cancellation itself files
200
+ // this row first (`cutInFlight`), so the record is seen only if it did not.
201
+ return 'cut';
202
+ default:
203
+ // `paused` cannot happen inside a fetch.
204
+ return 'failed';
205
+ }
206
+ }
207
+ function reasonOf(record, declined) {
208
+ if (record.outcome === 'ok')
209
+ return 'answered';
210
+ if (record.next === 'retry')
211
+ return 'retryable';
212
+ if (record.outcome === 'timeout')
213
+ return 'no-time-left';
214
+ switch (record.reason) {
215
+ case 'exhausted':
216
+ return 'exhausted';
217
+ case 'no-time-left':
218
+ return 'no-time-left';
219
+ case 'aborted':
220
+ return 'cancelled';
221
+ case 'declined':
222
+ return declined ?? 'not-retryable';
223
+ default:
224
+ return 'not-retryable';
225
+ }
226
+ }
227
+ function errorOf(outcome, category) {
228
+ return outcome === 'timed-out'
229
+ ? { message: OUT_OF_TIME, code: category ?? 'timeout' }
230
+ : { message: FAILED, code: category ?? 'unknown' };
231
+ }
232
+ /** How a request ended, when it ended with its last attempt. */
233
+ function endOf(last) {
234
+ const { outcome, reason, status, kind, failure, error, remote } = last;
235
+ return {
236
+ outcome,
237
+ reason,
238
+ ...(status !== undefined && { status }),
239
+ ...(kind !== undefined && { kind }),
240
+ ...(failure !== undefined && { failure }),
241
+ ...((outcome === 'timed-out' || outcome === 'cut') && { during: 'request' }),
242
+ ...(error !== undefined && { error }),
243
+ ...(remote !== undefined && { remote }),
244
+ };
245
+ }
246
+ //# sourceMappingURL=seriesEvidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seriesEvidence.js","sourceRoot":"","sources":["../../../src/mcp/seriesEvidence.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  /**
2
- * throttleRetry — when an MCP server refuses a request before running it, wait
3
- * 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.
4
4
  *
5
5
  * ── Why this exists ──────────────────────────────────────────────────────────
6
6
  * Managed MCP gateways enforce per-principal rate limits. A throttled
@@ -10,20 +10,24 @@
10
10
  * tool, or invents an answer. A designed, transient, self-clearing condition
11
11
  * was being turned into a wrong answer.
12
12
  *
13
- * ── Why retrying a 429 is safe, and why the policy is 429-ONLY ───────────────
14
- * **A 429 is a pre-execution rejection.** The rate limiter refused the request
15
- * at the edge; the server never ran the tool. Retrying therefore cannot
16
- * 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
17
21
  * timeout, where the call may have half-run and a retry could charge a card
18
22
  * twice.
19
23
  *
20
- * That asymmetry is the whole license for this module, so the policy must never
21
- * 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
22
26
  * — those belong to a caller who knows whether the specific tool is idempotent,
23
27
  * and this seam does not. A property test pins the boundary.
24
28
  *
25
29
  * The loop takes its question as a {@link RetryDecision}, so the one other
26
- * refusal a service DOCUMENTS as pre-execution — AgentCore Runtime's "session
30
+ * refusal a service documents as one to retry — AgentCore Runtime's "session
27
31
  * operation in progress" — reuses this loop rather than growing a second one.
28
32
  * That decision is applied only by that vendor's own transport; what
29
33
  * `mcpClient` and `retryingFetch` retry is still a 429 and nothing else.
@@ -46,10 +50,13 @@
46
50
  *
47
51
  * ── The loop is footprintjs's attempt runner, one series per call ────────────
48
52
  * Each call runs ONE `attempt()` series (footprintjs, used as it ships). Its
49
- * runner makes an attempt record per try; they stay inside this module for
50
- * now — only `onRetry`, before each wait, reaches a caller. An attempt sends
51
- * the request once, and an attempt that got a RESPONSE is not an operation
52
- * that succeeded: a 503 is delivered as the answer it was, never retried.
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.
53
60
  * A response a rule's decision recognises is thrown as a refusal that names
54
61
  * its kind, and the policy's `retryOn` accepts those refusals and nothing
55
62
  * else — so a 5xx, a dropped connection or a timeout ends the series on the
@@ -83,6 +90,7 @@
83
90
  *
84
91
  * Pattern: Decorator over `fetch`. Role: Layer-3 tool transport.
85
92
  */
93
+ import type { RequestLedger } from './requestLedger.js';
86
94
  /**
87
95
  * The fetch shape the MCP SDK's `fetch` hook uses — deliberately NARROWER
88
96
  * than `gatewayTransport`'s `FetchLike` (no `Request` input), because that is
@@ -184,21 +192,24 @@ export interface ThrottleRetryOptions {
184
192
  /**
185
193
  * A name for this endpoint, declared by you, that `onRetry` reports as
186
194
  * `endpoint` — so a log line can say which server was retried without
187
- * carrying any part of its URL past the origin. 1–128 characters, none of
188
- * them control characters. Absent, `onRetry` has no `endpoint` field; the
189
- * library never makes one up from the URL.
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.
190
199
  */
191
200
  readonly endpointLabel?: string;
192
201
  /**
193
- * A notification before each wait — and, today, the ONLY retry report a
194
- * caller gets. It is told the refusal's kind, the attempt about to start,
195
- * the wait, the endpoint's origin and the label you declared for it
196
- * (`endpointLabel`) — never the URL's path, the request's
197
- * arguments or the server's answer. The series' final outcome and the
198
- * attempt records footprintjs's runner makes for each try are NOT passed on
199
- * yet. The contract matches what `withRetry` and `withCredentialRetry`
200
- * already use: a decorator at a transport boundary reports to its consumer,
201
- * and emits no events of its own.
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`).
202
213
  *
203
214
  * A retried call is not invisible without this: the wait lands inside the
204
215
  * tool's `stream.tool_end` `durationMs`, and an exhausted retry still
@@ -229,9 +240,10 @@ export interface RetryVerdict {
229
240
  * The one question the loop asks of each response.
230
241
  *
231
242
  * ── The license every decision must hold ─────────────────────────────────────
232
- * A decision may answer "again" ONLY for a refusal the server made BEFORE it
233
- * ran anything — the property that makes a 429 safe to repeat (see the module
234
- * 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.
235
247
  * The library holds exactly two such decisions: {@link throttled} below, and
236
248
  * AgentCore Runtime's documented "session operation in progress" refusal,
237
249
  * which lives with that vendor's adapter (`adapters/mcp/agentcoreRuntime/`).
@@ -333,20 +345,43 @@ export declare function retryRule(kind: RetryKind, decide: RetryDecision, config
333
345
  * is built, never at the first call.
334
346
  */
335
347
  export declare function retryingFetch(inner: ThrottleFetch | undefined, config: RetryOnThrottle | undefined): ThrottleFetch | undefined;
348
+ /**
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;
336
365
  /**
337
366
  * @internal Declare that `fetch` runs its retries in ONE series, and how to
338
- * rebuild it with one more rule in that same series. `retryingFetch` joins such
339
- * a fetch instead of wrapping it. A transport whose public fetch wraps its
340
- * series (a session applied around it, its answers rewritten after it) uses
341
- * this so the rule lands INSIDE that wrapping.
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.
342
377
  */
343
- export declare function joinableRetry(fetch: ThrottleFetch, join: (rule: RetryRule) => ThrottleFetch): ThrottleFetch;
378
+ export declare function ledgeredFetch(fetch: ThrottleFetch, ledger: RequestLedger): ThrottleFetch | undefined;
344
379
  /**
345
- * @internal The one series per call over `inner`, asking `rules` in order —
380
+ * @internal The one series per call over `inner`, asking `spec.rules` in order —
346
381
  * `inner` itself when there are none. The first rule holds the call's budget;
347
382
  * see the module note. The result is joinable.
348
383
  */
349
- export declare function retryingFetchFor(inner: ThrottleFetch, rules: readonly RetryRule[]): ThrottleFetch;
384
+ export declare function retryingFetchFor(inner: ThrottleFetch, spec: SeriesSpec): ThrottleFetch;
350
385
  /**
351
386
  * `Retry-After` in either legal form: delta-seconds (`"2"`) or an HTTP-date
352
387
  * (`"Wed, 21 Oct 2026 07:28:00 GMT"`). Anything else is treated as absent so a