agentfootprint 12.1.0 → 12.2.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 +3 -1
- package/ai-instructions/claude-code/SKILL.md +1 -1
- package/dist/adapters/mcp/agentcoreRuntime/invoke.js +113 -7
- package/dist/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
- package/dist/adapters/mcp/agentcoreRuntime/session.js +21 -21
- package/dist/adapters/mcp/agentcoreRuntime/session.js.map +1 -1
- package/dist/adapters/mcp/agentcoreRuntime/transport.js +79 -5
- package/dist/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
- package/dist/core/Agent.js +6 -0
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/agent/stages/toolCalls.js +4 -0
- package/dist/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/core/slots/buildToolsSlot.js +8 -0
- package/dist/core/slots/buildToolsSlot.js.map +1 -1
- package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.d.ts +23 -4
- package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js +112 -6
- package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
- package/dist/esm/adapters/mcp/agentcoreRuntime/session.d.ts +20 -6
- package/dist/esm/adapters/mcp/agentcoreRuntime/session.js +21 -21
- package/dist/esm/adapters/mcp/agentcoreRuntime/session.js.map +1 -1
- package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js +81 -7
- package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
- package/dist/esm/core/Agent.js +6 -0
- package/dist/esm/core/Agent.js.map +1 -1
- package/dist/esm/core/agent/stages/toolCalls.js +4 -0
- package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
- package/dist/esm/core/slots/buildToolsSlot.d.ts +12 -0
- package/dist/esm/core/slots/buildToolsSlot.js +8 -0
- package/dist/esm/core/slots/buildToolsSlot.js.map +1 -1
- package/dist/esm/events/payloads.d.ts +41 -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/identity/types.d.ts +7 -3
- package/dist/esm/identity/types.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +4 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/boundedJson.d.ts +14 -7
- package/dist/esm/lib/boundedJson.js +14 -7
- package/dist/esm/lib/boundedJson.js.map +1 -1
- package/dist/esm/mcp/callLifetime.js +5 -2
- package/dist/esm/mcp/callLifetime.js.map +1 -1
- package/dist/esm/mcp/clientPort.d.ts +78 -0
- package/dist/esm/mcp/clientPort.js +33 -0
- package/dist/esm/mcp/clientPort.js.map +1 -0
- package/dist/esm/mcp/gatewayTransport.js +13 -3
- package/dist/esm/mcp/gatewayTransport.js.map +1 -1
- package/dist/esm/mcp/index.d.ts +9 -1
- package/dist/esm/mcp/index.js +8 -0
- package/dist/esm/mcp/index.js.map +1 -1
- package/dist/esm/mcp/mcpClient.d.ts +18 -1
- package/dist/esm/mcp/mcpClient.js +203 -43
- package/dist/esm/mcp/mcpClient.js.map +1 -1
- package/dist/esm/mcp/mockMcpClient.js +13 -0
- package/dist/esm/mcp/mockMcpClient.js.map +1 -1
- package/dist/esm/mcp/pool/boundTool.d.ts +58 -0
- package/dist/esm/mcp/pool/boundTool.js +218 -0
- package/dist/esm/mcp/pool/boundTool.js.map +1 -0
- package/dist/esm/mcp/pool/clientSet.d.ts +73 -0
- package/dist/esm/mcp/pool/clientSet.js +152 -0
- package/dist/esm/mcp/pool/clientSet.js.map +1 -0
- package/dist/esm/mcp/pool/definitions.d.ts +103 -0
- package/dist/esm/mcp/pool/definitions.js +168 -0
- package/dist/esm/mcp/pool/definitions.js.map +1 -0
- package/dist/esm/mcp/pool/errors.d.ts +76 -0
- package/dist/esm/mcp/pool/errors.js +91 -0
- package/dist/esm/mcp/pool/errors.js.map +1 -0
- package/dist/esm/mcp/pool/identityKey.d.ts +57 -0
- package/dist/esm/mcp/pool/identityKey.js +94 -0
- package/dist/esm/mcp/pool/identityKey.js.map +1 -0
- package/dist/esm/mcp/pool/lease.d.ts +36 -0
- package/dist/esm/mcp/pool/lease.js +51 -0
- package/dist/esm/mcp/pool/lease.js.map +1 -0
- package/dist/esm/mcp/pool/listTools.d.ts +33 -0
- package/dist/esm/mcp/pool/listTools.js +146 -0
- package/dist/esm/mcp/pool/listTools.js.map +1 -0
- package/dist/esm/mcp/pool/mcpClientPool.d.ts +121 -0
- package/dist/esm/mcp/pool/mcpClientPool.js +151 -0
- package/dist/esm/mcp/pool/mcpClientPool.js.map +1 -0
- package/dist/esm/mcp/pool/options.d.ts +183 -0
- package/dist/esm/mcp/pool/options.js +119 -0
- package/dist/esm/mcp/pool/options.js.map +1 -0
- package/dist/esm/mcp/pool/plan.d.ts +77 -0
- package/dist/esm/mcp/pool/plan.js +134 -0
- package/dist/esm/mcp/pool/plan.js.map +1 -0
- package/dist/esm/mcp/pool/pool.d.ts +307 -0
- package/dist/esm/mcp/pool/pool.js +1071 -0
- package/dist/esm/mcp/pool/pool.js.map +1 -0
- package/dist/esm/mcp/pool/pooledClient.d.ts +93 -0
- package/dist/esm/mcp/pool/pooledClient.js +90 -0
- package/dist/esm/mcp/pool/pooledClient.js.map +1 -0
- package/dist/esm/mcp/pool/record.d.ts +80 -0
- package/dist/esm/mcp/pool/record.js +75 -0
- package/dist/esm/mcp/pool/record.js.map +1 -0
- package/dist/esm/mcp/pool/sessionEnded.d.ts +24 -0
- package/dist/esm/mcp/pool/sessionEnded.js +31 -0
- package/dist/esm/mcp/pool/sessionEnded.js.map +1 -0
- package/dist/esm/mcp/pool/work.d.ts +116 -0
- package/dist/esm/mcp/pool/work.js +213 -0
- package/dist/esm/mcp/pool/work.js.map +1 -0
- package/dist/esm/mcp/requestGuard.d.ts +70 -0
- package/dist/esm/mcp/requestGuard.js +98 -0
- package/dist/esm/mcp/requestGuard.js.map +1 -0
- package/dist/esm/mcp/requestLedger.d.ts +35 -1
- package/dist/esm/mcp/requestLedger.js +76 -3
- package/dist/esm/mcp/requestLedger.js.map +1 -1
- package/dist/esm/mcp/seriesEvidence.d.ts +10 -6
- package/dist/esm/mcp/seriesEvidence.js +16 -7
- package/dist/esm/mcp/seriesEvidence.js.map +1 -1
- package/dist/esm/mcp/terminate.d.ts +94 -0
- package/dist/esm/mcp/terminate.js +184 -0
- package/dist/esm/mcp/terminate.js.map +1 -0
- package/dist/esm/mcp/throttleRetry.js +71 -7
- package/dist/esm/mcp/throttleRetry.js.map +1 -1
- package/dist/esm/mcp/types.d.ts +85 -7
- package/dist/esm/redaction/knownStrings.js +34 -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 +7 -1
- package/dist/esm/tool-providers/index.js.map +1 -1
- package/dist/esm/tools/mcpClientUse.d.ts +59 -0
- package/dist/esm/tools/mcpClientUse.js +216 -0
- package/dist/esm/tools/mcpClientUse.js.map +1 -0
- package/dist/esm/tools/toolProvider.d.ts +16 -0
- package/dist/esm/tools/toolSessions.d.ts +41 -0
- package/dist/esm/tools/toolSessions.js +41 -1
- package/dist/esm/tools/toolSessions.js.map +1 -1
- package/dist/events/registry.js +2 -0
- package/dist/events/registry.js.map +1 -1
- package/dist/identity/types.js.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/boundedJson.js +14 -7
- package/dist/lib/boundedJson.js.map +1 -1
- package/dist/mcp/callLifetime.js +5 -2
- package/dist/mcp/callLifetime.js.map +1 -1
- package/dist/mcp/clientPort.js +38 -0
- package/dist/mcp/clientPort.js.map +1 -0
- package/dist/mcp/gatewayTransport.js +13 -3
- package/dist/mcp/gatewayTransport.js.map +1 -1
- package/dist/mcp/index.js +16 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/mcpClient.js +207 -45
- package/dist/mcp/mcpClient.js.map +1 -1
- package/dist/mcp/mockMcpClient.js +13 -0
- package/dist/mcp/mockMcpClient.js.map +1 -1
- package/dist/mcp/pool/boundTool.js +223 -0
- package/dist/mcp/pool/boundTool.js.map +1 -0
- package/dist/mcp/pool/clientSet.js +157 -0
- package/dist/mcp/pool/clientSet.js.map +1 -0
- package/dist/mcp/pool/definitions.js +174 -0
- package/dist/mcp/pool/definitions.js.map +1 -0
- package/dist/mcp/pool/errors.js +96 -0
- package/dist/mcp/pool/errors.js.map +1 -0
- package/dist/mcp/pool/identityKey.js +99 -0
- package/dist/mcp/pool/identityKey.js.map +1 -0
- package/dist/mcp/pool/lease.js +55 -0
- package/dist/mcp/pool/lease.js.map +1 -0
- package/dist/mcp/pool/listTools.js +150 -0
- package/dist/mcp/pool/listTools.js.map +1 -0
- package/dist/mcp/pool/mcpClientPool.js +155 -0
- package/dist/mcp/pool/mcpClientPool.js.map +1 -0
- package/dist/mcp/pool/options.js +123 -0
- package/dist/mcp/pool/options.js.map +1 -0
- package/dist/mcp/pool/plan.js +140 -0
- package/dist/mcp/pool/plan.js.map +1 -0
- package/dist/mcp/pool/pool.js +1075 -0
- package/dist/mcp/pool/pool.js.map +1 -0
- package/dist/mcp/pool/pooledClient.js +94 -0
- package/dist/mcp/pool/pooledClient.js.map +1 -0
- package/dist/mcp/pool/record.js +80 -0
- package/dist/mcp/pool/record.js.map +1 -0
- package/dist/mcp/pool/sessionEnded.js +35 -0
- package/dist/mcp/pool/sessionEnded.js.map +1 -0
- package/dist/mcp/pool/work.js +219 -0
- package/dist/mcp/pool/work.js.map +1 -0
- package/dist/mcp/requestGuard.js +106 -0
- package/dist/mcp/requestGuard.js.map +1 -0
- package/dist/mcp/requestLedger.js +76 -3
- package/dist/mcp/requestLedger.js.map +1 -1
- package/dist/mcp/seriesEvidence.js +16 -7
- package/dist/mcp/seriesEvidence.js.map +1 -1
- package/dist/mcp/terminate.js +193 -0
- package/dist/mcp/terminate.js.map +1 -0
- package/dist/mcp/throttleRetry.js +71 -7
- package/dist/mcp/throttleRetry.js.map +1 -1
- package/dist/redaction/knownStrings.js +34 -0
- package/dist/redaction/knownStrings.js.map +1 -1
- package/dist/tool-providers/index.js +12 -1
- package/dist/tool-providers/index.js.map +1 -1
- package/dist/tools/mcpClientUse.js +225 -0
- package/dist/tools/mcpClientUse.js.map +1 -0
- package/dist/tools/toolSessions.js +44 -1
- package/dist/tools/toolSessions.js.map +1 -1
- package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts +23 -4
- package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts.map +1 -1
- package/dist/types/adapters/mcp/agentcoreRuntime/session.d.ts +20 -6
- package/dist/types/adapters/mcp/agentcoreRuntime/session.d.ts.map +1 -1
- package/dist/types/adapters/mcp/agentcoreRuntime/transport.d.ts.map +1 -1
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
- package/dist/types/core/slots/buildToolsSlot.d.ts +12 -0
- package/dist/types/core/slots/buildToolsSlot.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +41 -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/identity/types.d.ts +7 -3
- package/dist/types/identity/types.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/boundedJson.d.ts +14 -7
- package/dist/types/lib/boundedJson.d.ts.map +1 -1
- package/dist/types/mcp/callLifetime.d.ts.map +1 -1
- package/dist/types/mcp/clientPort.d.ts +79 -0
- package/dist/types/mcp/clientPort.d.ts.map +1 -0
- package/dist/types/mcp/gatewayTransport.d.ts.map +1 -1
- package/dist/types/mcp/index.d.ts +9 -1
- package/dist/types/mcp/index.d.ts.map +1 -1
- package/dist/types/mcp/mcpClient.d.ts +18 -1
- package/dist/types/mcp/mcpClient.d.ts.map +1 -1
- package/dist/types/mcp/mockMcpClient.d.ts.map +1 -1
- package/dist/types/mcp/pool/boundTool.d.ts +59 -0
- package/dist/types/mcp/pool/boundTool.d.ts.map +1 -0
- package/dist/types/mcp/pool/clientSet.d.ts +74 -0
- package/dist/types/mcp/pool/clientSet.d.ts.map +1 -0
- package/dist/types/mcp/pool/definitions.d.ts +104 -0
- package/dist/types/mcp/pool/definitions.d.ts.map +1 -0
- package/dist/types/mcp/pool/errors.d.ts +77 -0
- package/dist/types/mcp/pool/errors.d.ts.map +1 -0
- package/dist/types/mcp/pool/identityKey.d.ts +58 -0
- package/dist/types/mcp/pool/identityKey.d.ts.map +1 -0
- package/dist/types/mcp/pool/lease.d.ts +37 -0
- package/dist/types/mcp/pool/lease.d.ts.map +1 -0
- package/dist/types/mcp/pool/listTools.d.ts +34 -0
- package/dist/types/mcp/pool/listTools.d.ts.map +1 -0
- package/dist/types/mcp/pool/mcpClientPool.d.ts +122 -0
- package/dist/types/mcp/pool/mcpClientPool.d.ts.map +1 -0
- package/dist/types/mcp/pool/options.d.ts +184 -0
- package/dist/types/mcp/pool/options.d.ts.map +1 -0
- package/dist/types/mcp/pool/plan.d.ts +78 -0
- package/dist/types/mcp/pool/plan.d.ts.map +1 -0
- package/dist/types/mcp/pool/pool.d.ts +308 -0
- package/dist/types/mcp/pool/pool.d.ts.map +1 -0
- package/dist/types/mcp/pool/pooledClient.d.ts +94 -0
- package/dist/types/mcp/pool/pooledClient.d.ts.map +1 -0
- package/dist/types/mcp/pool/record.d.ts +81 -0
- package/dist/types/mcp/pool/record.d.ts.map +1 -0
- package/dist/types/mcp/pool/sessionEnded.d.ts +25 -0
- package/dist/types/mcp/pool/sessionEnded.d.ts.map +1 -0
- package/dist/types/mcp/pool/work.d.ts +117 -0
- package/dist/types/mcp/pool/work.d.ts.map +1 -0
- package/dist/types/mcp/requestGuard.d.ts +71 -0
- package/dist/types/mcp/requestGuard.d.ts.map +1 -0
- package/dist/types/mcp/requestLedger.d.ts +35 -1
- package/dist/types/mcp/requestLedger.d.ts.map +1 -1
- package/dist/types/mcp/seriesEvidence.d.ts +10 -6
- package/dist/types/mcp/seriesEvidence.d.ts.map +1 -1
- package/dist/types/mcp/terminate.d.ts +95 -0
- package/dist/types/mcp/terminate.d.ts.map +1 -0
- package/dist/types/mcp/throttleRetry.d.ts.map +1 -1
- package/dist/types/mcp/types.d.ts +85 -7
- package/dist/types/mcp/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/mcpClientUse.d.ts +60 -0
- package/dist/types/tools/mcpClientUse.d.ts.map +1 -0
- package/dist/types/tools/toolProvider.d.ts +16 -0
- package/dist/types/tools/toolProvider.d.ts.map +1 -1
- package/dist/types/tools/toolSessions.d.ts +41 -0
- package/dist/types/tools/toolSessions.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pool — the state behind `mcpClientPool`: who holds which client, what is
|
|
3
|
+
* charged, and what ends when.
|
|
4
|
+
*
|
|
5
|
+
* Pattern: one state machine, mutated only between awaits.
|
|
6
|
+
* Role: §§ 5–7 of the design. Every mutation of the sets and the budget runs
|
|
7
|
+
* synchronously — a check and the move it allows are never split by
|
|
8
|
+
* an await — so two callers cannot both take the last slot.
|
|
9
|
+
*
|
|
10
|
+
* - ADMISSION: every listing, call, acquire and ending is admitted against
|
|
11
|
+
* `maxOperations` before anything is sent. At each interaction the lazy
|
|
12
|
+
* sweep (revoked leases, idle ends, deferred ends) runs FIRST, so it
|
|
13
|
+
* reserves its endings before the new operation is admitted.
|
|
14
|
+
* - ONE OPEN PER KEY, from a plan resolved at that moment, under the pool's own
|
|
15
|
+
* signal and `initTimeoutMs`, never a caller's. A caller that gives up
|
|
16
|
+
* detaches alone; the operation that started the open keeps its charge until
|
|
17
|
+
* the open's work settles. Past the deadline every waiter is refused at once
|
|
18
|
+
* (`init-timeout`), and until the open's work settles the key cannot open
|
|
19
|
+
* again. A failure reaches every current waiter and is not cached.
|
|
20
|
+
* - THE HANDOFF: every operation waiting for an open holds a RESERVATION on
|
|
21
|
+
* the client until it takes its lease, so between the open settling and
|
|
22
|
+
* that lease the client is busy — nobody can evict, idle-end or end it. The
|
|
23
|
+
* client's state is checked again after every wait, and the lease taken in
|
|
24
|
+
* the same step: a lease is never handed out on a client that is ending.
|
|
25
|
+
* - MAKING ROOM: the principal's, then the pool's, least recently used IDLE
|
|
26
|
+
* client moves to the ending set — or `PoolFullError` at once.
|
|
27
|
+
* - ENDING reserves an ending slot and an operation slot FIRST; when either is
|
|
28
|
+
* full the client stays in the open set, counted, reported deferred, and is
|
|
29
|
+
* ended when slots free. Every end goes through `terminate()` — but a client
|
|
30
|
+
* whose handle this process lost: nothing can be sent for it, so its ending
|
|
31
|
+
* is its local close alone, charged the same way until it settles.
|
|
32
|
+
* - SETTLEMENT, never an abort, returns a slot (`work.ts`).
|
|
33
|
+
* - NOTHING UNCHECKED: on a pooled client every request carries a guard — its
|
|
34
|
+
* call's, or the client's open, listing or ending — and a request with none
|
|
35
|
+
* is refused before it is sent (`request-unmatched`), at the watched `send`
|
|
36
|
+
* and at the pool's own fetch alike.
|
|
37
|
+
*/
|
|
38
|
+
import type { Tool } from '../../tools/tools.js';
|
|
39
|
+
import type { McpTerminateOutcome } from '../types.js';
|
|
40
|
+
import { ClientSet, type PreviousEnd } from './clientSet.js';
|
|
41
|
+
import { SharedDefinitions, type Definition, type DefinitionList } from './definitions.js';
|
|
42
|
+
import { McpPoolRefusedError, PoolFullError, type McpPoolLimit } from './errors.js';
|
|
43
|
+
import { type PoolKey } from './identityKey.js';
|
|
44
|
+
import { type PoolSettings } from './options.js';
|
|
45
|
+
import { type ClientPlan } from './plan.js';
|
|
46
|
+
import { PooledClient, type EndReason } from './pooledClient.js';
|
|
47
|
+
import { Reporter, type UseFacts } from './record.js';
|
|
48
|
+
import { OperationBudget, Work, type Operation, type OperationKind, type WorkKind } from './work.js';
|
|
49
|
+
/** An app lease, as the pool tracks it for `maxLeaseMs`. */
|
|
50
|
+
export interface HeldLease {
|
|
51
|
+
readonly client: PooledClient;
|
|
52
|
+
readonly takenAt: number;
|
|
53
|
+
/** Revoked: its next use throws `lease-expired`. */
|
|
54
|
+
revoked: boolean;
|
|
55
|
+
/** Released: idempotent. */
|
|
56
|
+
released: boolean;
|
|
57
|
+
}
|
|
58
|
+
/** Where a list's definitions live: a client's own, or a shared entry. */
|
|
59
|
+
export interface ServedList {
|
|
60
|
+
readonly list: DefinitionList;
|
|
61
|
+
readonly shared: boolean;
|
|
62
|
+
/** The definitions context: `pc:` or `sh:`. */
|
|
63
|
+
readonly context: string;
|
|
64
|
+
}
|
|
65
|
+
/** What `stats()` returns: counts, never keys. */
|
|
66
|
+
export interface McpPoolStats {
|
|
67
|
+
/** Clients in the open set: opening, busy or idle. */
|
|
68
|
+
readonly open: number;
|
|
69
|
+
readonly busy: number;
|
|
70
|
+
readonly idle: number;
|
|
71
|
+
readonly opening: number;
|
|
72
|
+
/** Clients being ended, until each ending's work has settled. */
|
|
73
|
+
readonly ending: number;
|
|
74
|
+
/** Operations charged. */
|
|
75
|
+
readonly operations: number;
|
|
76
|
+
/** Shared definition entries kept. */
|
|
77
|
+
readonly entries: number;
|
|
78
|
+
/** Charged work past its deadline that has not settled, by what it is doing. */
|
|
79
|
+
readonly unsettled: Readonly<Record<WorkKind, number>>;
|
|
80
|
+
/** Endings whose remote outcome was not confirmed. */
|
|
81
|
+
readonly unresolvedEndings: number;
|
|
82
|
+
}
|
|
83
|
+
export declare class Pool {
|
|
84
|
+
readonly settings: PoolSettings;
|
|
85
|
+
readonly clients: ClientSet;
|
|
86
|
+
readonly budget: OperationBudget;
|
|
87
|
+
readonly shared: SharedDefinitions;
|
|
88
|
+
readonly reporter: Reporter;
|
|
89
|
+
/** The pool's own signal: what every open, listing and call runs under; aborted at `close()`. */
|
|
90
|
+
private readonly lifetime;
|
|
91
|
+
private readonly leases;
|
|
92
|
+
private readonly settleWaiters;
|
|
93
|
+
/** Waiting for some client to become idle (`terminate`, `close`). */
|
|
94
|
+
private readonly idleWaiters;
|
|
95
|
+
closed: boolean;
|
|
96
|
+
unresolvedEndings: number;
|
|
97
|
+
constructor(settings: PoolSettings);
|
|
98
|
+
now(): number;
|
|
99
|
+
get signal(): AbortSignal;
|
|
100
|
+
/**
|
|
101
|
+
* The lazy sweep, run at the start of every interaction: leases past
|
|
102
|
+
* `maxLeaseMs` revoked, idle clients ended, deferred endings retried — all of
|
|
103
|
+
* it before a new operation is admitted.
|
|
104
|
+
*/
|
|
105
|
+
interact(): void;
|
|
106
|
+
/**
|
|
107
|
+
* Admit one operation, or refuse at once: `closed`, or `PoolFullError`
|
|
108
|
+
* (`limit: 'operations'`) — before anything is sent.
|
|
109
|
+
*/
|
|
110
|
+
admit(kind: OperationKind, phase: WorkKind, callerSignal: AbortSignal | undefined): Operation;
|
|
111
|
+
refused(reason: McpPoolRefusedError['reason'], cause?: unknown): McpPoolRefusedError;
|
|
112
|
+
full(limit: McpPoolLimit): PoolFullError;
|
|
113
|
+
/**
|
|
114
|
+
* A library lease on `key`'s client for `operation`, opening one when the key
|
|
115
|
+
* has none (inside the operation's slot). `plan` is the plan resolved for a
|
|
116
|
+
* new client; a key that already has one keeps its own. The lease is
|
|
117
|
+
* released when the operation SETTLES.
|
|
118
|
+
*/
|
|
119
|
+
leaseClient(key: PoolKey, operation: Operation, facts: UseFacts, plan?: ClientPlan): Promise<PooledClient>;
|
|
120
|
+
/**
|
|
121
|
+
* Wait for `client`'s open inside `operation`, holding a reservation on it
|
|
122
|
+
* all the while — between the open settling and this lease the client is
|
|
123
|
+
* busy, so nobody can evict, idle-end or end it — then check it again and
|
|
124
|
+
* lease it in the same step, with no wait between. `undefined` when it no
|
|
125
|
+
* longer serves: the caller's next round finds the key's next client.
|
|
126
|
+
*/
|
|
127
|
+
private leaseOnceOpen;
|
|
128
|
+
/** `client` may have just become idle: a deferred ending may run, and a waiter for idleness may go on. */
|
|
129
|
+
private becameIdle;
|
|
130
|
+
private takeLease;
|
|
131
|
+
/** One lease ended: the client may now be idle, and a deferred ending may run. */
|
|
132
|
+
releaseLease(client: PooledClient): void;
|
|
133
|
+
private notifyIdle;
|
|
134
|
+
/** An app lease: a hold on a client for as long as the app keeps it, at most `maxLeaseMs`. */
|
|
135
|
+
holdLease(client: PooledClient): HeldLease;
|
|
136
|
+
/** End an app lease — at most once, whether released or revoked. */
|
|
137
|
+
endLease(lease: HeldLease): void;
|
|
138
|
+
private revokeExpiredLeases;
|
|
139
|
+
/** Every app lease is revoked: the pool is closing. */
|
|
140
|
+
revokeAllLeases(): void;
|
|
141
|
+
/**
|
|
142
|
+
* Open a client for `key`: make room, resolve its plan, admit it to the open
|
|
143
|
+
* set, and start the one open. The operation that started it tracks the open's
|
|
144
|
+
* settlement, so its charge stays until the open's work has settled.
|
|
145
|
+
*/
|
|
146
|
+
private openFor;
|
|
147
|
+
/** The one open of `client`, under the pool's own signal and `initTimeoutMs`. */
|
|
148
|
+
private startOpen;
|
|
149
|
+
private dropFailedOpen;
|
|
150
|
+
/** Wait for `client`'s open inside `operation`: the caller's signal detaches the caller only. */
|
|
151
|
+
private waitOpen;
|
|
152
|
+
/** What `mcpClient` is opened with: the connection-shaping options, the pool's signal. */
|
|
153
|
+
private clientOptions;
|
|
154
|
+
/** What only a pool asks of the client it opens (`clientPort.ts`). */
|
|
155
|
+
private seamFor;
|
|
156
|
+
/**
|
|
157
|
+
* The guard for a message on `client` that carries none of its own: a tool
|
|
158
|
+
* call always brings its call's guard, so one without it is refused; any
|
|
159
|
+
* other request runs under the client's open, listing or ending — and with
|
|
160
|
+
* none under way, it is refused too. Nothing pooled is sent unchecked.
|
|
161
|
+
*/
|
|
162
|
+
private guardOf;
|
|
163
|
+
/** The guard of a request nothing covers: it refuses, so the request is never sent. */
|
|
164
|
+
private readonly unmatched;
|
|
165
|
+
/**
|
|
166
|
+
* The pool's own fetch, outermost on every pooled transport: a request is
|
|
167
|
+
* checked against its guard (the pooled call's, else the client's phase) and
|
|
168
|
+
* counted under it; the guard's signal is linked in; and the answer is read
|
|
169
|
+
* for the two pieces of evidence the pool classifies on — a 404 the MCP server
|
|
170
|
+
* itself sent to a request that carried its session id, and a handle this
|
|
171
|
+
* process lost. The client's own standalone stream (a GET), a notification and
|
|
172
|
+
* an answer to the server's own request are the client's, not an operation's:
|
|
173
|
+
* they pass untouched. Any other request with no guard is refused unsent.
|
|
174
|
+
*/
|
|
175
|
+
private pooledFetch;
|
|
176
|
+
/**
|
|
177
|
+
* Make room for a new client of `key`: the principal's least recently used
|
|
178
|
+
* idle client, then the pool's, moves to the ending set — or `PoolFullError`
|
|
179
|
+
* at once, naming the budget. There is no queue.
|
|
180
|
+
*/
|
|
181
|
+
private makeRoom;
|
|
182
|
+
/**
|
|
183
|
+
* Move `victim` to the ending set to make room. When the slots cannot be
|
|
184
|
+
* reserved, the arrival is refused at once, and the victim stays in the open
|
|
185
|
+
* set, counted, reported deferred — ended once slots free.
|
|
186
|
+
*/
|
|
187
|
+
private evict;
|
|
188
|
+
/** An ending slot and an operation slot, both, or which one is full. */
|
|
189
|
+
private reserveEnding;
|
|
190
|
+
/**
|
|
191
|
+
* End `client` for `reason` — when it is idle and both slots can be reserved.
|
|
192
|
+
* Otherwise it stays in the open set, still counted, and is reported deferred
|
|
193
|
+
* (once); it is ended when its last lease ends or slots free.
|
|
194
|
+
*/
|
|
195
|
+
endClient(client: PooledClient, reason: EndReason): void;
|
|
196
|
+
private defer;
|
|
197
|
+
/**
|
|
198
|
+
* Move `client` into the ending set under `operation`, and end it through
|
|
199
|
+
* `terminate()` — or, for a lost handle, through its local close alone.
|
|
200
|
+
*/
|
|
201
|
+
private startEnding;
|
|
202
|
+
private noteEnded;
|
|
203
|
+
/**
|
|
204
|
+
* A client whose handle this process lost: nothing can be sent for it, so it
|
|
205
|
+
* leaves its key at once — the next use opens the key's next client — and is
|
|
206
|
+
* ended under the ending rule like any other: its ending is its LOCAL close,
|
|
207
|
+
* charged an ending slot and an operation slot until that close settles, its
|
|
208
|
+
* remote outcome recorded unresolved. Busy, or with no slots free, it waits —
|
|
209
|
+
* still counted in the open set, reported deferred.
|
|
210
|
+
*/
|
|
211
|
+
lostHandle(client: PooledClient): void;
|
|
212
|
+
/** A client whose session the server ended: no new lease; ended (through `terminate()`) when idle. */
|
|
213
|
+
expired(client: PooledClient): void;
|
|
214
|
+
private sweepIdle;
|
|
215
|
+
/** Retry every deferred ending whose client is now idle. */
|
|
216
|
+
retryDeferred(): void;
|
|
217
|
+
/** Where `client`'s definitions are served from: its shared entry, or its own list. */
|
|
218
|
+
servedListOf(client: PooledClient): ServedList;
|
|
219
|
+
/**
|
|
220
|
+
* The definitions context `client` serves under NOW: the app's `share` asked
|
|
221
|
+
* again over the client's own configuration. A changed answer moves the
|
|
222
|
+
* client to the new context and stops serving its own list, so every tool
|
|
223
|
+
* bound under the old one is refused before it is sent.
|
|
224
|
+
*
|
|
225
|
+
* @throws `binding-changed`, `share`'s error as its cause, when the answer
|
|
226
|
+
* cannot be had — never the old context
|
|
227
|
+
*/
|
|
228
|
+
refreshContext(client: PooledClient): PooledClient['definitions'];
|
|
229
|
+
/** Does `context` still name the definitions context `client` serves under? False when it cannot be had. */
|
|
230
|
+
contextHolds(client: PooledClient, context: string): boolean;
|
|
231
|
+
/**
|
|
232
|
+
* The list `client` serves under NOW, listed again on it when it cannot be
|
|
233
|
+
* served as it stands — one listing at a time per list; a second caller joins
|
|
234
|
+
* it inside its own slot. Every attempt asks the app's names again
|
|
235
|
+
* (`refreshContext`), so a listing that a moved context discarded or refused
|
|
236
|
+
* at its send is listed once more under the context of now, never written
|
|
237
|
+
* into the one it began under. A listing raced by an invalidation is
|
|
238
|
+
* discarded too. Refused (`stale-tools`) when three attempts serve nothing.
|
|
239
|
+
* What it returns was checked against the context with no wait since.
|
|
240
|
+
*/
|
|
241
|
+
ensureListed(client: PooledClient, operation: Operation): Promise<ServedList>;
|
|
242
|
+
/**
|
|
243
|
+
* What `client` can serve under the context of now — asked of the app's names
|
|
244
|
+
* here — or, when nothing can, the list it should list. Too long to share:
|
|
245
|
+
* the conversation's own client keeps that list, under the same context.
|
|
246
|
+
*/
|
|
247
|
+
private servableNow;
|
|
248
|
+
/**
|
|
249
|
+
* One listing on `client` for `served`'s context. Its requests are sent only
|
|
250
|
+
* while that context holds — asked at every boundary they cross — and its
|
|
251
|
+
* answer is written only if the context still holds when it arrives and the
|
|
252
|
+
* list's generation held: an answer the app's names moved under belongs to
|
|
253
|
+
* no context, and is dropped.
|
|
254
|
+
*/
|
|
255
|
+
private startListing;
|
|
256
|
+
/**
|
|
257
|
+
* A request failed: when the pool's fetch read the server's own 404 for the
|
|
258
|
+
* session, or this process lost the handle, the client leaves its key — the
|
|
259
|
+
* next use opens the next client under the SAME key — and the error says so.
|
|
260
|
+
*/
|
|
261
|
+
classifyFailure(client: PooledClient, work: Work, error: unknown): RequestEvidenceOutcome;
|
|
262
|
+
/** The server said a client's tool list changed: that client's list and its shared entry. */
|
|
263
|
+
private toolsChangedOn;
|
|
264
|
+
/** The app's permission signal: every list in the scope. */
|
|
265
|
+
permissionsChanged(scope: {
|
|
266
|
+
readonly tenant?: string;
|
|
267
|
+
readonly principal?: string;
|
|
268
|
+
}): void;
|
|
269
|
+
/** The server changed: every list. */
|
|
270
|
+
toolsChanged(): void;
|
|
271
|
+
/**
|
|
272
|
+
* Stop new leases on every client `scope` names, at once; wait for their
|
|
273
|
+
* in-flight work up to `waitMs`; then end each one whose slots can be
|
|
274
|
+
* reserved. The rest are reported deferred and ended when they can be.
|
|
275
|
+
*/
|
|
276
|
+
terminate(matches: (key: PoolKey) => boolean, reason: EndReason, waitMs: number): Promise<readonly McpTerminateOutcome[]>;
|
|
277
|
+
/** End each of `clients` whose slots can be reserved; the outcomes of those that started. */
|
|
278
|
+
private endNow;
|
|
279
|
+
/** Wait until every client in `clients` is idle, or `waitMs` passed. */
|
|
280
|
+
private waitIdle;
|
|
281
|
+
/**
|
|
282
|
+
* Close: refuse new work, revoke app leases, abort in-flight work through the
|
|
283
|
+
* pool's own signal, then end every client as slots can be reserved — at most
|
|
284
|
+
* `maxEnding` at a time — in rounds, each bounded by `waitMs` (and each
|
|
285
|
+
* ending's answer by its own deadline). What could not be ended yet is
|
|
286
|
+
* reported deferred and ended when slots free; work still unsettled stays
|
|
287
|
+
* charged until it settles.
|
|
288
|
+
*/
|
|
289
|
+
closeAll(waitMs: number): Promise<readonly McpTerminateOutcome[]>;
|
|
290
|
+
/** Wait until an ending slot and an operation slot are free, or `waitMs` passed. */
|
|
291
|
+
private waitSlots;
|
|
292
|
+
/** Refuse new work, revoke app leases, abort in-flight work through the pool's signal. */
|
|
293
|
+
shutDown(): void;
|
|
294
|
+
/** Resolve once every charged operation and every ending has settled. */
|
|
295
|
+
settled(): Promise<void>;
|
|
296
|
+
private quiet;
|
|
297
|
+
private notifySettled;
|
|
298
|
+
stats(): McpPoolStats;
|
|
299
|
+
/** The bound shape of every definition in `served`, for a client of `key`. */
|
|
300
|
+
definitionsOf(served: ServedList): readonly Definition[];
|
|
301
|
+
/** The tools a list's client-own entries carry, by name (per-client lists only). */
|
|
302
|
+
ownTool(served: ServedList, name: string): Tool | undefined;
|
|
303
|
+
}
|
|
304
|
+
/** What a failed request proved about its client, if anything. */
|
|
305
|
+
export type RequestEvidenceOutcome = 'expired' | 'handle-lost' | undefined;
|
|
306
|
+
/** Re-exported for the bound tool: which end reasons name a previous client. */
|
|
307
|
+
export type { PreviousEnd };
|
|
308
|
+
//# sourceMappingURL=pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../../../src/mcp/pool/pool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pooledClient — one client INCARNATION: the conversation it serves, the plan it
|
|
3
|
+
* was opened from, its leases, its own tool list, and where it is in its life.
|
|
4
|
+
*
|
|
5
|
+
* Pattern: a plain record the pool owns; no behaviour beyond its own counters.
|
|
6
|
+
* Role: § 5 of the design. A client is OPENING until its open settles, OPEN
|
|
7
|
+
* while it can serve, ENDING from the decision to end it until that
|
|
8
|
+
* ending's work has settled, then ENDED. It is BUSY while any lease is
|
|
9
|
+
* open — the library's, one per operation, or the app's — while an
|
|
10
|
+
* operation that waited for its open has not yet taken its lease (a
|
|
11
|
+
* RESERVATION), and while it opens; IDLE otherwise. A busy client is
|
|
12
|
+
* never evicted, closed for idleness or ended. "Used" is the last lease
|
|
13
|
+
* taken or released.
|
|
14
|
+
*
|
|
15
|
+
* Its `clientId` is the pool's own random id; its `generation` counts the key's
|
|
16
|
+
* incarnations (1 = the key's first client). A replacement is a new record with
|
|
17
|
+
* a new id, a new list and a count of its own: nothing of an old incarnation
|
|
18
|
+
* can match it.
|
|
19
|
+
*/
|
|
20
|
+
import type { McpClient, McpTerminateOutcome } from '../types.js';
|
|
21
|
+
import type { ClientPort } from '../clientPort.js';
|
|
22
|
+
import type { RequestGuard } from '../requestGuard.js';
|
|
23
|
+
import { DefinitionList } from './definitions.js';
|
|
24
|
+
import type { PoolKey } from './identityKey.js';
|
|
25
|
+
import type { ClientPlan } from './plan.js';
|
|
26
|
+
import type { Work } from './work.js';
|
|
27
|
+
/** Where a client is in its life. */
|
|
28
|
+
export type ClientState = 'opening' | 'open' | 'ending' | 'ended';
|
|
29
|
+
/** Why a client ended — the record's `reason`. */
|
|
30
|
+
export type EndReason = 'idle' | 'evicted' | 'terminated' | 'closed' | 'expired' | 'handle-lost' | 'abandoned-open';
|
|
31
|
+
/** One client incarnation. */
|
|
32
|
+
export declare class PooledClient {
|
|
33
|
+
readonly key: PoolKey;
|
|
34
|
+
readonly plan: ClientPlan;
|
|
35
|
+
/** 1 = the key's first client, 2 = its first replacement, … */
|
|
36
|
+
readonly generation: number;
|
|
37
|
+
readonly clientId: string;
|
|
38
|
+
state: ClientState;
|
|
39
|
+
/** The ordinary `McpClient`, once opened. */
|
|
40
|
+
client: McpClient | undefined;
|
|
41
|
+
/** The port back (`clientPort.ts`), once opened. */
|
|
42
|
+
port: ClientPort | undefined;
|
|
43
|
+
/** Open leases: one per library operation, one per app lease. */
|
|
44
|
+
leases: number;
|
|
45
|
+
/**
|
|
46
|
+
* Operations waiting for its open, each holding it until it takes its lease —
|
|
47
|
+
* so between the open settling and that lease nothing can evict or end it.
|
|
48
|
+
*/
|
|
49
|
+
reserved: number;
|
|
50
|
+
/** The last lease taken or released, on the pool's clock. */
|
|
51
|
+
usedAt: number;
|
|
52
|
+
/** No new lease: `terminate` named it, its session expired, or its handle was lost. */
|
|
53
|
+
closedToNew: boolean;
|
|
54
|
+
/** Its open ran past `initTimeoutMs`: refused to every waiter, still counted until it settles. */
|
|
55
|
+
abandoned: boolean;
|
|
56
|
+
/** Waiting for an ending slot and an operation slot, and why. */
|
|
57
|
+
deferredEnd: EndReason | undefined;
|
|
58
|
+
/** This incarnation's own tool list. */
|
|
59
|
+
readonly list: DefinitionList;
|
|
60
|
+
/**
|
|
61
|
+
* The guard of the open, listing or ending in progress on this client — what
|
|
62
|
+
* a request that is not a pooled tool call is checked against and counted by.
|
|
63
|
+
*/
|
|
64
|
+
phase: RequestGuard | undefined;
|
|
65
|
+
/** The open in flight, with the work it owns. */
|
|
66
|
+
opening: {
|
|
67
|
+
readonly ready: Promise<void>;
|
|
68
|
+
readonly work: Work;
|
|
69
|
+
readonly startedAt: number;
|
|
70
|
+
} | undefined;
|
|
71
|
+
/** How long the open took, once it settled within its deadline. */
|
|
72
|
+
initMs: number | undefined;
|
|
73
|
+
/** Why it left its key without an ordinary ending: its session expired, or its handle was lost. */
|
|
74
|
+
lost: 'expired' | 'handle-lost' | undefined;
|
|
75
|
+
/** The outcome of its ending, once one started. */
|
|
76
|
+
endingOutcome: Promise<McpTerminateOutcome> | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* The definitions context its tools are served under now. It starts as its
|
|
79
|
+
* plan's; the app's `share` is asked again at every use, and a changed answer
|
|
80
|
+
* moves it here — its connection, the plan's transport, never changes.
|
|
81
|
+
*/
|
|
82
|
+
definitions: {
|
|
83
|
+
readonly context: string;
|
|
84
|
+
readonly shared: boolean;
|
|
85
|
+
};
|
|
86
|
+
constructor(key: PoolKey, plan: ClientPlan,
|
|
87
|
+
/** 1 = the key's first client, 2 = its first replacement, … */
|
|
88
|
+
generation: number, now: number);
|
|
89
|
+
/** Busy: a lease is open, an operation holds it between its open and its lease, or it is still opening. */
|
|
90
|
+
get busy(): boolean;
|
|
91
|
+
/** Can it serve a new lease right now? */
|
|
92
|
+
get serving(): boolean;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=pooledClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pooledClient.d.ts","sourceRoot":"","sources":["../../../../src/mcp/pool/pooledClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,qCAAqC;AACrC,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAElE,kDAAkD;AAClD,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,SAAS,GACT,YAAY,GACZ,QAAQ,GACR,SAAS,GACT,aAAa,GACb,gBAAgB,CAAC;AAOrB,8BAA8B;AAC9B,qBAAa,YAAY;IA+CrB,QAAQ,CAAC,GAAG,EAAE,OAAO;IACrB,QAAQ,CAAC,IAAI,EAAE,UAAU;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,UAAU,EAAE,MAAM;IAjD7B,QAAQ,CAAC,QAAQ,SAAiB;IAClC,KAAK,EAAE,WAAW,CAAa;IAC/B,6CAA6C;IAC7C,MAAM,EAAE,SAAS,GAAG,SAAS,CAAC;IAC9B,oDAAoD;IACpD,IAAI,EAAE,UAAU,GAAG,SAAS,CAAC;IAC7B,iEAAiE;IACjE,MAAM,SAAK;IACX;;;OAGG;IACH,QAAQ,SAAK;IACb,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,WAAW,UAAS;IACpB,kGAAkG;IAClG,SAAS,UAAS;IAClB,iEAAiE;IACjE,WAAW,EAAE,SAAS,GAAG,SAAS,CAAC;IACnC,wCAAwC;IACxC,QAAQ,CAAC,IAAI,iBAAwB;IACrC;;;OAGG;IACH,KAAK,EAAE,YAAY,GAAG,SAAS,CAAC;IAChC,iDAAiD;IACjD,OAAO,EACH;QAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAClF,SAAS,CAAC;IACd,mEAAmE;IACnE,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,mGAAmG;IACnG,IAAI,EAAE,SAAS,GAAG,aAAa,GAAG,SAAS,CAAC;IAC5C,mDAAmD;IACnD,aAAa,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,SAAS,CAAC;IACxD;;;;OAIG;IACH,WAAW,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;gBAGzD,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,UAAU;IACzB,+DAA+D;IACtD,UAAU,EAAE,MAAM,EAC3B,GAAG,EAAE,MAAM;IAMb,2GAA2G;IAC3G,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,0CAA0C;IAC1C,IAAI,OAAO,IAAI,OAAO,CAErB;CACF"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* record — what the pool says about itself: one event per use in a run, and a
|
|
3
|
+
* report for what happens outside one.
|
|
4
|
+
*
|
|
5
|
+
* Pattern: facts gathered while a use runs, filed once; reports delivered to the
|
|
6
|
+
* app's `onEvent`, which can never break the pool.
|
|
7
|
+
* Role: § 8 of the design. The record holds ids and outcomes. It never holds
|
|
8
|
+
* identity values, remote session ids or handles, header values, tool
|
|
9
|
+
* arguments, results, definitions, or a server's error text. In a run,
|
|
10
|
+
* every listing and every call files one `agentfootprint.tools.mcp_client`
|
|
11
|
+
* (`tools/mcpClientUse.ts`). Outside a run — idle ends, evictions,
|
|
12
|
+
* terminations, revoked leases, deferred ends and work that settled
|
|
13
|
+
* after its deadline — the pool reports to `onEvent`.
|
|
14
|
+
*
|
|
15
|
+
* Local settlement and remote resolution are different facts, reported apart:
|
|
16
|
+
* an ending can settle here and stay unresolved there.
|
|
17
|
+
*/
|
|
18
|
+
import type { ToolsMcpClientPayload } from '../../events/payloads.js';
|
|
19
|
+
import type { McpClientUse } from '../../tools/mcpClientUse.js';
|
|
20
|
+
import type { McpTerminateOutcome } from '../types.js';
|
|
21
|
+
import type { EndReason } from './pooledClient.js';
|
|
22
|
+
import type { WorkKind } from './work.js';
|
|
23
|
+
/** What happens to a pool outside a run, as `onEvent` receives it. Ids and outcomes only. */
|
|
24
|
+
export interface McpPoolReport {
|
|
25
|
+
/**
|
|
26
|
+
* - `'ended'` — a client's ending finished, with its remote outcome;
|
|
27
|
+
* - `'deferred'` — a client to be ended stays in the open set, still counted,
|
|
28
|
+
* until an ending slot and an operation slot free (or its lease ends);
|
|
29
|
+
* - `'lease-revoked'` — an app lease ran past `maxLeaseMs`;
|
|
30
|
+
* - `'settled-late'` — work whose caller was already answered has settled,
|
|
31
|
+
* and its charge is released.
|
|
32
|
+
*/
|
|
33
|
+
readonly kind: 'ended' | 'deferred' | 'lease-revoked' | 'settled-late';
|
|
34
|
+
/** The pool's name. */
|
|
35
|
+
readonly server: string;
|
|
36
|
+
/** The pool's own random id for the client, when one is concerned. */
|
|
37
|
+
readonly clientId?: string;
|
|
38
|
+
/** The tool-session digest of the conversation's key, when one is concerned. */
|
|
39
|
+
readonly keyHash?: string;
|
|
40
|
+
/** Why the client ended, or is to end. */
|
|
41
|
+
readonly reason?: EndReason;
|
|
42
|
+
/** `'ended'`: what the remote side answered (`McpTerminateOutcome.remote`). */
|
|
43
|
+
readonly remote?: McpTerminateOutcome['remote'];
|
|
44
|
+
/** `'ended'`: whether the remote ending was confirmed. */
|
|
45
|
+
readonly resolved?: boolean;
|
|
46
|
+
/** `'ended'`: the HTTP status the remote side answered with, when one was read. */
|
|
47
|
+
readonly status?: number;
|
|
48
|
+
/** `'ended'`: a failure's class name, never its message. */
|
|
49
|
+
readonly errorClass?: string;
|
|
50
|
+
/** `'settled-late'`: what the work was doing. */
|
|
51
|
+
readonly work?: WorkKind;
|
|
52
|
+
/** `'ended'`: how long the caller waited; `'settled-late'`: how long it ran past its answer. */
|
|
53
|
+
readonly durationMs: number;
|
|
54
|
+
}
|
|
55
|
+
/** Delivers reports to the app; a throwing handler is swallowed and changes nothing. */
|
|
56
|
+
export declare class Reporter {
|
|
57
|
+
private readonly server;
|
|
58
|
+
private readonly onEvent;
|
|
59
|
+
constructor(server: string, onEvent: ((report: McpPoolReport) => void) | undefined);
|
|
60
|
+
report(report: Omit<McpPoolReport, 'server'>): void;
|
|
61
|
+
}
|
|
62
|
+
/** The facts one pool use gathers while it runs, filed once when it settles. */
|
|
63
|
+
export declare class UseFacts {
|
|
64
|
+
private readonly server;
|
|
65
|
+
private readonly at;
|
|
66
|
+
keyHash: string | undefined;
|
|
67
|
+
clientId: string | undefined;
|
|
68
|
+
generation: number | undefined;
|
|
69
|
+
client: ToolsMcpClientPayload['client'];
|
|
70
|
+
previous: ToolsMcpClientPayload['previous'];
|
|
71
|
+
evidence: ToolsMcpClientPayload['evidence'];
|
|
72
|
+
refusal: ToolsMcpClientPayload['refusal'];
|
|
73
|
+
initMs: number | undefined;
|
|
74
|
+
definitions: ToolsMcpClientPayload['definitions'];
|
|
75
|
+
definitionsAgeMs: number | undefined;
|
|
76
|
+
revalidated: ToolsMcpClientPayload['revalidated'];
|
|
77
|
+
constructor(server: string, at: ToolsMcpClientPayload['at']);
|
|
78
|
+
/** The use, as `tools/mcpClientUse.ts` files it. */
|
|
79
|
+
toUse(): McpClientUse;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=record.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../../../src/mcp/pool/record.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1C,6FAA6F;AAC7F,MAAM,WAAW,aAAa;IAC5B;;;;;;;OAOG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,GAAG,eAAe,GAAG,cAAc,CAAC;IACvE,uBAAuB;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,gFAAgF;IAChF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,0CAA0C;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;IAC5B,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,CAAC,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAChD,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,mFAAmF;IACnF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,4DAA4D;IAC5D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,iDAAiD;IACjD,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;IACzB,gGAAgG;IAChG,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,wFAAwF;AACxF,qBAAa,QAAQ;IAEjB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC,GAAG,SAAS;IAGzE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,GAAG,IAAI;CAQpD;AAED,gFAAgF;AAChF,qBAAa,QAAQ;IAaP,OAAO,CAAC,QAAQ,CAAC,MAAM;IAAU,OAAO,CAAC,QAAQ,CAAC,EAAE;IAZhE,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,MAAM,EAAE,qBAAqB,CAAC,QAAQ,CAAC,CAAa;IACpD,QAAQ,EAAE,qBAAqB,CAAC,UAAU,CAAC,CAAC;IAC5C,QAAQ,EAAE,qBAAqB,CAAC,UAAU,CAAC,CAAC;IAC5C,OAAO,EAAE,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAC;IAClD,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,WAAW,EAAE,qBAAqB,CAAC,aAAa,CAAC,CAAC;gBAErB,MAAM,EAAE,MAAM,EAAmB,EAAE,EAAE,qBAAqB,CAAC,IAAI,CAAC;IAE7F,oDAAoD;IACpD,KAAK,IAAI,YAAY;CAiBtB"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sessionEnded — the MCP server ended a conversation's session: the library's
|
|
3
|
+
* one `SessionExpiredError`, said the pool's way.
|
|
4
|
+
*
|
|
5
|
+
* Pattern: a subclass that keeps the class and changes only what the pool must.
|
|
6
|
+
* Role: § 5.5 of the design. There is ONE expired-session class
|
|
7
|
+
* (`provider-contract/sessionExpired.ts` · `SessionExpiredError`), so a
|
|
8
|
+
* caller catches a code session's expiry and an MCP session's with the
|
|
9
|
+
* same `instanceof`, under the same rule: only documented evidence
|
|
10
|
+
* raises it. Here the evidence is `'server-404'`: an MCP server answered
|
|
11
|
+
* HTTP 404 to a request that carried the session id it issued.
|
|
12
|
+
*
|
|
13
|
+
* What differs is what the pool may say. The model reads this error as the
|
|
14
|
+
* call's result, so its message is one fixed sentence; it names no remote
|
|
15
|
+
* session id (`sessionId` is the pool's own client id, which the record carries
|
|
16
|
+
* too) and never the server's text. The original error is `cause`, for the app.
|
|
17
|
+
*/
|
|
18
|
+
import { SessionExpiredError } from '../../provider-contract/sessionExpired.js';
|
|
19
|
+
/** The one sentence a server-ended session reaches the model as. */
|
|
20
|
+
export declare const SESSION_ENDED_SENTENCE = "The server had already ended the conversation's session when the call this result answers reached it.";
|
|
21
|
+
/** @internal An MCP server ended the session; raised by the pool. Catch `SessionExpiredError`. */
|
|
22
|
+
export declare class ServerEndedSessionError extends SessionExpiredError {
|
|
23
|
+
constructor(server: string, clientId: string, cause: unknown);
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=sessionEnded.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionEnded.d.ts","sourceRoot":"","sources":["../../../../src/mcp/pool/sessionEnded.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAC;AAEhF,oEAAoE;AACpE,eAAO,MAAM,sBAAsB,0GACsE,CAAC;AAE1G,kGAAkG;AAClG,qBAAa,uBAAwB,SAAQ,mBAAmB;gBAClD,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAO7D"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* work — an admitted operation's charge, and the work under it until that work
|
|
3
|
+
* has settled.
|
|
4
|
+
*
|
|
5
|
+
* Pattern: one object per unit of work that is at once the request guard
|
|
6
|
+
* (`mcp/requestGuard.ts`) and the count of what is still running.
|
|
7
|
+
* Role: The pool's third budget (`docs/design/2026-10-mcp-client-pool.md`
|
|
8
|
+
* § 5.3). The accounting unit is the admitted LOGICAL operation: a
|
|
9
|
+
* `tools/call`, a listing (one `list(ctx)` for one conversation), an
|
|
10
|
+
* `acquire` and an ending each take one slot at admission. Setup an
|
|
11
|
+
* operation performs for itself — the open of its key's client, the
|
|
12
|
+
* revalidating `tools/list` of a replacement — runs inside that slot.
|
|
13
|
+
*
|
|
14
|
+
* AN ABORT IS NOT SETTLEMENT. A slot is released only when the operation's
|
|
15
|
+
* logical request has its answer AND every piece of work under it has settled:
|
|
16
|
+
* the `send()` it made, a credential vend, an attempt's `fetch`, an AWS `send`,
|
|
17
|
+
* the open it owns. A caller's timeout answers the caller; it frees nothing.
|
|
18
|
+
* Work that never settles keeps its charge — `stats().unsettled` reports it,
|
|
19
|
+
* and the budget refuses new work rather than admit it against room that does
|
|
20
|
+
* not exist. There is no release that returns capacity sooner.
|
|
21
|
+
*/
|
|
22
|
+
import type { RequestGuard } from '../requestGuard.js';
|
|
23
|
+
/** What a unit of work is doing now — what `stats().unsettled` counts it under. */
|
|
24
|
+
export type WorkKind = 'open' | 'listing' | 'call' | 'ending';
|
|
25
|
+
/** What an operation is, as the budget admits it. */
|
|
26
|
+
export type OperationKind = 'listing' | 'call' | 'acquire' | 'ending';
|
|
27
|
+
/** What a request's answer proved, as the pool's fetch read it (`pool.ts`). */
|
|
28
|
+
export type WorkEvidence = 'server-404' | 'handle-lost';
|
|
29
|
+
/**
|
|
30
|
+
* One unit of pooled work: its requests are checked against it at every
|
|
31
|
+
* boundary (`check`), and every promise started for it is counted until it
|
|
32
|
+
* settles (`track`). It is SETTLED once its logical part has finished and the
|
|
33
|
+
* count is zero.
|
|
34
|
+
*/
|
|
35
|
+
export declare class Work implements RequestGuard {
|
|
36
|
+
/** What it is doing now. */
|
|
37
|
+
phase: WorkKind;
|
|
38
|
+
private readonly link;
|
|
39
|
+
private pending;
|
|
40
|
+
private finished;
|
|
41
|
+
private done;
|
|
42
|
+
/** Still running underneath when the caller was answered: it lingered. */
|
|
43
|
+
private lingered;
|
|
44
|
+
private readonly listeners;
|
|
45
|
+
/** What `check` asks besides the abort — a call's binding. */
|
|
46
|
+
private extra;
|
|
47
|
+
/** What the latest answered request proved, if anything. */
|
|
48
|
+
evidence: WorkEvidence | undefined;
|
|
49
|
+
constructor(
|
|
50
|
+
/** What it is doing now. */
|
|
51
|
+
phase: WorkKind, sources: readonly (AbortSignal | undefined)[]);
|
|
52
|
+
/** What aborts its own work: its sources, its deadline, its caller detaching. */
|
|
53
|
+
get signal(): AbortSignal;
|
|
54
|
+
/** True once its logical part finished and everything under it settled. */
|
|
55
|
+
get settled(): boolean;
|
|
56
|
+
/** Its caller was answered while work under it still ran. */
|
|
57
|
+
get unsettledPastAnswer(): boolean;
|
|
58
|
+
/** Abort its work with `reason` (a deadline, a detached caller). Idempotent. */
|
|
59
|
+
abort(reason: unknown): void;
|
|
60
|
+
/** Ask `gate` too, each time a request is checked. */
|
|
61
|
+
guardWith(gate: () => void): void;
|
|
62
|
+
/**
|
|
63
|
+
* The send gate: refused once its caller was answered (nothing more is sent
|
|
64
|
+
* for an answered operation), once aborted, or when the extra gate refuses.
|
|
65
|
+
*/
|
|
66
|
+
check(): void;
|
|
67
|
+
/** Count `work` until it settles. Never throws; never surfaces its rejection. */
|
|
68
|
+
track(work: PromiseLike<unknown>): void;
|
|
69
|
+
/** Record what a request's answer proved. */
|
|
70
|
+
note(evidence: WorkEvidence): void;
|
|
71
|
+
/**
|
|
72
|
+
* Its logical part is over: the caller has its answer. It settles now, or —
|
|
73
|
+
* when work under it still runs — when that work does.
|
|
74
|
+
*/
|
|
75
|
+
finish(): void;
|
|
76
|
+
/** Did it linger — answered while work under it ran? Read once it settled. */
|
|
77
|
+
get settledLate(): boolean;
|
|
78
|
+
/** Call `listener` once it has settled (at once when it already has). */
|
|
79
|
+
onSettled(listener: () => void): void;
|
|
80
|
+
/** A promise that resolves once it has settled. */
|
|
81
|
+
whenSettled(): Promise<void>;
|
|
82
|
+
private settleIfDone;
|
|
83
|
+
}
|
|
84
|
+
/** An admitted operation: a unit of work that holds one slot of the budget. */
|
|
85
|
+
export declare class Operation extends Work {
|
|
86
|
+
readonly kind: OperationKind;
|
|
87
|
+
/** When it was admitted, on the pool's clock. */
|
|
88
|
+
readonly admittedAt: number;
|
|
89
|
+
constructor(kind: OperationKind, phase: WorkKind, sources: readonly (AbortSignal | undefined)[],
|
|
90
|
+
/** When it was admitted, on the pool's clock. */
|
|
91
|
+
admittedAt: number);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The pool-wide operation budget: at most `max` operations charged, each from
|
|
95
|
+
* its admission until it has SETTLED (see the module note). Admission is the
|
|
96
|
+
* only way in; settlement the only way out.
|
|
97
|
+
*/
|
|
98
|
+
export declare class OperationBudget {
|
|
99
|
+
readonly max: number;
|
|
100
|
+
private readonly charged;
|
|
101
|
+
private readonly onRelease;
|
|
102
|
+
constructor(max: number);
|
|
103
|
+
/** Operations charged now. */
|
|
104
|
+
get count(): number;
|
|
105
|
+
/** Is there a free slot? */
|
|
106
|
+
get hasRoom(): boolean;
|
|
107
|
+
/**
|
|
108
|
+
* Admit one operation, or `undefined` when the budget is full. The slot is
|
|
109
|
+
* charged from here until the operation settles.
|
|
110
|
+
*/
|
|
111
|
+
admit(kind: OperationKind, phase: WorkKind, sources: readonly (AbortSignal | undefined)[], now: number): Operation | undefined;
|
|
112
|
+
/** Call `listener` each time an operation settles and frees its slot. Returns the unsubscribe. */
|
|
113
|
+
whenReleased(listener: (operation: Operation) => void): () => void;
|
|
114
|
+
/** Charged work whose caller was already answered and which has not settled, by what it is doing. */
|
|
115
|
+
unsettled(): Record<WorkKind, number>;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=work.d.ts.map
|