agentfootprint 11.4.0 → 12.0.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/CAPABILITIES.md +3 -1
- package/dist/adapters/code/agentcore.js +295 -214
- package/dist/adapters/code/agentcore.js.map +1 -1
- package/dist/adapters/code/agentcoreClient.js +178 -0
- package/dist/adapters/code/agentcoreClient.js.map +1 -0
- package/dist/adapters/code/agentcoreWire.js +348 -0
- package/dist/adapters/code/agentcoreWire.js.map +1 -0
- package/dist/adapters/code/fileName.js +100 -0
- package/dist/adapters/code/fileName.js.map +1 -0
- package/dist/adapters/code/local.js +529 -183
- package/dist/adapters/code/local.js.map +1 -1
- package/dist/adapters/code/output.js +140 -0
- package/dist/adapters/code/output.js.map +1 -0
- package/dist/adapters/mcp/agentcoreRuntime/invoke.js +7 -6
- package/dist/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
- package/dist/adapters/mcp/agentcoreRuntime/sessionBusy.js +36 -2
- package/dist/adapters/mcp/agentcoreRuntime/sessionBusy.js.map +1 -1
- package/dist/adapters/mcp/agentcoreRuntime/transport.js +3 -1
- package/dist/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
- package/dist/core/codeRunnerTool.js +52 -7
- package/dist/core/codeRunnerTool.js.map +1 -1
- package/dist/doors/providers.js.map +1 -1
- package/dist/esm/adapters/code/agentcore.d.ts +65 -68
- package/dist/esm/adapters/code/agentcore.js +293 -212
- package/dist/esm/adapters/code/agentcore.js.map +1 -1
- package/dist/esm/adapters/code/agentcoreClient.d.ts +193 -0
- package/dist/esm/adapters/code/agentcoreClient.js +173 -0
- package/dist/esm/adapters/code/agentcoreClient.js.map +1 -0
- package/dist/esm/adapters/code/agentcoreWire.d.ts +119 -0
- package/dist/esm/adapters/code/agentcoreWire.js +334 -0
- package/dist/esm/adapters/code/agentcoreWire.js.map +1 -0
- package/dist/esm/adapters/code/fileName.d.ts +43 -0
- package/dist/esm/adapters/code/fileName.js +96 -0
- package/dist/esm/adapters/code/fileName.js.map +1 -0
- package/dist/esm/adapters/code/local.d.ts +91 -12
- package/dist/esm/adapters/code/local.js +528 -182
- package/dist/esm/adapters/code/local.js.map +1 -1
- package/dist/esm/adapters/code/output.d.ts +70 -0
- package/dist/esm/adapters/code/output.js +129 -0
- package/dist/esm/adapters/code/output.js.map +1 -0
- package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.d.ts +7 -6
- package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js +7 -6
- package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
- package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts +32 -1
- package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.js +35 -1
- package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.js.map +1 -1
- package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js +4 -2
- package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
- package/dist/esm/core/codeRunnerTool.d.ts +15 -3
- package/dist/esm/core/codeRunnerTool.js +52 -7
- package/dist/esm/core/codeRunnerTool.js.map +1 -1
- package/dist/esm/doors/providers.d.ts +1 -1
- package/dist/esm/doors/providers.js.map +1 -1
- package/dist/esm/events/payloads.d.ts +144 -29
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/mcp/callLifetime.d.ts +57 -14
- package/dist/esm/mcp/callLifetime.js +67 -19
- package/dist/esm/mcp/callLifetime.js.map +1 -1
- package/dist/esm/mcp/callMarker.d.ts +43 -0
- package/dist/esm/mcp/callMarker.js +69 -0
- package/dist/esm/mcp/callMarker.js.map +1 -0
- package/dist/esm/mcp/connectionRefusals.js +7 -0
- package/dist/esm/mcp/connectionRefusals.js.map +1 -1
- package/dist/esm/mcp/index.d.ts +2 -0
- package/dist/esm/mcp/index.js +3 -0
- package/dist/esm/mcp/index.js.map +1 -1
- package/dist/esm/mcp/mcpClient.js +93 -26
- package/dist/esm/mcp/mcpClient.js.map +1 -1
- package/dist/esm/mcp/replay.d.ts +291 -0
- package/dist/esm/mcp/replay.js +405 -0
- package/dist/esm/mcp/replay.js.map +1 -0
- package/dist/esm/mcp/replayUnavailable.d.ts +68 -0
- package/dist/esm/mcp/replayUnavailable.js +87 -0
- package/dist/esm/mcp/replayUnavailable.js.map +1 -0
- package/dist/esm/mcp/requestLedger.d.ts +115 -32
- package/dist/esm/mcp/requestLedger.js +193 -52
- package/dist/esm/mcp/requestLedger.js.map +1 -1
- package/dist/esm/mcp/seriesEvidence.d.ts +73 -15
- package/dist/esm/mcp/seriesEvidence.js +114 -21
- package/dist/esm/mcp/seriesEvidence.js.map +1 -1
- package/dist/esm/mcp/throttleRetry.d.ts +86 -42
- package/dist/esm/mcp/throttleRetry.js +158 -50
- package/dist/esm/mcp/throttleRetry.js.map +1 -1
- package/dist/esm/mcp/toolResult.d.ts +6 -0
- package/dist/esm/mcp/toolResult.js +15 -0
- package/dist/esm/mcp/toolResult.js.map +1 -1
- package/dist/esm/mcp/types.d.ts +73 -8
- package/dist/esm/provider-contract/codeSandbox.d.ts +89 -0
- package/dist/esm/provider-contract/codeSandbox.js +119 -0
- package/dist/esm/provider-contract/codeSandbox.js.map +1 -0
- package/dist/esm/provider-contract/sessionExpired.d.ts +31 -0
- package/dist/esm/provider-contract/sessionExpired.js +40 -0
- package/dist/esm/provider-contract/sessionExpired.js.map +1 -0
- package/dist/esm/provider-contract/types.d.ts +166 -17
- package/dist/esm/provider-contract/types.js +9 -0
- package/dist/esm/provider-contract/types.js.map +1 -1
- package/dist/esm/redaction/knownStrings.js +16 -0
- package/dist/esm/redaction/knownStrings.js.map +1 -1
- package/dist/esm/tool-providers/index.d.ts +2 -2
- package/dist/esm/tool-providers/index.js +4 -0
- package/dist/esm/tool-providers/index.js.map +1 -1
- package/dist/esm/tools/requestEvidence.js +60 -0
- package/dist/esm/tools/requestEvidence.js.map +1 -1
- package/dist/index.js +12 -4
- package/dist/index.js.map +1 -1
- package/dist/mcp/callLifetime.js +66 -18
- package/dist/mcp/callLifetime.js.map +1 -1
- package/dist/mcp/callMarker.js +74 -0
- package/dist/mcp/callMarker.js.map +1 -0
- package/dist/mcp/connectionRefusals.js +7 -0
- package/dist/mcp/connectionRefusals.js.map +1 -1
- package/dist/mcp/index.js +5 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/mcpClient.js +91 -24
- package/dist/mcp/mcpClient.js.map +1 -1
- package/dist/mcp/replay.js +415 -0
- package/dist/mcp/replay.js.map +1 -0
- package/dist/mcp/replayUnavailable.js +92 -0
- package/dist/mcp/replayUnavailable.js.map +1 -0
- package/dist/mcp/requestLedger.js +193 -52
- package/dist/mcp/requestLedger.js.map +1 -1
- package/dist/mcp/seriesEvidence.js +116 -22
- package/dist/mcp/seriesEvidence.js.map +1 -1
- package/dist/mcp/throttleRetry.js +160 -51
- package/dist/mcp/throttleRetry.js.map +1 -1
- package/dist/mcp/toolResult.js +17 -1
- package/dist/mcp/toolResult.js.map +1 -1
- package/dist/provider-contract/codeSandbox.js +125 -0
- package/dist/provider-contract/codeSandbox.js.map +1 -0
- package/dist/provider-contract/sessionExpired.js +44 -0
- package/dist/provider-contract/sessionExpired.js.map +1 -0
- package/dist/provider-contract/types.js +12 -1
- package/dist/provider-contract/types.js.map +1 -1
- package/dist/redaction/knownStrings.js +16 -0
- package/dist/redaction/knownStrings.js.map +1 -1
- package/dist/tool-providers/index.js +5 -1
- package/dist/tool-providers/index.js.map +1 -1
- package/dist/tools/requestEvidence.js +60 -0
- package/dist/tools/requestEvidence.js.map +1 -1
- package/dist/types/adapters/code/agentcore.d.ts +65 -68
- package/dist/types/adapters/code/agentcore.d.ts.map +1 -1
- package/dist/types/adapters/code/agentcoreClient.d.ts +194 -0
- package/dist/types/adapters/code/agentcoreClient.d.ts.map +1 -0
- package/dist/types/adapters/code/agentcoreWire.d.ts +120 -0
- package/dist/types/adapters/code/agentcoreWire.d.ts.map +1 -0
- package/dist/types/adapters/code/fileName.d.ts +44 -0
- package/dist/types/adapters/code/fileName.d.ts.map +1 -0
- package/dist/types/adapters/code/local.d.ts +91 -12
- package/dist/types/adapters/code/local.d.ts.map +1 -1
- package/dist/types/adapters/code/output.d.ts +71 -0
- package/dist/types/adapters/code/output.d.ts.map +1 -0
- package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts +7 -6
- package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts.map +1 -1
- package/dist/types/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts +32 -1
- package/dist/types/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts.map +1 -1
- package/dist/types/adapters/mcp/agentcoreRuntime/transport.d.ts.map +1 -1
- package/dist/types/core/codeRunnerTool.d.ts +15 -3
- package/dist/types/core/codeRunnerTool.d.ts.map +1 -1
- package/dist/types/doors/providers.d.ts +1 -1
- package/dist/types/doors/providers.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +144 -29
- package/dist/types/events/payloads.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/mcp/callLifetime.d.ts +57 -14
- package/dist/types/mcp/callLifetime.d.ts.map +1 -1
- package/dist/types/mcp/callMarker.d.ts +44 -0
- package/dist/types/mcp/callMarker.d.ts.map +1 -0
- package/dist/types/mcp/index.d.ts +2 -0
- package/dist/types/mcp/index.d.ts.map +1 -1
- package/dist/types/mcp/mcpClient.d.ts.map +1 -1
- package/dist/types/mcp/replay.d.ts +292 -0
- package/dist/types/mcp/replay.d.ts.map +1 -0
- package/dist/types/mcp/replayUnavailable.d.ts +69 -0
- package/dist/types/mcp/replayUnavailable.d.ts.map +1 -0
- package/dist/types/mcp/requestLedger.d.ts +115 -32
- package/dist/types/mcp/requestLedger.d.ts.map +1 -1
- package/dist/types/mcp/seriesEvidence.d.ts +73 -15
- package/dist/types/mcp/seriesEvidence.d.ts.map +1 -1
- package/dist/types/mcp/throttleRetry.d.ts +86 -42
- package/dist/types/mcp/throttleRetry.d.ts.map +1 -1
- package/dist/types/mcp/toolResult.d.ts +6 -0
- package/dist/types/mcp/toolResult.d.ts.map +1 -1
- package/dist/types/mcp/types.d.ts +73 -8
- package/dist/types/mcp/types.d.ts.map +1 -1
- package/dist/types/provider-contract/codeSandbox.d.ts +90 -0
- package/dist/types/provider-contract/codeSandbox.d.ts.map +1 -0
- package/dist/types/provider-contract/sessionExpired.d.ts +32 -0
- package/dist/types/provider-contract/sessionExpired.d.ts.map +1 -0
- package/dist/types/provider-contract/types.d.ts +166 -17
- package/dist/types/provider-contract/types.d.ts.map +1 -1
- package/dist/types/redaction/knownStrings.d.ts.map +1 -1
- package/dist/types/tool-providers/index.d.ts +2 -2
- package/dist/types/tool-providers/index.d.ts.map +1 -1
- package/dist/types/tools/requestEvidence.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -28,17 +28,31 @@
|
|
|
28
28
|
* timed out, or failed — was sent, and the server may have received it and run
|
|
29
29
|
* it. Its row says so (`remote: 'unknown'`); nothing here records it as not run.
|
|
30
30
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
31
|
+
* THREE FACTS PER ATTEMPT, NONE READ FROM ANOTHER (`replay.ts`): the failure
|
|
32
|
+
* (footprintjs's category), what is known of its effect (`unknown` for every
|
|
33
|
+
* attempt sent that did not complete — a refusal included; `applied` when the
|
|
34
|
+
* call completed, never proof of a write; `none` only for what was never
|
|
35
|
+
* sent), and — on an attempt the series asked again after — what permitted it.
|
|
36
|
+
* Each row also says how long it took. The end says how many requests were
|
|
37
|
+
* sent and what is known of the whole series' effect; uncertainty survives
|
|
38
|
+
* (`SeriesKnowledge`).
|
|
39
|
+
*
|
|
40
|
+
* WHEN IT FILES. When the call settles — the series has ended by then, and the
|
|
41
|
+
* call's verdict is what says whether an answered attempt completed (a 200 can
|
|
42
|
+
* carry a tool error) — and, for a cancellation, at the moment the signal
|
|
43
|
+
* fires: a cancelled run stops waiting for its stage at once, so a record filed
|
|
44
|
+
* when the series later unwinds would land after the run was saved. The runner
|
|
45
|
+
* makes no record for an attempt it abandons at that moment or for a wait it
|
|
46
|
+
* was cut out of, so those are written here: the cut attempt's row and
|
|
47
|
+
* `during: 'request'`, or `during: 'wait'`. A series ended and waiting for its
|
|
48
|
+
* call files at once if the call is cancelled first, with what it knows.
|
|
49
|
+
* Anything the series reports after it has filed is not part of the request's
|
|
50
|
+
* story any more and is ignored.
|
|
38
51
|
*/
|
|
39
52
|
import type { AttemptRecord } from 'footprintjs';
|
|
40
|
-
import type { ToolRequestAttempt, ToolRequestReason } from '../events/payloads.js';
|
|
53
|
+
import type { ToolRequestAttempt, ToolRequestEffect, ToolRequestPermission, ToolRequestReason } from '../events/payloads.js';
|
|
41
54
|
import { type RequestEvidence, type RequestEvidenceSink } from '../tools/requestEvidence.js';
|
|
55
|
+
import { type RequestReplay } from './replay.js';
|
|
42
56
|
/** Where the request went, as a row may say it: the app's label for it, or its origin. */
|
|
43
57
|
export type RequestWhere = Pick<RequestEvidence, 'endpoint' | 'origin'>;
|
|
44
58
|
/** What the series saw of one attempt that its record does not hold. */
|
|
@@ -52,24 +66,49 @@ export interface AttemptSeen {
|
|
|
52
66
|
};
|
|
53
67
|
}
|
|
54
68
|
/** 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'>;
|
|
69
|
+
export type DeclineReason = Extract<ToolRequestReason, 'exhausted' | 'wait-limit' | 'no-time-left' | 'not-replayable' | 'not-retryable' | 'not-permitted' | 'changes-without-key'>;
|
|
70
|
+
/**
|
|
71
|
+
* What the series knows of one attempt beyond the runner's record (`replay.ts`):
|
|
72
|
+
* its effect — absent for an answered attempt, which the call's verdict decides
|
|
73
|
+
* when the record is filed — what permitted the next attempt, and how long it
|
|
74
|
+
* took.
|
|
75
|
+
*/
|
|
76
|
+
export interface AttemptFacts {
|
|
77
|
+
readonly effect?: ToolRequestEffect;
|
|
78
|
+
readonly permission?: ToolRequestPermission;
|
|
79
|
+
readonly durationMs: number;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Where the record waits for its call: the call's signal (it fires when the
|
|
83
|
+
* call settles or is cancelled), and the facts the call leaves there.
|
|
84
|
+
*/
|
|
85
|
+
export interface Settlement {
|
|
86
|
+
readonly signal: AbortSignal;
|
|
87
|
+
readonly replay: RequestReplay;
|
|
88
|
+
}
|
|
56
89
|
/** One request's evidence, collected as its series runs and filed once. */
|
|
57
90
|
export declare class SeriesEvidence {
|
|
58
91
|
private readonly sink;
|
|
59
92
|
private readonly where;
|
|
93
|
+
private readonly settlement?;
|
|
60
94
|
private readonly rows;
|
|
61
95
|
private omitted;
|
|
62
96
|
private last;
|
|
63
97
|
private filed;
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
|
|
98
|
+
private waiting;
|
|
99
|
+
/** What is known of the series' effect, attempt by attempt — the answer's excepted. */
|
|
100
|
+
private readonly knowledge;
|
|
101
|
+
/** The answered attempt, while its effect waits for the call's verdict. */
|
|
102
|
+
private answer;
|
|
103
|
+
constructor(sink: RequestEvidenceSink, where: RequestWhere, settlement?: Settlement | undefined);
|
|
104
|
+
/** One attempt as the runner recorded it, with what the series knows of it. */
|
|
105
|
+
attempt(record: AttemptRecord, seen: AttemptSeen | undefined, declined?: DeclineReason, facts?: AttemptFacts): void;
|
|
67
106
|
/**
|
|
68
107
|
* The caller's cancellation cut attempt `n` in flight. It was sent — the
|
|
69
108
|
* server may have it, and may have run it — so it is a row, `cut`, with the
|
|
70
109
|
* remote outcome `unknown`; then the request's end says the same.
|
|
71
110
|
*/
|
|
72
|
-
cutInFlight(n: number): void;
|
|
111
|
+
cutInFlight(n: number, durationMs?: number): void;
|
|
73
112
|
/**
|
|
74
113
|
* The caller's cancellation landed with NO request in flight: between two —
|
|
75
114
|
* `during: 'wait'`, the next request never sent — or before the first, when
|
|
@@ -82,7 +121,7 @@ export declare class SeriesEvidence {
|
|
|
82
121
|
* refusal it will not ask again after. A refusal it MEANT to ask again after
|
|
83
122
|
* is delivered when the deadline lands inside the wait: the runner's wait
|
|
84
123
|
* ends early, the series stops, and the end says so (`no-time-left`, during
|
|
85
|
-
* the `wait`).
|
|
124
|
+
* the `wait`). Filed when the call has read it.
|
|
86
125
|
*/
|
|
87
126
|
delivered(): void;
|
|
88
127
|
/**
|
|
@@ -92,11 +131,30 @@ export declare class SeriesEvidence {
|
|
|
92
131
|
* as one: a deadline that had passed before the first request (`timed-out`,
|
|
93
132
|
* no `during`, nothing sent) or one a future runner reports from inside a wait
|
|
94
133
|
* (`during: 'wait'`); anything else is filed as a failure the record cannot
|
|
95
|
-
* account for, so a request is never left unfiled.
|
|
134
|
+
* account for, so a request is never left unfiled. Filed when the call settles.
|
|
96
135
|
*/
|
|
97
136
|
threw(outOfTime: boolean): void;
|
|
98
137
|
private add;
|
|
138
|
+
/**
|
|
139
|
+
* File `end` once the call has settled — its verdict is what says whether an
|
|
140
|
+
* answered attempt completed — or at once, when the call is already settled
|
|
141
|
+
* or cancelled, or there is no call to wait for.
|
|
142
|
+
*/
|
|
143
|
+
private fileWhenSettled;
|
|
99
144
|
private file;
|
|
145
|
+
/**
|
|
146
|
+
* The rows, the answered one given its effect: `applied` when the call
|
|
147
|
+
* completed — the server answered it, and not with an error — else `unknown`
|
|
148
|
+
* (a 5xx, a JSON-RPC error, a tool error, a call cancelled before it read the
|
|
149
|
+
* answer). The answer's effect joins the series' knowledge here.
|
|
150
|
+
*/
|
|
151
|
+
private settleAnswer;
|
|
100
152
|
}
|
|
101
153
|
/** One record as a row — see the module note for what a row may say. */
|
|
102
154
|
export declare function rowOf(record: AttemptRecord, seen: AttemptSeen | undefined, declined?: DeclineReason): ToolRequestAttempt;
|
|
155
|
+
/**
|
|
156
|
+
* `row` with what the series knows of its attempt beyond the record — its
|
|
157
|
+
* effect, what permitted the next attempt, how long it took. Without `facts`,
|
|
158
|
+
* the row as the record alone says it.
|
|
159
|
+
*/
|
|
160
|
+
export declare function withFacts(row: ToolRequestAttempt, facts: AttemptFacts | undefined): ToolRequestAttempt;
|
|
@@ -28,44 +28,76 @@
|
|
|
28
28
|
* timed out, or failed — was sent, and the server may have received it and run
|
|
29
29
|
* it. Its row says so (`remote: 'unknown'`); nothing here records it as not run.
|
|
30
30
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
31
|
+
* THREE FACTS PER ATTEMPT, NONE READ FROM ANOTHER (`replay.ts`): the failure
|
|
32
|
+
* (footprintjs's category), what is known of its effect (`unknown` for every
|
|
33
|
+
* attempt sent that did not complete — a refusal included; `applied` when the
|
|
34
|
+
* call completed, never proof of a write; `none` only for what was never
|
|
35
|
+
* sent), and — on an attempt the series asked again after — what permitted it.
|
|
36
|
+
* Each row also says how long it took. The end says how many requests were
|
|
37
|
+
* sent and what is known of the whole series' effect; uncertainty survives
|
|
38
|
+
* (`SeriesKnowledge`).
|
|
39
|
+
*
|
|
40
|
+
* WHEN IT FILES. When the call settles — the series has ended by then, and the
|
|
41
|
+
* call's verdict is what says whether an answered attempt completed (a 200 can
|
|
42
|
+
* carry a tool error) — and, for a cancellation, at the moment the signal
|
|
43
|
+
* fires: a cancelled run stops waiting for its stage at once, so a record filed
|
|
44
|
+
* when the series later unwinds would land after the run was saved. The runner
|
|
45
|
+
* makes no record for an attempt it abandons at that moment or for a wait it
|
|
46
|
+
* was cut out of, so those are written here: the cut attempt's row and
|
|
47
|
+
* `during: 'request'`, or `during: 'wait'`. A series ended and waiting for its
|
|
48
|
+
* call files at once if the call is cancelled first, with what it knows.
|
|
49
|
+
* Anything the series reports after it has filed is not part of the request's
|
|
50
|
+
* story any more and is ignored.
|
|
38
51
|
*/
|
|
39
52
|
import { MAX_REQUEST_ATTEMPT_ROWS, } from '../tools/requestEvidence.js';
|
|
53
|
+
import { SeriesKnowledge } from './replay.js';
|
|
40
54
|
const FAILED = 'The request failed before an answer arrived. Its error is not kept.';
|
|
41
55
|
const OUT_OF_TIME = 'The call ran out of time before an answer arrived.';
|
|
42
56
|
/** One request's evidence, collected as its series runs and filed once. */
|
|
43
57
|
export class SeriesEvidence {
|
|
44
58
|
sink;
|
|
45
59
|
where;
|
|
60
|
+
settlement;
|
|
46
61
|
rows = [];
|
|
47
62
|
omitted = 0;
|
|
48
63
|
last;
|
|
49
64
|
filed = false;
|
|
50
|
-
|
|
65
|
+
waiting = false;
|
|
66
|
+
/** What is known of the series' effect, attempt by attempt — the answer's excepted. */
|
|
67
|
+
knowledge = new SeriesKnowledge();
|
|
68
|
+
/** The answered attempt, while its effect waits for the call's verdict. */
|
|
69
|
+
answer;
|
|
70
|
+
constructor(sink, where, settlement) {
|
|
51
71
|
this.sink = sink;
|
|
52
72
|
this.where = where;
|
|
73
|
+
this.settlement = settlement;
|
|
53
74
|
}
|
|
54
|
-
/** One attempt as the runner recorded it. */
|
|
55
|
-
attempt(record, seen, declined) {
|
|
75
|
+
/** One attempt as the runner recorded it, with what the series knows of it. */
|
|
76
|
+
attempt(record, seen, declined, facts) {
|
|
56
77
|
if (this.filed)
|
|
57
78
|
return;
|
|
58
|
-
|
|
79
|
+
const row = withFacts(rowOf(record, seen, declined), facts);
|
|
80
|
+
if (facts !== undefined && row.effect === undefined && row.outcome === 'answered') {
|
|
81
|
+
this.answer = row;
|
|
82
|
+
}
|
|
83
|
+
this.add(row);
|
|
59
84
|
}
|
|
60
85
|
/**
|
|
61
86
|
* The caller's cancellation cut attempt `n` in flight. It was sent — the
|
|
62
87
|
* server may have it, and may have run it — so it is a row, `cut`, with the
|
|
63
88
|
* remote outcome `unknown`; then the request's end says the same.
|
|
64
89
|
*/
|
|
65
|
-
cutInFlight(n) {
|
|
90
|
+
cutInFlight(n, durationMs) {
|
|
66
91
|
if (this.filed)
|
|
67
92
|
return;
|
|
68
|
-
this.add({
|
|
93
|
+
this.add({
|
|
94
|
+
attempt: n,
|
|
95
|
+
outcome: 'cut',
|
|
96
|
+
reason: 'cancelled',
|
|
97
|
+
remote: 'unknown',
|
|
98
|
+
effect: 'unknown',
|
|
99
|
+
...(durationMs !== undefined && { durationMs }),
|
|
100
|
+
});
|
|
69
101
|
this.file({ outcome: 'cut', reason: 'cancelled', during: 'request', remote: 'unknown' });
|
|
70
102
|
}
|
|
71
103
|
/**
|
|
@@ -91,15 +123,15 @@ export class SeriesEvidence {
|
|
|
91
123
|
* refusal it will not ask again after. A refusal it MEANT to ask again after
|
|
92
124
|
* is delivered when the deadline lands inside the wait: the runner's wait
|
|
93
125
|
* ends early, the series stops, and the end says so (`no-time-left`, during
|
|
94
|
-
* the `wait`).
|
|
126
|
+
* the `wait`). Filed when the call has read it.
|
|
95
127
|
*/
|
|
96
128
|
delivered() {
|
|
97
129
|
const last = this.last;
|
|
98
130
|
if (last === undefined) {
|
|
99
|
-
this.
|
|
131
|
+
this.fileWhenSettled(UNACCOUNTED);
|
|
100
132
|
return;
|
|
101
133
|
}
|
|
102
|
-
this.
|
|
134
|
+
this.fileWhenSettled(last.reason === 'retryable'
|
|
103
135
|
? { ...endOf(last), reason: 'no-time-left', during: 'wait' }
|
|
104
136
|
: endOf(last));
|
|
105
137
|
}
|
|
@@ -110,19 +142,19 @@ export class SeriesEvidence {
|
|
|
110
142
|
* as one: a deadline that had passed before the first request (`timed-out`,
|
|
111
143
|
* no `during`, nothing sent) or one a future runner reports from inside a wait
|
|
112
144
|
* (`during: 'wait'`); anything else is filed as a failure the record cannot
|
|
113
|
-
* account for, so a request is never left unfiled.
|
|
145
|
+
* account for, so a request is never left unfiled. Filed when the call settles.
|
|
114
146
|
*/
|
|
115
147
|
threw(outOfTime) {
|
|
116
148
|
const last = this.last;
|
|
117
149
|
if (last !== undefined && last.reason !== 'retryable') {
|
|
118
|
-
this.
|
|
150
|
+
this.fileWhenSettled(endOf(last));
|
|
119
151
|
return;
|
|
120
152
|
}
|
|
121
153
|
if (!outOfTime) {
|
|
122
|
-
this.
|
|
154
|
+
this.fileWhenSettled(UNACCOUNTED);
|
|
123
155
|
return;
|
|
124
156
|
}
|
|
125
|
-
this.
|
|
157
|
+
this.fileWhenSettled({
|
|
126
158
|
outcome: 'timed-out',
|
|
127
159
|
reason: 'no-time-left',
|
|
128
160
|
failure: 'timeout',
|
|
@@ -132,22 +164,67 @@ export class SeriesEvidence {
|
|
|
132
164
|
}
|
|
133
165
|
add(row) {
|
|
134
166
|
this.last = row;
|
|
167
|
+
if (row.effect !== undefined)
|
|
168
|
+
this.knowledge.note(row.effect);
|
|
135
169
|
if (this.rows.length < MAX_REQUEST_ATTEMPT_ROWS)
|
|
136
170
|
this.rows.push(row);
|
|
137
171
|
else
|
|
138
172
|
this.omitted += 1;
|
|
139
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* File `end` once the call has settled — its verdict is what says whether an
|
|
176
|
+
* answered attempt completed — or at once, when the call is already settled
|
|
177
|
+
* or cancelled, or there is no call to wait for.
|
|
178
|
+
*/
|
|
179
|
+
fileWhenSettled(end) {
|
|
180
|
+
const signal = this.settlement?.signal;
|
|
181
|
+
if (signal === undefined || signal.aborted) {
|
|
182
|
+
this.file(end);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (this.waiting)
|
|
186
|
+
return;
|
|
187
|
+
this.waiting = true;
|
|
188
|
+
signal.addEventListener('abort', () => this.file(end), { once: true });
|
|
189
|
+
}
|
|
140
190
|
file(end) {
|
|
141
191
|
if (this.filed)
|
|
142
192
|
return;
|
|
143
193
|
this.filed = true;
|
|
194
|
+
const replay = this.settlement?.replay;
|
|
195
|
+
const rows = this.settleAnswer(replay);
|
|
144
196
|
try {
|
|
145
|
-
this.sink.file({
|
|
197
|
+
this.sink.file({
|
|
198
|
+
...this.where,
|
|
199
|
+
attempts: rows,
|
|
200
|
+
omitted: this.omitted,
|
|
201
|
+
end: {
|
|
202
|
+
...end,
|
|
203
|
+
attempts: this.rows.length + this.omitted,
|
|
204
|
+
effect: this.knowledge.effect,
|
|
205
|
+
...(replay?.mayHaveRun === true && { mayHaveRun: true }),
|
|
206
|
+
},
|
|
207
|
+
});
|
|
146
208
|
}
|
|
147
209
|
catch {
|
|
148
210
|
// The library's sink never throws; one that does must not fail the call.
|
|
149
211
|
}
|
|
150
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* The rows, the answered one given its effect: `applied` when the call
|
|
215
|
+
* completed — the server answered it, and not with an error — else `unknown`
|
|
216
|
+
* (a 5xx, a JSON-RPC error, a tool error, a call cancelled before it read the
|
|
217
|
+
* answer). The answer's effect joins the series' knowledge here.
|
|
218
|
+
*/
|
|
219
|
+
settleAnswer(replay) {
|
|
220
|
+
const answer = this.answer;
|
|
221
|
+
if (answer === undefined)
|
|
222
|
+
return [...this.rows];
|
|
223
|
+
const effect = replay?.verdict === 'completed' ? 'applied' : 'unknown';
|
|
224
|
+
this.knowledge.note(effect);
|
|
225
|
+
const settled = { ...answer, effect };
|
|
226
|
+
return this.rows.map((row) => (row === answer ? settled : row));
|
|
227
|
+
}
|
|
151
228
|
}
|
|
152
229
|
/**
|
|
153
230
|
* An end no attempt accounts for — never seen; kept so a request is never left
|
|
@@ -183,6 +260,22 @@ export function rowOf(record, seen, declined) {
|
|
|
183
260
|
...(noAnswer(outcome) && { remote: 'unknown' }),
|
|
184
261
|
};
|
|
185
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* `row` with what the series knows of its attempt beyond the record — its
|
|
265
|
+
* effect, what permitted the next attempt, how long it took. Without `facts`,
|
|
266
|
+
* the row as the record alone says it.
|
|
267
|
+
*/
|
|
268
|
+
export function withFacts(row, facts) {
|
|
269
|
+
if (facts === undefined)
|
|
270
|
+
return row;
|
|
271
|
+
return {
|
|
272
|
+
...row,
|
|
273
|
+
...(facts.effect !== undefined && { effect: facts.effect }),
|
|
274
|
+
...(row.reason === 'retryable' &&
|
|
275
|
+
facts.permission !== undefined && { permission: facts.permission }),
|
|
276
|
+
durationMs: facts.durationMs,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
186
279
|
/** An attempt that ended without an answer — the server may have run it, or not. */
|
|
187
280
|
function noAnswer(outcome) {
|
|
188
281
|
return outcome === 'failed' || outcome === 'timed-out' || outcome === 'cut';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seriesEvidence.js","sourceRoot":"","sources":["../../../src/mcp/seriesEvidence.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"seriesEvidence.js","sourceRoot":"","sources":["../../../src/mcp/seriesEvidence.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,27 +10,33 @@
|
|
|
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
|
-
* ──
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* turns that off per server. What is certain is the contrast with a 500 or a
|
|
21
|
-
* timeout, where the call may have half-run and a retry could charge a card
|
|
22
|
-
* twice.
|
|
13
|
+
* ── Who may ask again: the app, by declaration (`replay.ts`) ─────────────────
|
|
14
|
+
* HTTP 429 says only that the request was rate-limited (RFC 6585 §4). It does
|
|
15
|
+
* not prove the server ran nothing, and `Retry-After` says when to ask again,
|
|
16
|
+
* not that asking is safe. So permission to send a tool call again is the
|
|
17
|
+
* APP's, declared per (server, tool) when the client is built (`mcpClient({
|
|
18
|
+
* replay })`), and kept apart from what is known of an attempt's effect. Before
|
|
19
|
+
* every repeat the series asks `permit`; the record keeps its answer.
|
|
23
20
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
21
|
+
* - `'compatibility'` (the default, kept in 12.0) keeps today's behaviour by
|
|
22
|
+
* name: a 429 is repeated for every tool, ASSUMING the server refused it
|
|
23
|
+
* before running it — and every such repeat records that assumption.
|
|
24
|
+
* - `'app-authorized'` (opt-in, by name) repeats a 429 only for a tool the
|
|
25
|
+
* app declared repeatable on it.
|
|
26
|
+
* - A request that failed in transport without an answer (footprintjs's
|
|
27
|
+
* `network`: a lost connection, a timeout below the series) is repeated
|
|
28
|
+
* only when the app declared that for the tool. A 5xx is an answer, never
|
|
29
|
+
* repeated. A cut or a deadline ends the series.
|
|
30
|
+
* - Under both, a tool the app declares as making changes is never repeated
|
|
31
|
+
* automatically unless the server is declared to deduplicate by a key the
|
|
32
|
+
* call carries — footprintjs's side-effect guard, now wired here.
|
|
28
33
|
*
|
|
29
34
|
* The loop takes its question as a {@link RetryDecision}, so the one other
|
|
30
35
|
* refusal a service documents as one to retry — AgentCore Runtime's "session
|
|
31
36
|
* operation in progress" — reuses this loop rather than growing a second one.
|
|
32
|
-
* That decision is applied only by that vendor's own transport
|
|
33
|
-
*
|
|
37
|
+
* That decision is applied only by that vendor's own transport, and its rule
|
|
38
|
+
* carries the adapter's retry assumption (`RetryRule.assumes`) — a policy,
|
|
39
|
+
* never evidence: its attempts record effect `unknown`, as a 429's do.
|
|
34
40
|
*
|
|
35
41
|
* ── Why it lives at the fetch seam and not around `Tool.execute` ─────────────
|
|
36
42
|
* Because `Retry-After` is only reachable here. The MCP SDK reads the response,
|
|
@@ -58,12 +64,17 @@
|
|
|
58
64
|
* operation that succeeded: a 503 is delivered as the answer it was, never
|
|
59
65
|
* retried — and written down as `answered` with its status, never success.
|
|
60
66
|
* 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
|
|
62
|
-
*
|
|
63
|
-
* attempt it happened in, as it
|
|
64
|
-
* series ends on a refusal (attempts spent, a ceiling
|
|
65
|
-
* the refusal's response is delivered
|
|
66
|
-
* the 429, never an error of ours.
|
|
67
|
+
* its kind, and the policy's `retryOn` accepts those refusals — and a network
|
|
68
|
+
* failure the app declared for the tool — when the replay rule permits them,
|
|
69
|
+
* and nothing else: a 5xx ends the series on the attempt it happened in, as it
|
|
70
|
+
* always did. When the series ends on a refusal (attempts spent, a ceiling
|
|
71
|
+
* reached, no time left, no permission), the refusal's response is delivered
|
|
72
|
+
* as the server sent it: the caller sees the 429, never an error of ours. The
|
|
73
|
+
* call decides what that means for it (`callLifetime.ts`): under
|
|
74
|
+
* 'app-authorized', a call that genuinely lacked an answer somewhere and does
|
|
75
|
+
* not complete fails as "may have run". This series reports the HTTP half of
|
|
76
|
+
* that — an attempt that got no response at all, and the status it delivered;
|
|
77
|
+
* a received refusal is an answer, its effect still unknown.
|
|
67
78
|
*
|
|
68
79
|
* ── A fetch that already retries is JOINED, never wrapped ────────────────────
|
|
69
80
|
* A transport whose own fetch runs a series (AgentCore Runtime's session-busy
|
|
@@ -90,6 +101,7 @@
|
|
|
90
101
|
*
|
|
91
102
|
* Pattern: Decorator over `fetch`. Role: Layer-3 tool transport.
|
|
92
103
|
*/
|
|
104
|
+
import { type ReplayDeclaration } from './replay.js';
|
|
93
105
|
import type { RequestLedger } from './requestLedger.js';
|
|
94
106
|
/**
|
|
95
107
|
* The fetch shape the MCP SDK's `fetch` hook uses — deliberately NARROWER
|
|
@@ -107,8 +119,12 @@ export type ThrottleFetch = (input: string | URL, init?: RequestInit) => Promise
|
|
|
107
119
|
export type RetryKind = 'throttle' | 'session-busy';
|
|
108
120
|
/** Reported to {@link ThrottleRetryOptions.onRetry} before each wait. */
|
|
109
121
|
export interface ThrottleRetryInfo {
|
|
110
|
-
/**
|
|
111
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Which refusal this retry answers — or `'network'`, a tool call the app
|
|
124
|
+
* declared repeatable after a request that failed without an answer
|
|
125
|
+
* (`McpClientOptions.replay`). It is reported to the series' first rule.
|
|
126
|
+
*/
|
|
127
|
+
readonly kind: RetryKind | 'network';
|
|
112
128
|
/** The attempt about to START. `2` is the first retry. */
|
|
113
129
|
readonly attempt: number;
|
|
114
130
|
/** Ceiling in force for this refusal, including the first attempt. */
|
|
@@ -240,16 +256,18 @@ export interface RetryVerdict {
|
|
|
240
256
|
* The one question the loop asks of each response.
|
|
241
257
|
*
|
|
242
258
|
* ── The license every decision must hold ─────────────────────────────────────
|
|
243
|
-
* A decision
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
259
|
+
* A decision RECOGNISES a refusal; whether the request is sent again is the
|
|
260
|
+
* replay rule's (`replay.ts`), never the decision's. It may recognise only a
|
|
261
|
+
* response that is a refusal — never one that could be the record of
|
|
262
|
+
* half-done work. The library holds exactly two: {@link throttled} below, a
|
|
263
|
+
* 429, and AgentCore Runtime's "session operation in progress" refusal, which
|
|
264
|
+
* lives with that vendor's adapter (`adapters/mcp/agentcoreRuntime/`) and whose
|
|
265
|
+
* rule carries the adapter's retry assumption (`RetryRule.assumes`). Either
|
|
266
|
+
* one's effect stays unknown: a 429 says the request was rate-limited, and the
|
|
267
|
+
* busy body is matched by its code and words, which a server behind the
|
|
268
|
+
* runtime can send after it ran the call. Each stays ONE small function, so a
|
|
269
|
+
* refusal has exactly one place it is recognised — and each attempt is written
|
|
270
|
+
* down as one footprintjs attempt record.
|
|
253
271
|
*/
|
|
254
272
|
export type RetryDecision = (response: Response,
|
|
255
273
|
/**
|
|
@@ -297,6 +315,13 @@ export interface RetryRule {
|
|
|
297
315
|
/** The caller's own name for the endpoint, reported as `endpoint`. */
|
|
298
316
|
readonly endpointLabel?: string;
|
|
299
317
|
readonly onRetry?: (info: ThrottleRetryInfo) => void;
|
|
318
|
+
/**
|
|
319
|
+
* Set only by an adapter that retries this refusal as its own policy
|
|
320
|
+
* (`sessionBusy.ts`): what it assumes in doing so. The assumption is recorded
|
|
321
|
+
* beside each repeat (`permission: { by: 'adapter', assumes }`) — never as
|
|
322
|
+
* evidence: the attempt's effect stays `unknown`.
|
|
323
|
+
*/
|
|
324
|
+
readonly assumes?: 'refused-before-execution';
|
|
300
325
|
}
|
|
301
326
|
/**
|
|
302
327
|
* @internal A rule from a caller's options — `undefined` when retry is off
|
|
@@ -307,7 +332,7 @@ export interface RetryRule {
|
|
|
307
332
|
* @throws TypeError, when the rule is BUILT, for a value the schedule cannot
|
|
308
333
|
* mean — named by option, never echoing a value that is not a number.
|
|
309
334
|
*/
|
|
310
|
-
export declare function retryRule(kind: RetryKind, decide: RetryDecision, config: RetryOnThrottle | undefined, defaults: RetryDefaults, where: string): RetryRule | undefined;
|
|
335
|
+
export declare function retryRule(kind: RetryKind, decide: RetryDecision, config: RetryOnThrottle | undefined, defaults: RetryDefaults, where: string, assumes?: 'refused-before-execution'): RetryRule | undefined;
|
|
311
336
|
/**
|
|
312
337
|
* Wrap a `fetch` so HTTP 429 responses are retried, honouring `Retry-After`.
|
|
313
338
|
*
|
|
@@ -346,19 +371,37 @@ export declare function retryRule(kind: RetryKind, decide: RetryDecision, config
|
|
|
346
371
|
*/
|
|
347
372
|
export declare function retryingFetch(inner: ThrottleFetch | undefined, config: RetryOnThrottle | undefined): ThrottleFetch | undefined;
|
|
348
373
|
/**
|
|
349
|
-
* @internal
|
|
350
|
-
*
|
|
351
|
-
*
|
|
374
|
+
* @internal The series for a transport whose 429 rule is off (`retryOnThrottle:
|
|
375
|
+
* false`) while the app's replay declaration still needs one (`replay.ts` ·
|
|
376
|
+
* `needsSeries`): a tool declared repeatable on `'network'`, or the
|
|
377
|
+
* `'app-authorized'` policy, whose record and "may have run" rest on the series.
|
|
378
|
+
* `retryOnThrottle: false` turns off the 429 rule and nothing else, so its one
|
|
379
|
+
* rule is that rule switched off: it recognises no response and holds the
|
|
380
|
+
* call's budget (`retryOnThrottle`'s defaults). A transport fetch that already
|
|
381
|
+
* runs a series is joined, as `retryingFetch` joins it.
|
|
382
|
+
*/
|
|
383
|
+
export declare function seriesWithoutThrottle(inner: ThrottleFetch | undefined): ThrottleFetch;
|
|
384
|
+
/**
|
|
385
|
+
* @internal What one call's series is built from: the rules it asks, in order;
|
|
386
|
+
* the connection's ledger — which tool call each request belongs to, so the
|
|
387
|
+
* series can file its attempts into that call's run (`requestLedger.ts`); and
|
|
388
|
+
* the app's replay declaration — who may send a tool call again (`replay.ts`).
|
|
389
|
+
* No declaration is the compatibility policy, naming no tool.
|
|
352
390
|
*/
|
|
353
391
|
export interface SeriesSpec {
|
|
354
392
|
readonly rules: readonly RetryRule[];
|
|
355
393
|
readonly ledger?: RequestLedger;
|
|
394
|
+
readonly replay?: ReplayDeclaration;
|
|
356
395
|
}
|
|
357
|
-
/**
|
|
396
|
+
/**
|
|
397
|
+
* @internal What a joinable fetch's series can be rebuilt with: one more rule,
|
|
398
|
+
* or a ledger and the replay declaration (they arrive together, from `mcpClient`).
|
|
399
|
+
*/
|
|
358
400
|
export type SeriesJoin = {
|
|
359
401
|
readonly rule: RetryRule;
|
|
360
402
|
} | {
|
|
361
403
|
readonly ledger: RequestLedger;
|
|
404
|
+
readonly replay?: ReplayDeclaration;
|
|
362
405
|
};
|
|
363
406
|
/** @internal `spec` with `join` in it. */
|
|
364
407
|
export declare function joinedSpec(spec: SeriesSpec, join: SeriesJoin): SeriesSpec;
|
|
@@ -372,10 +415,11 @@ export declare function joinedSpec(spec: SeriesSpec, join: SeriesJoin): SeriesSp
|
|
|
372
415
|
export declare function joinableRetry(fetch: ThrottleFetch, rebuild: (join: SeriesJoin) => ThrottleFetch): ThrottleFetch;
|
|
373
416
|
/**
|
|
374
417
|
* @internal `fetch` rebuilt so its series files each request's attempts through
|
|
375
|
-
* `ledger
|
|
376
|
-
* is nothing to file and the
|
|
418
|
+
* `ledger`, and asks `replay` before sending a tool call again — or `undefined`
|
|
419
|
+
* when `fetch` runs no series (retry off), so there is nothing to file and the
|
|
420
|
+
* caller keeps `fetch` as it is.
|
|
377
421
|
*/
|
|
378
|
-
export declare function ledgeredFetch(fetch: ThrottleFetch, ledger: RequestLedger): ThrottleFetch | undefined;
|
|
422
|
+
export declare function ledgeredFetch(fetch: ThrottleFetch, ledger: RequestLedger, replay?: ReplayDeclaration): ThrottleFetch | undefined;
|
|
379
423
|
/**
|
|
380
424
|
* @internal The one series per call over `inner`, asking `spec.rules` in order —
|
|
381
425
|
* `inner` itself when there are none. The first rule holds the call's budget;
|