agentfootprint 11.2.0 → 11.4.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/AGENTS.md +1 -1
- package/CAPABILITIES.md +4 -0
- package/ai-instructions/claude-code/SKILL.md +1 -1
- package/dist/adapters/identity/verify/claims.js +3 -3
- package/dist/adapters/mcp/agentcoreRuntime/invoke.js +3 -2
- package/dist/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
- package/dist/adapters/mcp/agentcoreRuntime/sessionBusy.js +6 -5
- package/dist/adapters/mcp/agentcoreRuntime/sessionBusy.js.map +1 -1
- package/dist/adapters/mcp/agentcoreRuntime/transport.js +8 -6
- package/dist/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
- package/dist/answer-account/account.js +15 -3
- package/dist/answer-account/account.js.map +1 -1
- package/dist/answer-account/facts/howSure.js +10 -22
- package/dist/answer-account/facts/howSure.js.map +1 -1
- package/dist/core/Agent.js +26 -3
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/agent/AgentBuilder.js +69 -12
- package/dist/core/agent/AgentBuilder.js.map +1 -1
- package/dist/core/agent/assessment/assess.js +15 -4
- package/dist/core/agent/assessment/assess.js.map +1 -1
- package/dist/core/agent/assessment/compose.js +153 -15
- package/dist/core/agent/assessment/compose.js.map +1 -1
- package/dist/core/agent/assessment/reasons.js +35 -1
- package/dist/core/agent/assessment/reasons.js.map +1 -1
- package/dist/core/agent/assessment/sources.js +205 -0
- package/dist/core/agent/assessment/sources.js.map +1 -0
- package/dist/core/agent/assessment/stage.js +15 -4
- package/dist/core/agent/assessment/stage.js.map +1 -1
- package/dist/core/agent/buildAgentChart.js.map +1 -1
- package/dist/core/agent/buildToolRegistry.js +4 -1
- package/dist/core/agent/buildToolRegistry.js.map +1 -1
- package/dist/core/agent/evidence/evidenceIndex.js +30 -2
- package/dist/core/agent/evidence/evidenceIndex.js.map +1 -1
- package/dist/core/agent/evidence/extract.js +34 -5
- package/dist/core/agent/evidence/extract.js.map +1 -1
- package/dist/core/agent/evidence/figures.js +31 -3
- package/dist/core/agent/evidence/figures.js.map +1 -1
- package/dist/core/agent/evidence/numberPrecision.js +58 -2
- package/dist/core/agent/evidence/numberPrecision.js.map +1 -1
- package/dist/core/agent/honesty/mounts.js.map +1 -1
- package/dist/core/agent/stages/prepareFinal.js +33 -17
- package/dist/core/agent/stages/prepareFinal.js.map +1 -1
- package/dist/core/agent/stages/route.js +2 -1
- package/dist/core/agent/stages/route.js.map +1 -1
- package/dist/core/agent/stages/toolCalls.js +14 -1
- package/dist/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/core/slots/buildToolsSlot.js +1 -1
- package/dist/core/slots/buildToolsSlot.js.map +1 -1
- package/dist/esm/adapters/identity/jwks.d.ts +2 -2
- package/dist/esm/adapters/identity/verify/claims.d.ts +3 -3
- package/dist/esm/adapters/identity/verify/claims.js +3 -3
- package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.d.ts +3 -2
- package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js +3 -2
- package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
- package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts +6 -5
- package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.js +6 -5
- package/dist/esm/adapters/mcp/agentcoreRuntime/sessionBusy.js.map +1 -1
- package/dist/esm/adapters/mcp/agentcoreRuntime/transport.d.ts +3 -1
- package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js +9 -7
- package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
- package/dist/esm/answer-account/account.js +16 -4
- package/dist/esm/answer-account/account.js.map +1 -1
- package/dist/esm/answer-account/facts/howSure.js +10 -22
- package/dist/esm/answer-account/facts/howSure.js.map +1 -1
- package/dist/esm/core/Agent.d.ts +2 -1
- package/dist/esm/core/Agent.js +26 -3
- package/dist/esm/core/Agent.js.map +1 -1
- package/dist/esm/core/agent/AgentBuilder.d.ts +22 -1
- package/dist/esm/core/agent/AgentBuilder.js +69 -12
- package/dist/esm/core/agent/AgentBuilder.js.map +1 -1
- package/dist/esm/core/agent/assessment/assess.js +15 -4
- package/dist/esm/core/agent/assessment/assess.js.map +1 -1
- package/dist/esm/core/agent/assessment/compose.d.ts +82 -5
- package/dist/esm/core/agent/assessment/compose.js +148 -14
- package/dist/esm/core/agent/assessment/compose.js.map +1 -1
- package/dist/esm/core/agent/assessment/reasons.d.ts +17 -1
- package/dist/esm/core/agent/assessment/reasons.js +35 -1
- package/dist/esm/core/agent/assessment/reasons.js.map +1 -1
- package/dist/esm/core/agent/assessment/sources.d.ts +66 -0
- package/dist/esm/core/agent/assessment/sources.js +201 -0
- package/dist/esm/core/agent/assessment/sources.js.map +1 -0
- package/dist/esm/core/agent/assessment/stage.d.ts +17 -4
- package/dist/esm/core/agent/assessment/stage.js +16 -5
- package/dist/esm/core/agent/assessment/stage.js.map +1 -1
- package/dist/esm/core/agent/assessment/types.d.ts +37 -0
- package/dist/esm/core/agent/buildAgentChart.d.ts +8 -0
- package/dist/esm/core/agent/buildAgentChart.js.map +1 -1
- package/dist/esm/core/agent/buildToolRegistry.js +5 -2
- package/dist/esm/core/agent/buildToolRegistry.js.map +1 -1
- package/dist/esm/core/agent/evidence/evidenceIndex.d.ts +12 -2
- package/dist/esm/core/agent/evidence/evidenceIndex.js +30 -2
- package/dist/esm/core/agent/evidence/evidenceIndex.js.map +1 -1
- package/dist/esm/core/agent/evidence/extract.js +35 -6
- package/dist/esm/core/agent/evidence/extract.js.map +1 -1
- package/dist/esm/core/agent/evidence/figures.d.ts +6 -0
- package/dist/esm/core/agent/evidence/figures.js +32 -4
- package/dist/esm/core/agent/evidence/figures.js.map +1 -1
- package/dist/esm/core/agent/evidence/numberPrecision.d.ts +29 -1
- package/dist/esm/core/agent/evidence/numberPrecision.js +56 -1
- package/dist/esm/core/agent/evidence/numberPrecision.js.map +1 -1
- package/dist/esm/core/agent/honesty/mounts.d.ts +11 -2
- package/dist/esm/core/agent/honesty/mounts.js.map +1 -1
- package/dist/esm/core/agent/stages/prepareFinal.d.ts +19 -3
- package/dist/esm/core/agent/stages/prepareFinal.js +33 -17
- package/dist/esm/core/agent/stages/prepareFinal.js.map +1 -1
- package/dist/esm/core/agent/stages/route.js +2 -1
- package/dist/esm/core/agent/stages/route.js.map +1 -1
- package/dist/esm/core/agent/stages/toolCalls.js +14 -1
- package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/esm/core/agent/types.d.ts +16 -2
- package/dist/esm/core/slots/buildToolsSlot.js +1 -1
- package/dist/esm/core/slots/buildToolsSlot.js.map +1 -1
- package/dist/esm/events/payloads.d.ts +194 -0
- package/dist/esm/events/registry.d.ts +3 -1
- package/dist/esm/events/registry.js +2 -0
- package/dist/esm/events/registry.js.map +1 -1
- package/dist/esm/hosting/doorGuard.d.ts +3 -3
- package/dist/esm/hosting/doorGuard.js +2 -2
- package/dist/esm/hosting/nodeHost.d.ts +1 -1
- package/dist/esm/lib/displayName.d.ts +81 -0
- package/dist/esm/lib/displayName.js +119 -0
- package/dist/esm/lib/displayName.js.map +1 -0
- package/dist/esm/mcp/callLifetime.d.ts +49 -0
- package/dist/esm/mcp/callLifetime.js +99 -0
- package/dist/esm/mcp/callLifetime.js.map +1 -0
- package/dist/esm/mcp/mcpClient.d.ts +4 -1
- package/dist/esm/mcp/mcpClient.js +70 -28
- package/dist/esm/mcp/mcpClient.js.map +1 -1
- package/dist/esm/mcp/requestLedger.d.ts +97 -0
- package/dist/esm/mcp/requestLedger.js +192 -0
- package/dist/esm/mcp/requestLedger.js.map +1 -0
- package/dist/esm/mcp/seriesEvidence.d.ts +102 -0
- package/dist/esm/mcp/seriesEvidence.js +246 -0
- package/dist/esm/mcp/seriesEvidence.js.map +1 -0
- package/dist/esm/mcp/throttleRetry.d.ts +70 -35
- package/dist/esm/mcp/throttleRetry.js +181 -54
- package/dist/esm/mcp/throttleRetry.js.map +1 -1
- package/dist/esm/mcp/types.d.ts +12 -7
- package/dist/esm/redaction/knownStrings.js +30 -0
- package/dist/esm/redaction/knownStrings.js.map +1 -1
- package/dist/esm/security/PermissionPolicy.d.ts +1 -1
- package/dist/esm/security/PermissionPolicy.js +1 -1
- package/dist/esm/semantics/coverage/answer.d.ts +9 -1
- package/dist/esm/semantics/coverage/answer.js +50 -10
- package/dist/esm/semantics/coverage/answer.js.map +1 -1
- package/dist/esm/strategies/defaults/chatBubbleLiveStatus.d.ts +1 -1
- package/dist/esm/strategies/defaults/chatBubbleLiveStatus.js +1 -1
- package/dist/esm/tool-lint/analyze.d.ts +1 -1
- package/dist/esm/tool-lint/analyze.js +1 -1
- package/dist/esm/tool-lint/rules.d.ts +3 -3
- package/dist/esm/tool-lint/rules.js +3 -3
- package/dist/esm/tools/requestEvidence.d.ts +78 -0
- package/dist/esm/tools/requestEvidence.js +331 -0
- package/dist/esm/tools/requestEvidence.js.map +1 -0
- package/dist/esm/tools/tools.d.ts +30 -0
- package/dist/esm/tools/tools.js +16 -0
- package/dist/esm/tools/tools.js.map +1 -1
- package/dist/events/registry.js +2 -0
- package/dist/events/registry.js.map +1 -1
- package/dist/hosting/doorGuard.js +2 -2
- package/dist/lib/displayName.js +125 -0
- package/dist/lib/displayName.js.map +1 -0
- package/dist/mcp/callLifetime.js +103 -0
- package/dist/mcp/callLifetime.js.map +1 -0
- package/dist/mcp/mcpClient.js +69 -27
- package/dist/mcp/mcpClient.js.map +1 -1
- package/dist/mcp/requestLedger.js +196 -0
- package/dist/mcp/requestLedger.js.map +1 -0
- package/dist/mcp/seriesEvidence.js +251 -0
- package/dist/mcp/seriesEvidence.js.map +1 -0
- package/dist/mcp/throttleRetry.js +184 -55
- package/dist/mcp/throttleRetry.js.map +1 -1
- package/dist/redaction/knownStrings.js +30 -0
- package/dist/redaction/knownStrings.js.map +1 -1
- package/dist/security/PermissionPolicy.js +1 -1
- package/dist/semantics/coverage/answer.js +49 -9
- package/dist/semantics/coverage/answer.js.map +1 -1
- package/dist/strategies/defaults/chatBubbleLiveStatus.js +1 -1
- package/dist/tool-lint/analyze.js +1 -1
- package/dist/tool-lint/rules.js +3 -3
- package/dist/tools/requestEvidence.js +337 -0
- package/dist/tools/requestEvidence.js.map +1 -0
- package/dist/tools/tools.js +18 -1
- package/dist/tools/tools.js.map +1 -1
- package/dist/types/adapters/identity/jwks.d.ts +2 -2
- package/dist/types/adapters/identity/verify/claims.d.ts +3 -3
- package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts +3 -2
- package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts.map +1 -1
- package/dist/types/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts +6 -5
- package/dist/types/adapters/mcp/agentcoreRuntime/sessionBusy.d.ts.map +1 -1
- package/dist/types/adapters/mcp/agentcoreRuntime/transport.d.ts +3 -1
- package/dist/types/adapters/mcp/agentcoreRuntime/transport.d.ts.map +1 -1
- package/dist/types/answer-account/account.d.ts.map +1 -1
- package/dist/types/answer-account/facts/howSure.d.ts.map +1 -1
- package/dist/types/core/Agent.d.ts +2 -1
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/core/agent/AgentBuilder.d.ts +22 -1
- package/dist/types/core/agent/AgentBuilder.d.ts.map +1 -1
- package/dist/types/core/agent/assessment/assess.d.ts.map +1 -1
- package/dist/types/core/agent/assessment/compose.d.ts +82 -5
- package/dist/types/core/agent/assessment/compose.d.ts.map +1 -1
- package/dist/types/core/agent/assessment/reasons.d.ts +17 -1
- package/dist/types/core/agent/assessment/reasons.d.ts.map +1 -1
- package/dist/types/core/agent/assessment/sources.d.ts +67 -0
- package/dist/types/core/agent/assessment/sources.d.ts.map +1 -0
- package/dist/types/core/agent/assessment/stage.d.ts +17 -4
- package/dist/types/core/agent/assessment/stage.d.ts.map +1 -1
- package/dist/types/core/agent/assessment/types.d.ts +37 -0
- package/dist/types/core/agent/assessment/types.d.ts.map +1 -1
- package/dist/types/core/agent/buildAgentChart.d.ts +8 -0
- package/dist/types/core/agent/buildAgentChart.d.ts.map +1 -1
- package/dist/types/core/agent/buildToolRegistry.d.ts.map +1 -1
- package/dist/types/core/agent/evidence/evidenceIndex.d.ts +12 -2
- package/dist/types/core/agent/evidence/evidenceIndex.d.ts.map +1 -1
- package/dist/types/core/agent/evidence/extract.d.ts.map +1 -1
- package/dist/types/core/agent/evidence/figures.d.ts +6 -0
- package/dist/types/core/agent/evidence/figures.d.ts.map +1 -1
- package/dist/types/core/agent/evidence/numberPrecision.d.ts +29 -1
- package/dist/types/core/agent/evidence/numberPrecision.d.ts.map +1 -1
- package/dist/types/core/agent/honesty/mounts.d.ts +11 -2
- package/dist/types/core/agent/honesty/mounts.d.ts.map +1 -1
- package/dist/types/core/agent/stages/prepareFinal.d.ts +19 -3
- package/dist/types/core/agent/stages/prepareFinal.d.ts.map +1 -1
- package/dist/types/core/agent/stages/route.d.ts.map +1 -1
- package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
- package/dist/types/core/agent/types.d.ts +16 -2
- package/dist/types/core/agent/types.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +194 -0
- package/dist/types/events/payloads.d.ts.map +1 -1
- package/dist/types/events/registry.d.ts +3 -1
- package/dist/types/events/registry.d.ts.map +1 -1
- package/dist/types/hosting/doorGuard.d.ts +3 -3
- package/dist/types/hosting/nodeHost.d.ts +1 -1
- package/dist/types/lib/displayName.d.ts +82 -0
- package/dist/types/lib/displayName.d.ts.map +1 -0
- package/dist/types/mcp/callLifetime.d.ts +50 -0
- package/dist/types/mcp/callLifetime.d.ts.map +1 -0
- package/dist/types/mcp/mcpClient.d.ts +4 -1
- package/dist/types/mcp/mcpClient.d.ts.map +1 -1
- package/dist/types/mcp/requestLedger.d.ts +98 -0
- package/dist/types/mcp/requestLedger.d.ts.map +1 -0
- package/dist/types/mcp/seriesEvidence.d.ts +103 -0
- package/dist/types/mcp/seriesEvidence.d.ts.map +1 -0
- package/dist/types/mcp/throttleRetry.d.ts +70 -35
- package/dist/types/mcp/throttleRetry.d.ts.map +1 -1
- package/dist/types/mcp/types.d.ts +12 -7
- package/dist/types/mcp/types.d.ts.map +1 -1
- package/dist/types/redaction/knownStrings.d.ts.map +1 -1
- package/dist/types/security/PermissionPolicy.d.ts +1 -1
- package/dist/types/semantics/coverage/answer.d.ts +9 -1
- package/dist/types/semantics/coverage/answer.d.ts.map +1 -1
- package/dist/types/strategies/defaults/chatBubbleLiveStatus.d.ts +1 -1
- package/dist/types/tool-lint/analyze.d.ts +1 -1
- package/dist/types/tool-lint/rules.d.ts +3 -3
- package/dist/types/tools/requestEvidence.d.ts +79 -0
- package/dist/types/tools/requestEvidence.d.ts.map +1 -0
- package/dist/types/tools/tools.d.ts +30 -0
- package/dist/types/tools/tools.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* displayName — the ONE rule for a tool's `displayName` (the app's own words
|
|
3
|
+
* for what a call of the tool does, read by a person), and the ONE way the
|
|
4
|
+
* library names a set of calls in those words: the declared ones named, the
|
|
5
|
+
* rest counted.
|
|
6
|
+
*
|
|
7
|
+
* Pattern: two pure functions and one small reader, no state.
|
|
8
|
+
* Role: Leaf. Asked for the RULE by `tools/tools.ts` · `defineTool` and by
|
|
9
|
+
* the registration funnel (`core/agent/buildToolRegistry.ts`), and for
|
|
10
|
+
* the NAMING by the two texts the library appends after an answer —
|
|
11
|
+
* the standing line (`core/agent/assessment/compose.ts`) and the
|
|
12
|
+
* limits block (`semantics/coverage/answer.ts`). Those two cannot
|
|
13
|
+
* import each other, so the naming lives here and they cannot name
|
|
14
|
+
* the same calls in two different ways.
|
|
15
|
+
* Emits: N/A.
|
|
16
|
+
*
|
|
17
|
+
* ## Why only the app's words
|
|
18
|
+
*
|
|
19
|
+
* A tool's registered name is the MODEL's vocabulary (`load_attachment`), and
|
|
20
|
+
* an app may forbid showing it to the people it serves. This module never
|
|
21
|
+
* prints it: a call is named only by the words its tool declared, and a call
|
|
22
|
+
* whose tool declared none is counted ("and 1 other call"), never named. A
|
|
23
|
+
* caller that gets `undefined` back says what it always said. Not every
|
|
24
|
+
* surface asks this module yet — the time layer's limits lines and the
|
|
25
|
+
* answer account's rows still print the registered name (a known follow-up).
|
|
26
|
+
*
|
|
27
|
+
* ## Why the plain-line rule
|
|
28
|
+
*
|
|
29
|
+
* The words reach a person verbatim, after an answer, so they are held to the
|
|
30
|
+
* rule every declared label a report prints is held to (`lib/plainLine.ts` ·
|
|
31
|
+
* `plainLineProblem`: no control, line or paragraph separator, or invisible
|
|
32
|
+
* format character — a bidi override would reverse what the person reads),
|
|
33
|
+
* judged BEFORE the length, and capped at the 60 characters a skill's `title`
|
|
34
|
+
* and an account label are capped at.
|
|
35
|
+
*/
|
|
36
|
+
import { plainLineProblem } from './plainLine.js';
|
|
37
|
+
/** The longest display name a person reads — the cap every declared label a report prints has. */
|
|
38
|
+
export const MAX_DISPLAY_NAME_CHARS = 60;
|
|
39
|
+
/**
|
|
40
|
+
* At most this many declared names in one phrase; any further call is counted
|
|
41
|
+
* with the calls whose tools declared none. A line for a person, not a list.
|
|
42
|
+
*/
|
|
43
|
+
export const MAX_NAMED_CALLS = 3;
|
|
44
|
+
/**
|
|
45
|
+
* Why `value` is not a display name, or `undefined` when it is — judged on the
|
|
46
|
+
* trimmed text (the text a person would read). `label` names the field in the
|
|
47
|
+
* sentence, so a refusal says where it was written.
|
|
48
|
+
*/
|
|
49
|
+
export function displayNameProblem(label, value) {
|
|
50
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
51
|
+
return (`${label} must be a non-empty string — the app's own words for what a call of this ` +
|
|
52
|
+
`tool does, read by a person (got ${typeof value === 'string' ? JSON.stringify(value) : typeof value}). Omit it to ` +
|
|
53
|
+
'leave the call unnamed.');
|
|
54
|
+
}
|
|
55
|
+
const text = value.trim();
|
|
56
|
+
const notPlain = plainLineProblem(label, text);
|
|
57
|
+
if (notPlain !== undefined)
|
|
58
|
+
return notPlain;
|
|
59
|
+
if (text.length > MAX_DISPLAY_NAME_CHARS) {
|
|
60
|
+
return `${label} is ${text.length} characters; the limit is ${MAX_DISPLAY_NAME_CHARS}.`;
|
|
61
|
+
}
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The display name a person may read — trimmed — or `undefined`. A value the
|
|
66
|
+
* rule refuses is never printed: a tool assembled by hand, or served by a
|
|
67
|
+
* ToolProvider after the agent was built, is read through this too.
|
|
68
|
+
*/
|
|
69
|
+
export function readDisplayName(value) {
|
|
70
|
+
return displayNameProblem('displayName', value) === undefined
|
|
71
|
+
? value.trim()
|
|
72
|
+
: undefined;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The calls, named in the app's words — each distinct declared name once, in
|
|
76
|
+
* the calls' order, at most {@link MAX_NAMED_CALLS}; every other call counted,
|
|
77
|
+
* with `alsoUnnamed` (calls the record does not name at all). `calls` holds one
|
|
78
|
+
* entry per CALL (the caller has already said each call once), each with its
|
|
79
|
+
* tool's registered name — the key a declared name is looked up by, never
|
|
80
|
+
* printed:
|
|
81
|
+
*
|
|
82
|
+
* - `loading the attached data`
|
|
83
|
+
* - `loading the attached data and searching the catalog`
|
|
84
|
+
* - `loading the attached data and 1 other call`
|
|
85
|
+
*
|
|
86
|
+
* `undefined` when no call's tool declared a name: the caller then says what
|
|
87
|
+
* it always said — the registered name is never the fallback.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* namedCalls(
|
|
92
|
+
* [{ toolCallId: 'c1', toolName: 'load_attachment' }, { toolCallId: 'c2', toolName: 'list_runs' }],
|
|
93
|
+
* 0,
|
|
94
|
+
* (tool) => (tool === 'load_attachment' ? 'loading the attached data' : undefined),
|
|
95
|
+
* ); // 'loading the attached data and 1 other call'
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export function namedCalls(calls, alsoUnnamed, displayNameOf) {
|
|
99
|
+
const named = [];
|
|
100
|
+
let rest = alsoUnnamed;
|
|
101
|
+
for (const call of calls) {
|
|
102
|
+
const words = displayNameOf(call.toolName);
|
|
103
|
+
if (words === undefined)
|
|
104
|
+
rest += 1;
|
|
105
|
+
else if (named.includes(words))
|
|
106
|
+
continue;
|
|
107
|
+
else if (named.length < MAX_NAMED_CALLS)
|
|
108
|
+
named.push(words);
|
|
109
|
+
else
|
|
110
|
+
rest += 1;
|
|
111
|
+
}
|
|
112
|
+
if (named.length === 0)
|
|
113
|
+
return undefined;
|
|
114
|
+
const parts = rest > 0 ? [...named, `${rest} other ${rest === 1 ? 'call' : 'calls'}`] : named;
|
|
115
|
+
return parts.length === 1
|
|
116
|
+
? parts[0]
|
|
117
|
+
: `${parts.slice(0, -1).join(', ')} and ${parts[parts.length - 1]}`;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=displayName.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"displayName.js","sourceRoot":"","sources":["../../../src/lib/displayName.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,kGAAkG;AAClG,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAEzC;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AAEjC;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAa,EAAE,KAAc;IAC9D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3D,OAAO,CACL,GAAG,KAAK,4EAA4E;YACpF,oCACE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,KAC7D,gBAAgB;YAChB,yBAAyB,CAC1B,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC1B,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC/C,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IAC5C,IAAI,IAAI,CAAC,MAAM,GAAG,sBAAsB,EAAE,CAAC;QACzC,OAAO,GAAG,KAAK,OAAO,IAAI,CAAC,MAAM,6BAA6B,sBAAsB,GAAG,CAAC;IAC1F,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,kBAAkB,CAAC,aAAa,EAAE,KAAK,CAAC,KAAK,SAAS;QAC3D,CAAC,CAAE,KAAgB,CAAC,IAAI,EAAE;QAC1B,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,UAAU,CACxB,KAA+C,EAC/C,WAAmB,EACnB,aAAuD;IAEvD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,IAAI,GAAG,WAAW,CAAC;IACvB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3C,IAAI,KAAK,KAAK,SAAS;YAAE,IAAI,IAAI,CAAC,CAAC;aAC9B,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,SAAS;aACpC,IAAI,KAAK,CAAC,MAAM,GAAG,eAAe;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;;YACtD,IAAI,IAAI,CAAC,CAAC;IACjB,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACzC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,GAAG,IAAI,UAAU,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC9F,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;QACvB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACV,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;AACxE,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* callLifetime — one MCP tool call, from the moment it is sent until it settles:
|
|
3
|
+
* what cancels it while it runs, and what its settling stops.
|
|
4
|
+
*
|
|
5
|
+
* Pattern: open / close around `callTool` (`mcpClient.ts` · `wrapMcpTool`).
|
|
6
|
+
* Role: The call's side of the evidence seam (`requestLedger.ts` is the
|
|
7
|
+
* transport's). Three things are true of a call while it runs, and
|
|
8
|
+
* none of them may outlive it:
|
|
9
|
+
*
|
|
10
|
+
* 1. ITS CANCELLATION reaches the SDK. The call's context signal (the run's,
|
|
11
|
+
* for a call the agent dispatched) and the client's own `signal` are linked
|
|
12
|
+
* into one signal the SDK request is given — so a cancelled run makes the
|
|
13
|
+
* SDK reject the call, drop its response handler and send the server
|
|
14
|
+
* `notifications/cancelled`, whether or not the request could be matched to
|
|
15
|
+
* the call. The link is undone when the call settles: the SDK keeps its
|
|
16
|
+
* abort listener on the signal it was given, and a link that outlived the
|
|
17
|
+
* call would cancel a request that had already finished.
|
|
18
|
+
* 2. ITS TICKET is issued, when the call carries the run's evidence port and
|
|
19
|
+
* the connection has a ledger, keyed by the request's params object.
|
|
20
|
+
* 3. ITS SETTLING ENDS ITS SERIES. However `callTool` settles — answered,
|
|
21
|
+
* failed, or given up by the SDK (its own timeout) — a retry series still
|
|
22
|
+
* sending the request is cut there and then, inside the call: it files
|
|
23
|
+
* `cancelled` before the call's result is read, and sends nothing more.
|
|
24
|
+
*
|
|
25
|
+
* In dev mode, a ticket that no request was bound to by the time the call
|
|
26
|
+
* settled, when a `tools/call` request DID go out, is named once per connection: the SDK copied
|
|
27
|
+
* the params, so the call's attempts could not be matched to it. Its
|
|
28
|
+
* cancellation still reached the request (1, and the ledger's own watch on
|
|
29
|
+
* `notifications/cancelled`).
|
|
30
|
+
*/
|
|
31
|
+
import type { RequestLedger } from './requestLedger.js';
|
|
32
|
+
/** A call that has been opened: the signal its SDK request runs under, and how to close it. */
|
|
33
|
+
export interface OpenCall {
|
|
34
|
+
/** What cancels the SDK request — absent when nothing can. */
|
|
35
|
+
readonly signal?: AbortSignal;
|
|
36
|
+
/** The call settled: undo the link, cut a series still sending, check the ticket was bound. */
|
|
37
|
+
close(): void;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Open one call.
|
|
41
|
+
*
|
|
42
|
+
* @param params the request's params object — the SDK hands this very object to
|
|
43
|
+
* the transport, which is how the ledger knows the request is this call's.
|
|
44
|
+
* @param ctx the call's context: its signal, and the run's evidence port if any.
|
|
45
|
+
* @param clientSignal the client's own `signal` (`McpClientOptions.signal`).
|
|
46
|
+
* @param ledger the connection's ledger, when the library built its transport.
|
|
47
|
+
* @param server the client's name, for the dev-mode note.
|
|
48
|
+
*/
|
|
49
|
+
export declare function openCall(params: object, ctx: unknown, clientSignal: AbortSignal | undefined, ledger: RequestLedger | undefined, server: string): OpenCall;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* callLifetime — one MCP tool call, from the moment it is sent until it settles:
|
|
3
|
+
* what cancels it while it runs, and what its settling stops.
|
|
4
|
+
*
|
|
5
|
+
* Pattern: open / close around `callTool` (`mcpClient.ts` · `wrapMcpTool`).
|
|
6
|
+
* Role: The call's side of the evidence seam (`requestLedger.ts` is the
|
|
7
|
+
* transport's). Three things are true of a call while it runs, and
|
|
8
|
+
* none of them may outlive it:
|
|
9
|
+
*
|
|
10
|
+
* 1. ITS CANCELLATION reaches the SDK. The call's context signal (the run's,
|
|
11
|
+
* for a call the agent dispatched) and the client's own `signal` are linked
|
|
12
|
+
* into one signal the SDK request is given — so a cancelled run makes the
|
|
13
|
+
* SDK reject the call, drop its response handler and send the server
|
|
14
|
+
* `notifications/cancelled`, whether or not the request could be matched to
|
|
15
|
+
* the call. The link is undone when the call settles: the SDK keeps its
|
|
16
|
+
* abort listener on the signal it was given, and a link that outlived the
|
|
17
|
+
* call would cancel a request that had already finished.
|
|
18
|
+
* 2. ITS TICKET is issued, when the call carries the run's evidence port and
|
|
19
|
+
* the connection has a ledger, keyed by the request's params object.
|
|
20
|
+
* 3. ITS SETTLING ENDS ITS SERIES. However `callTool` settles — answered,
|
|
21
|
+
* failed, or given up by the SDK (its own timeout) — a retry series still
|
|
22
|
+
* sending the request is cut there and then, inside the call: it files
|
|
23
|
+
* `cancelled` before the call's result is read, and sends nothing more.
|
|
24
|
+
*
|
|
25
|
+
* In dev mode, a ticket that no request was bound to by the time the call
|
|
26
|
+
* settled, when a `tools/call` request DID go out, is named once per connection: the SDK copied
|
|
27
|
+
* the params, so the call's attempts could not be matched to it. Its
|
|
28
|
+
* cancellation still reached the request (1, and the ledger's own watch on
|
|
29
|
+
* `notifications/cancelled`).
|
|
30
|
+
*/
|
|
31
|
+
import { isDevMode } from 'footprintjs';
|
|
32
|
+
import { eitherSignal, linkedController } from '../lib/abort.js';
|
|
33
|
+
import { requestEvidenceOf } from '../tools/requestEvidence.js';
|
|
34
|
+
/**
|
|
35
|
+
* Open one call.
|
|
36
|
+
*
|
|
37
|
+
* @param params the request's params object — the SDK hands this very object to
|
|
38
|
+
* the transport, which is how the ledger knows the request is this call's.
|
|
39
|
+
* @param ctx the call's context: its signal, and the run's evidence port if any.
|
|
40
|
+
* @param clientSignal the client's own `signal` (`McpClientOptions.signal`).
|
|
41
|
+
* @param ledger the connection's ledger, when the library built its transport.
|
|
42
|
+
* @param server the client's name, for the dev-mode note.
|
|
43
|
+
*/
|
|
44
|
+
export function openCall(params, ctx, clientSignal, ledger, server) {
|
|
45
|
+
const own = signalOf(ctx);
|
|
46
|
+
const link = own === undefined ? undefined : linkedController(own, clientSignal);
|
|
47
|
+
const signal = link?.controller.signal ?? clientSignal;
|
|
48
|
+
const sink = ledger === undefined ? undefined : requestEvidenceOf(ctx);
|
|
49
|
+
const settled = sink === undefined ? undefined : new AbortController();
|
|
50
|
+
const ticket = sink === undefined
|
|
51
|
+
? undefined
|
|
52
|
+
: { sink, signal: eitherSignal(signal, settled?.signal) };
|
|
53
|
+
const sentBefore = ledger?.toolCallsSent ?? 0;
|
|
54
|
+
if (ticket !== undefined)
|
|
55
|
+
ledger?.issue(params, ticket);
|
|
56
|
+
return {
|
|
57
|
+
...(signal !== undefined && { signal }),
|
|
58
|
+
close: () => {
|
|
59
|
+
settled?.abort(callSettled());
|
|
60
|
+
link?.unlink();
|
|
61
|
+
if (ticket !== undefined && ledger !== undefined) {
|
|
62
|
+
noteUnbound(ledger, ticket, sentBefore, server);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/** The call's own signal, when its context carries a real one. */
|
|
68
|
+
function signalOf(ctx) {
|
|
69
|
+
if (ctx === null || typeof ctx !== 'object' || typeof AbortSignal === 'undefined') {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
let signal;
|
|
73
|
+
try {
|
|
74
|
+
signal = ctx.signal;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
return signal instanceof AbortSignal ? signal : undefined;
|
|
80
|
+
}
|
|
81
|
+
/** Why a series is cut when its call settled first — a fixed sentence. */
|
|
82
|
+
function callSettled() {
|
|
83
|
+
return Object.assign(new Error('The tool call settled before its MCP request series did.'), {
|
|
84
|
+
name: 'AbortError',
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/** Dev mode, once per connection: a request went out for this call, but the ledger never matched it. */
|
|
88
|
+
function noteUnbound(ledger, ticket, sentBefore, server) {
|
|
89
|
+
if (!isDevMode() || ledger.wasBound(ticket) || ledger.toolCallsSent <= sentBefore)
|
|
90
|
+
return;
|
|
91
|
+
if (!ledger.firstUnbound())
|
|
92
|
+
return;
|
|
93
|
+
// eslint-disable-next-line no-console
|
|
94
|
+
console.warn(`[agentfootprint] mcpClient[${server}]: a tool call's request could not be matched to ` +
|
|
95
|
+
'the call, so its retry attempts were not recorded in the run. The MCP SDK copied the ' +
|
|
96
|
+
"request's params before sending them. The call itself is unaffected, and its " +
|
|
97
|
+
'cancellation still reached the request.');
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=callLifetime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callLifetime.js","sourceRoot":"","sources":["../../../src/mcp/callLifetime.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,7 +33,10 @@
|
|
|
33
33
|
* `agentfootprint.stream.tool_start` / `tool_end` events
|
|
34
34
|
* when the agent calls them. Add `name: '<mcp-server>'` to
|
|
35
35
|
* `McpClientOptions` so observability surfaces can group
|
|
36
|
-
* tool calls by server.
|
|
36
|
+
* tool calls by server. On a transport this module builds,
|
|
37
|
+
* a call the agent dispatched also gets its request's retry
|
|
38
|
+
* series as `agentfootprint.tools.request_attempts`, filed by
|
|
39
|
+
* the series through the call's own port (`requestLedger.ts`).
|
|
37
40
|
*
|
|
38
41
|
* Lazy-require pattern: the `@modelcontextprotocol/sdk` peer-dep
|
|
39
42
|
* loads only when a consumer actually constructs a client. Tests
|
|
@@ -33,7 +33,10 @@
|
|
|
33
33
|
* `agentfootprint.stream.tool_start` / `tool_end` events
|
|
34
34
|
* when the agent calls them. Add `name: '<mcp-server>'` to
|
|
35
35
|
* `McpClientOptions` so observability surfaces can group
|
|
36
|
-
* tool calls by server.
|
|
36
|
+
* tool calls by server. On a transport this module builds,
|
|
37
|
+
* a call the agent dispatched also gets its request's retry
|
|
38
|
+
* series as `agentfootprint.tools.request_attempts`, filed by
|
|
39
|
+
* the series through the call's own port (`requestLedger.ts`).
|
|
37
40
|
*
|
|
38
41
|
* Lazy-require pattern: the `@modelcontextprotocol/sdk` peer-dep
|
|
39
42
|
* loads only when a consumer actually constructs a client. Tests
|
|
@@ -42,7 +45,9 @@
|
|
|
42
45
|
import { callMetaOf, readToolExtras } from './toolExtras.js';
|
|
43
46
|
import { readToolResult, resultModeOf } from './toolResult.js';
|
|
44
47
|
import { createVendingFetch } from './gatewayTransport.js';
|
|
45
|
-
import { retryingFetch } from './throttleRetry.js';
|
|
48
|
+
import { ledgeredFetch, retryingFetch } from './throttleRetry.js';
|
|
49
|
+
import { RequestLedger } from './requestLedger.js';
|
|
50
|
+
import { openCall } from './callLifetime.js';
|
|
46
51
|
import { refuseConflictingOptions } from './connectionRefusals.js';
|
|
47
52
|
import { sdkLoadFailure } from './sdkLoadFailure.js';
|
|
48
53
|
import { transportUrl } from './transportUrl.js';
|
|
@@ -82,7 +87,7 @@ export async function mcpClient(opts) {
|
|
|
82
87
|
// Before anything connects: an option that names a behaviour which cannot
|
|
83
88
|
// happen on the chosen arm is a defect, not a preference.
|
|
84
89
|
refuseConflictingOptions(opts, name);
|
|
85
|
-
const connection = await openConnection(opts);
|
|
90
|
+
const { connection, ledger } = await openConnection(opts);
|
|
86
91
|
// Tool cache so consumers calling `.tools()` more than once don't
|
|
87
92
|
// hammer the server. `.refresh()` invalidates it.
|
|
88
93
|
let cache = null;
|
|
@@ -98,7 +103,7 @@ export async function mcpClient(opts) {
|
|
|
98
103
|
const listed = opts.signal
|
|
99
104
|
? await connection.listTools(undefined, { signal: opts.signal })
|
|
100
105
|
: await connection.listTools();
|
|
101
|
-
return listed.tools.map((t) => wrapMcpTool(name, connection, t, opts.signal, resultMode));
|
|
106
|
+
return listed.tools.map((t) => wrapMcpTool(name, connection, t, opts.signal, resultMode, ledger));
|
|
102
107
|
};
|
|
103
108
|
return {
|
|
104
109
|
name,
|
|
@@ -122,19 +127,20 @@ export async function mcpClient(opts) {
|
|
|
122
127
|
},
|
|
123
128
|
};
|
|
124
129
|
}
|
|
125
|
-
// ─── Getting a connection ──────────────────────────────────────────
|
|
126
130
|
/**
|
|
127
131
|
* The one funnel every arm passes through, in precedence order: a connection
|
|
128
132
|
* you handed over, the internal test seam, then the library building one.
|
|
133
|
+
* Only the last has a ledger: a connection built elsewhere has no retry series
|
|
134
|
+
* of ours to file a call's attempts.
|
|
129
135
|
*
|
|
130
136
|
* A call with neither `connection` nor `sdk` reaches `resolveClient` with two
|
|
131
137
|
* `undefined` arguments and takes the identical path it always took.
|
|
132
138
|
*/
|
|
133
139
|
async function openConnection(opts) {
|
|
134
140
|
if (opts.connection !== undefined)
|
|
135
|
-
return opts.connection;
|
|
141
|
+
return { connection: opts.connection };
|
|
136
142
|
if (opts._client !== undefined)
|
|
137
|
-
return opts._client;
|
|
143
|
+
return { connection: opts._client };
|
|
138
144
|
// `refuseConflictingOptions` has already refused the case where this is
|
|
139
145
|
// absent, so the assertion documents that guarantee rather than assuming it.
|
|
140
146
|
const transport = opts.transport;
|
|
@@ -148,13 +154,13 @@ async function resolveClient(transport, clientInfo, signal, retryOnThrottle, sdk
|
|
|
148
154
|
const client = new mod.Client(clientInfo ?? DEFAULT_CLIENT_INFO, {
|
|
149
155
|
capabilities: {},
|
|
150
156
|
});
|
|
151
|
-
const
|
|
157
|
+
const built = await buildTransport(transport, retryOnThrottle, sdk);
|
|
152
158
|
// Same rule as callTool: options ride beside the transport, never inside it.
|
|
153
159
|
if (signal)
|
|
154
|
-
await client.connect(
|
|
160
|
+
await client.connect(built.transport, { signal });
|
|
155
161
|
else
|
|
156
|
-
await client.connect(
|
|
157
|
-
return client;
|
|
162
|
+
await client.connect(built.transport);
|
|
163
|
+
return { connection: client, ...(built.ledger !== undefined && { ledger: built.ledger }) };
|
|
158
164
|
}
|
|
159
165
|
/**
|
|
160
166
|
* An injected `sdk` is checked before anything is built, so a wrong import (a
|
|
@@ -218,12 +224,15 @@ async function buildTransport(t, retryOnThrottle, sdk) {
|
|
|
218
224
|
"reach the server over `transport: { transport: 'http', url }` instead.",
|
|
219
225
|
}));
|
|
220
226
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
+
// No fetch, so no retry series: a stdio call has no attempts to file.
|
|
228
|
+
return {
|
|
229
|
+
transport: new stdioMod.StdioClientTransport({
|
|
230
|
+
command: t.command,
|
|
231
|
+
args: t.args ? [...t.args] : [],
|
|
232
|
+
...(t.env && { env: { ...t.env } }),
|
|
233
|
+
...(t.cwd !== undefined && { cwd: t.cwd }),
|
|
234
|
+
}),
|
|
235
|
+
};
|
|
227
236
|
}
|
|
228
237
|
// http + gateway transports both ride Streamable HTTP. They differ only in
|
|
229
238
|
// WHEN the auth headers are decided: `http` fixes them at construction,
|
|
@@ -237,6 +246,12 @@ async function buildTransport(t, retryOnThrottle, sdk) {
|
|
|
237
246
|
// did before 8.11.0. A transport fetch that already runs a retry series of
|
|
238
247
|
// its own (AgentCore Runtime's) is never wrapped: `retryingFetch` joins the
|
|
239
248
|
// 429 rule to that series, so one call is one series.
|
|
249
|
+
//
|
|
250
|
+
// The ledger joins the same series, so each request a dispatched tool call
|
|
251
|
+
// sends files its attempts into that call's run; the transport's `send` is
|
|
252
|
+
// watched to bind each request to its call (`requestLedger.ts`). A fetch that
|
|
253
|
+
// runs no series (retry off) gets no ledger: there is nothing to file.
|
|
254
|
+
const ledger = new RequestLedger();
|
|
240
255
|
if (t.transport === 'gateway') {
|
|
241
256
|
// The consumer's own `fetch` (9.32.0) goes UNDERNEATH the vending, not
|
|
242
257
|
// beside it: `createVendingFetch` resolves the credential, applies it to
|
|
@@ -245,19 +260,34 @@ async function buildTransport(t, retryOnThrottle, sdk) {
|
|
|
245
260
|
// credential is still vended per request. Passing `undefined` is the
|
|
246
261
|
// default global `fetch`, which is byte-identical to every release before
|
|
247
262
|
// the seam existed.
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
263
|
+
const gatewayFetch = retryingFetch(createVendingFetch(t, t.fetch), retryOnThrottle);
|
|
264
|
+
const ledgered = gatewayFetch && ledgeredFetch(gatewayFetch, ledger);
|
|
265
|
+
return watched(new httpMod.StreamableHTTPClientTransport(transportUrl(t.url, 'mcpClient'), {
|
|
266
|
+
fetch: ledgered ?? gatewayFetch,
|
|
267
|
+
}), ledgered && ledger);
|
|
251
268
|
}
|
|
252
269
|
// Both options ride the SAME SDK transport, and both are forwarded when both
|
|
253
270
|
// are given. The SDK folds `requestInit.headers` into the `init.headers` it
|
|
254
271
|
// hands the custom fetch, so a signer sees the static headers and has the
|
|
255
272
|
// final word over the bytes — see `McpHttpTransport.fetch`.
|
|
256
273
|
const httpFetch = retryingFetch(t.fetch, retryOnThrottle);
|
|
257
|
-
|
|
274
|
+
const ledgered = httpFetch && ledgeredFetch(httpFetch, ledger);
|
|
275
|
+
const fetch = ledgered ?? httpFetch;
|
|
276
|
+
return watched(new httpMod.StreamableHTTPClientTransport(transportUrl(t.url, 'mcpClient'), {
|
|
258
277
|
...(t.headers && { requestInit: { headers: { ...t.headers } } }),
|
|
259
|
-
...(
|
|
260
|
-
});
|
|
278
|
+
...(fetch && { fetch }),
|
|
279
|
+
}), ledgered && ledger);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* `transport` with its sends watched by `ledger` — the SAME object, its own
|
|
283
|
+
* `send` installed in place. As it is, with no ledger, when there is none or it
|
|
284
|
+
* cannot be watched: then no call expects its attempts filed.
|
|
285
|
+
*/
|
|
286
|
+
function watched(transport, ledger) {
|
|
287
|
+
if (ledger === undefined || transport === null || typeof transport !== 'object') {
|
|
288
|
+
return { transport };
|
|
289
|
+
}
|
|
290
|
+
return ledger.watch(transport) === undefined ? { transport } : { transport, ledger };
|
|
261
291
|
}
|
|
262
292
|
/** The Node loader path for Streamable HTTP — reached only with no `sdk`. */
|
|
263
293
|
function loadHttpModule(transport) {
|
|
@@ -277,7 +307,7 @@ function loadHttpModule(transport) {
|
|
|
277
307
|
}
|
|
278
308
|
}
|
|
279
309
|
// ─── Tool wrapping ─────────────────────────────────────────────────
|
|
280
|
-
function wrapMcpTool(serverName, connection, mcp, signal, resultMode) {
|
|
310
|
+
function wrapMcpTool(serverName, connection, mcp, signal, resultMode, ledger) {
|
|
281
311
|
const tool = {
|
|
282
312
|
schema: {
|
|
283
313
|
name: mcp.name,
|
|
@@ -318,10 +348,22 @@ function wrapMcpTool(serverName, connection, mcp, signal, resultMode) {
|
|
|
318
348
|
arguments: argsObj,
|
|
319
349
|
...(ctx?.time !== undefined && { _meta: callMetaOf(ctx.time) }),
|
|
320
350
|
};
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
351
|
+
// The call's lifetime (`callLifetime.ts`): its context's signal and the
|
|
352
|
+
// client's cancel the SDK request while it runs; a call the agent
|
|
353
|
+
// dispatched issues a ticket keyed by THIS params object — the one the
|
|
354
|
+
// SDK hands the transport — so the retry series that sends it files its
|
|
355
|
+
// attempts into the call's run; and however the call settles, a series
|
|
356
|
+
// still sending is cut, inside the call. Nothing is added to the request.
|
|
357
|
+
const call = openCall(params, ctx, signal, ledger, serverName);
|
|
358
|
+
try {
|
|
359
|
+
const result = call.signal
|
|
360
|
+
? await connection.callTool(params, undefined, { signal: call.signal })
|
|
361
|
+
: await connection.callTool(params);
|
|
362
|
+
return readToolResult(result, mcp.name, serverName, resultMode);
|
|
363
|
+
}
|
|
364
|
+
finally {
|
|
365
|
+
call.close();
|
|
366
|
+
}
|
|
325
367
|
},
|
|
326
368
|
};
|
|
327
369
|
return tool;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcpClient.js","sourceRoot":"","sources":["../../../src/mcp/mcpClient.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"mcpClient.js","sourceRoot":"","sources":["../../../src/mcp/mcpClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
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
|
+
}
|