@adcp/sdk 15.4.0 → 15.6.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/README.md +15 -0
- package/dist/lib/advanced.d.mts +2 -2
- package/dist/lib/advanced.d.ts +2 -2
- package/dist/lib/advanced.js +8 -2
- package/dist/lib/advanced.mjs +8 -2
- package/dist/lib/auth/oauth/index.d.mts +1 -0
- package/dist/lib/auth/oauth/index.d.ts +1 -0
- package/dist/lib/auth/oauth/index.js +5 -0
- package/dist/lib/auth/oauth/index.mjs +3 -0
- package/dist/lib/auth/oauth/pending-web-flow.d.mts +16 -0
- package/dist/lib/auth/oauth/pending-web-flow.d.ts +16 -0
- package/dist/lib/auth/oauth/pending-web-flow.js +66 -0
- package/dist/lib/auth/oauth/pending-web-flow.mjs +41 -0
- package/dist/lib/auth/oauth/web-flow.js +3 -3
- package/dist/lib/auth/oauth/web-flow.mjs +3 -3
- package/dist/lib/core/AgentClient.d.mts +4 -0
- package/dist/lib/core/AgentClient.d.ts +4 -0
- package/dist/lib/core/AgentClient.js +8 -0
- package/dist/lib/core/AgentClient.mjs +8 -0
- package/dist/lib/core/SingleAgentClient.d.mts +154 -0
- package/dist/lib/core/SingleAgentClient.d.ts +154 -0
- package/dist/lib/core/SingleAgentClient.js +661 -23
- package/dist/lib/core/SingleAgentClient.mjs +666 -23
- package/dist/lib/core/agent-discovery-cache.d.mts +103 -0
- package/dist/lib/core/agent-discovery-cache.d.ts +103 -0
- package/dist/lib/core/agent-discovery-cache.js +121 -0
- package/dist/lib/core/agent-discovery-cache.mjs +92 -0
- package/dist/lib/index.d.mts +5 -3
- package/dist/lib/index.d.ts +5 -3
- package/dist/lib/index.js +7 -0
- package/dist/lib/index.mjs +6 -0
- package/dist/lib/protocols/index.d.mts +2 -2
- package/dist/lib/protocols/index.d.ts +2 -2
- package/dist/lib/protocols/index.js +1 -1
- package/dist/lib/protocols/index.mjs +1 -1
- package/dist/lib/protocols/mcp-call-context.d.mts +109 -0
- package/dist/lib/protocols/mcp-call-context.d.ts +109 -0
- package/dist/lib/protocols/mcp-call-context.js +221 -0
- package/dist/lib/protocols/mcp-call-context.mjs +186 -0
- package/dist/lib/protocols/mcp-modern.d.mts +9 -1
- package/dist/lib/protocols/mcp-modern.d.ts +9 -1
- package/dist/lib/protocols/mcp-modern.js +180 -104
- package/dist/lib/protocols/mcp-modern.mjs +193 -104
- package/dist/lib/protocols/mcp-scope.d.mts +15 -0
- package/dist/lib/protocols/mcp-scope.d.ts +15 -0
- package/dist/lib/protocols/mcp.d.mts +4 -2
- package/dist/lib/protocols/mcp.d.ts +4 -2
- package/dist/lib/protocols/mcp.js +178 -154
- package/dist/lib/protocols/mcp.mjs +189 -153
- package/dist/lib/protocols/transportDiagnostics.d.mts +33 -1
- package/dist/lib/protocols/transportDiagnostics.d.ts +33 -1
- package/dist/lib/protocols/transportDiagnostics.js +128 -12
- package/dist/lib/protocols/transportDiagnostics.mjs +128 -12
- package/dist/lib/registry/types.generated.d.mts +63 -1
- package/dist/lib/registry/types.generated.d.ts +63 -1
- package/dist/lib/reporting/azure/index.d.mts +26 -0
- package/dist/lib/reporting/azure/index.d.ts +26 -0
- package/dist/lib/reporting/azure/index.js +247 -0
- package/dist/lib/reporting/azure/index.mjs +230 -0
- package/dist/lib/reporting/bigquery/index.d.mts +127 -0
- package/dist/lib/reporting/bigquery/index.d.ts +127 -0
- package/dist/lib/reporting/bigquery/index.js +379 -0
- package/dist/lib/reporting/bigquery/index.mjs +341 -0
- package/dist/lib/reporting/gcs/index.d.mts +2 -0
- package/dist/lib/reporting/gcs/index.d.ts +2 -0
- package/dist/lib/reporting/gcs/index.js +3 -0
- package/dist/lib/reporting/gcs/index.mjs +2 -0
- package/dist/lib/reporting/gcs/row-provider.d.mts +32 -0
- package/dist/lib/reporting/gcs/row-provider.d.ts +32 -0
- package/dist/lib/reporting/gcs/row-provider.js +205 -0
- package/dist/lib/reporting/gcs/row-provider.mjs +188 -0
- package/dist/lib/reporting/ledger/change-feed.d.mts +41 -0
- package/dist/lib/reporting/ledger/change-feed.d.ts +41 -0
- package/dist/lib/reporting/ledger/change-feed.js +101 -0
- package/dist/lib/reporting/ledger/change-feed.mjs +74 -0
- package/dist/lib/reporting/ledger/handler.js +22 -8
- package/dist/lib/reporting/ledger/handler.mjs +22 -8
- package/dist/lib/reporting/ledger/index.d.mts +4 -0
- package/dist/lib/reporting/ledger/index.d.ts +4 -0
- package/dist/lib/reporting/ledger/index.js +9 -1
- package/dist/lib/reporting/ledger/index.mjs +4 -0
- package/dist/lib/reporting/ledger/managed-postgres.d.mts +2 -0
- package/dist/lib/reporting/ledger/managed-postgres.d.ts +2 -0
- package/dist/lib/reporting/ledger/managed-postgres.js +21 -1
- package/dist/lib/reporting/ledger/managed-postgres.mjs +21 -1
- package/dist/lib/reporting/ledger/managed.d.mts +9 -0
- package/dist/lib/reporting/ledger/managed.d.ts +9 -0
- package/dist/lib/reporting/ledger/managed.js +18 -0
- package/dist/lib/reporting/ledger/managed.mjs +18 -0
- package/dist/lib/reporting/ledger/postgres.d.mts +185 -0
- package/dist/lib/reporting/ledger/postgres.d.ts +185 -0
- package/dist/lib/reporting/ledger/postgres.js +872 -26
- package/dist/lib/reporting/ledger/postgres.mjs +880 -26
- package/dist/lib/reporting/ledger/producer.js +10 -1
- package/dist/lib/reporting/ledger/producer.mjs +10 -1
- package/dist/lib/reporting/ledger/row-storage-errors.d.mts +7 -0
- package/dist/lib/reporting/ledger/row-storage-errors.d.ts +7 -0
- package/dist/lib/reporting/ledger/row-storage-errors.js +41 -0
- package/dist/lib/reporting/ledger/row-storage-errors.mjs +16 -0
- package/dist/lib/reporting/ledger/row-storage-migration.d.mts +41 -0
- package/dist/lib/reporting/ledger/row-storage-migration.d.ts +41 -0
- package/dist/lib/reporting/ledger/row-storage-migration.js +234 -0
- package/dist/lib/reporting/ledger/row-storage-migration.mjs +208 -0
- package/dist/lib/reporting/ledger/row-storage-object.d.mts +112 -0
- package/dist/lib/reporting/ledger/row-storage-object.d.ts +112 -0
- package/dist/lib/reporting/ledger/row-storage-object.js +304 -0
- package/dist/lib/reporting/ledger/row-storage-object.mjs +262 -0
- package/dist/lib/reporting/ledger/row-storage-provider-io.d.mts +44 -0
- package/dist/lib/reporting/ledger/row-storage-provider-io.d.ts +44 -0
- package/dist/lib/reporting/ledger/row-storage-provider-io.js +142 -0
- package/dist/lib/reporting/ledger/row-storage-provider-io.mjs +111 -0
- package/dist/lib/reporting/ledger/row-storage.d.mts +224 -0
- package/dist/lib/reporting/ledger/row-storage.d.ts +224 -0
- package/dist/lib/reporting/ledger/row-storage.js +692 -0
- package/dist/lib/reporting/ledger/row-storage.mjs +680 -0
- package/dist/lib/reporting/ledger/types.d.mts +8 -0
- package/dist/lib/reporting/ledger/types.d.ts +8 -0
- package/dist/lib/reporting/s3/index.d.mts +29 -0
- package/dist/lib/reporting/s3/index.d.ts +29 -0
- package/dist/lib/reporting/s3/index.js +324 -0
- package/dist/lib/reporting/s3/index.mjs +317 -0
- package/dist/lib/reporting/service/index.d.mts +43 -1
- package/dist/lib/reporting/service/index.d.ts +43 -1
- package/dist/lib/reporting/service/index.js +69 -1
- package/dist/lib/reporting/service/index.mjs +71 -1
- package/dist/lib/schemas/browser.d.mts +14 -0
- package/dist/lib/schemas/browser.d.ts +14 -0
- package/dist/lib/schemas/browser.js +48 -0
- package/dist/lib/schemas/browser.mjs +20 -0
- package/dist/lib/schemas/index.d.mts +2 -120
- package/dist/lib/schemas/index.d.ts +2 -120
- package/dist/lib/schemas/index.js +3 -11
- package/dist/lib/schemas/index.mjs +1 -9
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/testing/index.d.mts +1 -0
- package/dist/lib/testing/index.d.ts +1 -0
- package/dist/lib/testing/index.js +3 -0
- package/dist/lib/testing/index.mjs +2 -0
- package/dist/lib/testing/pending-web-flow-store.d.mts +20 -0
- package/dist/lib/testing/pending-web-flow-store.d.ts +20 -0
- package/dist/lib/testing/pending-web-flow-store.js +132 -0
- package/dist/lib/testing/pending-web-flow-store.mjs +98 -0
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/validation/get-products-request.d.mts +122 -0
- package/dist/lib/validation/get-products-request.d.ts +122 -0
- package/dist/lib/validation/get-products-request.js +39 -0
- package/dist/lib/validation/get-products-request.mjs +14 -0
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.mjs +3 -3
- package/docs/README.md +1 -1
- package/docs/TYPE-SUMMARY.md +35 -2
- package/docs/ZOD-SCHEMAS.md +13 -1
- package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +142 -0
- package/docs/guides/EXISTING-PLATFORM.md +43 -12
- package/docs/guides/OAUTH-ISSUER-BINDING.md +6 -0
- package/docs/guides/REPORTING-LEDGER.md +374 -0
- package/docs/guides/REPORTING-OPERATIONS.md +76 -1
- package/docs/guides/WEB-OAUTH.md +48 -1
- package/docs/llms.txt +4 -2
- package/docs/migration-14.x-rc-worksheet.md +6 -4
- package/package.json +64 -1
|
@@ -51,6 +51,7 @@ var import_task_deadline = require('./task-deadline.js');
|
|
|
51
51
|
var import_auth = require('../auth/index.js');
|
|
52
52
|
var import_abort = require('../protocols/abort.js');
|
|
53
53
|
var import_signedRequestRejection = require('../protocols/signedRequestRejection.js');
|
|
54
|
+
var import_mcp_call_context = require('../protocols/mcp-call-context.js');
|
|
54
55
|
var import_protocols = require('../protocols/index.js');
|
|
55
56
|
var import_errors = require('../errors/index.js');
|
|
56
57
|
var import_net = require('../net/index.js');
|
|
@@ -68,6 +69,7 @@ var import_ProtocolResponseParser = require('./ProtocolResponseParser.js');
|
|
|
68
69
|
var import_a2a_discovery = require('../utils/a2a-discovery.js');
|
|
69
70
|
var crypto = __toESM(require("crypto"));
|
|
70
71
|
var import_abort2 = require('../protocols/abort.js');
|
|
72
|
+
var import_agent_discovery_cache = require('./agent-discovery-cache.js');
|
|
71
73
|
var import_capabilities = require('../utils/capabilities.js');
|
|
72
74
|
var import_errors3 = require('../errors/index.js');
|
|
73
75
|
var import_buyer_account_registry = require('./buyer-account-registry.js');
|
|
@@ -656,6 +658,30 @@ const DURABLE_SETTLEMENT_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
|
656
658
|
"aborted"
|
|
657
659
|
]);
|
|
658
660
|
const MCP_WEBHOOK_REQUIRED_FIELDS = ["idempotency_key", "task_id", "task_type", "status", "timestamp"];
|
|
661
|
+
const sharedInvalidations = /* @__PURE__ */ new WeakMap();
|
|
662
|
+
const sharedInvalidationFloors = /* @__PURE__ */ new WeakMap();
|
|
663
|
+
let sharedInvalidationCounter = 0;
|
|
664
|
+
const MAX_SHARED_INVALIDATION_RECORDS = 1024;
|
|
665
|
+
const sharedMutationChains = /* @__PURE__ */ new WeakMap();
|
|
666
|
+
const MAX_PENDING_SHARED_MUTATIONS_PER_KEY = 16;
|
|
667
|
+
const MAX_SHARED_MUTATION_KEYS = 1024;
|
|
668
|
+
const sharedDiscoveryFlights = /* @__PURE__ */ new WeakMap();
|
|
669
|
+
const MAX_SHARED_DISCOVERY_WAITS = 3;
|
|
670
|
+
const SHARED_DISCOVERY_CACHE_TIMEOUT_MS = 2e3;
|
|
671
|
+
const SHARED_DISCOVERY_CLOCK_SKEW_MS = 5e3;
|
|
672
|
+
const CAPABILITY_STALE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
673
|
+
"VERSION_UNSUPPORTED",
|
|
674
|
+
"UNSUPPORTED_FEATURE",
|
|
675
|
+
"FEATURE_UNSUPPORTED",
|
|
676
|
+
"TOOL_NOT_FOUND",
|
|
677
|
+
"METHOD_NOT_FOUND",
|
|
678
|
+
"UNKNOWN_TOOL"
|
|
679
|
+
]);
|
|
680
|
+
function isToolSchemaRecord(value) {
|
|
681
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.values(value).every(
|
|
682
|
+
(properties) => typeof properties === "object" && properties !== null && !Array.isArray(properties)
|
|
683
|
+
);
|
|
684
|
+
}
|
|
659
685
|
function isCapabilityEvidence(value) {
|
|
660
686
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
661
687
|
const candidate = value;
|
|
@@ -753,6 +779,7 @@ class SingleAgentClient {
|
|
|
753
779
|
...configuredWebhookVerification !== void 0 && { webhookVerification: configuredWebhookVerification }
|
|
754
780
|
};
|
|
755
781
|
config = this.config;
|
|
782
|
+
(0, import_agent_discovery_cache.validateAgentDiscoveryCacheConfig)(config.discoveryCache);
|
|
756
783
|
this.resolvedAdcpVersion = (0, import_adcp_version_config.resolveAdcpVersion)(config.adcpVersion);
|
|
757
784
|
this.webhookRegistrationStore = config.webhookRegistrationStore ?? new import_webhook_registration.InMemoryWebhookRegistrationStore();
|
|
758
785
|
this.webhookReplayStore = config.webhookVerification?.replayStore ?? new import_server.InMemoryReplayStore();
|
|
@@ -1031,6 +1058,20 @@ class SingleAgentClient {
|
|
|
1031
1058
|
// Freshness bound for application-owned evidence only
|
|
1032
1059
|
capabilityEvidenceScopeKey = (0, import_node_crypto.randomUUID)();
|
|
1033
1060
|
capabilityEvidenceAuthMaterial;
|
|
1061
|
+
capabilitiesFromSharedCache = false;
|
|
1062
|
+
// Installed from config.discoveryCache rather than discovered live
|
|
1063
|
+
discoveryEpoch = 0;
|
|
1064
|
+
// bumped by invalidation so an older in-flight discovery cannot re-install what was dropped
|
|
1065
|
+
discoveredEndpointKey;
|
|
1066
|
+
// discoveryCache key the local endpoint was obtained under
|
|
1067
|
+
discoveredEndpointEpoch;
|
|
1068
|
+
// shared invalidation epoch of that key when the endpoint was obtained
|
|
1069
|
+
discoveredEndpointExpiresAt;
|
|
1070
|
+
// freshness bound for that endpoint (shared-cache mode only)
|
|
1071
|
+
sharedEvidenceEpoch;
|
|
1072
|
+
// shared invalidation epoch of that key when the evidence was obtained
|
|
1073
|
+
sharedEvidenceKey;
|
|
1074
|
+
// discoveryCache key the local capability cache was obtained under
|
|
1034
1075
|
_v2WarningFired = false;
|
|
1035
1076
|
// Gate: emit the v2-sunset warning once per client instance
|
|
1036
1077
|
_syntheticV3WarningFired = false;
|
|
@@ -1702,19 +1743,34 @@ class SingleAgentClient {
|
|
|
1702
1743
|
if (!needsDiscovery) {
|
|
1703
1744
|
return this.normalizedAgent;
|
|
1704
1745
|
}
|
|
1746
|
+
const effectiveEndpointKey = this.config.discoveryCache && !usesScopedFetch && this.discoveredEndpoint ? this.sharedDiscoveryKey(options) : void 0;
|
|
1747
|
+
if (this.config.discoveryCache && !usesScopedFetch && this.discoveredEndpoint && (this.discoveredEndpointKey !== effectiveEndpointKey || effectiveEndpointKey !== void 0 && this.discoveredEndpointEpoch !== this.sharedInvalidationEpoch(effectiveEndpointKey) || (this.discoveredEndpointExpiresAt ?? 0) <= Date.now())) {
|
|
1748
|
+
this.discoveredEndpoint = void 0;
|
|
1749
|
+
this.discoveredAgent = void 0;
|
|
1750
|
+
this.discoveredMcpEra = void 0;
|
|
1751
|
+
}
|
|
1705
1752
|
if (!usesScopedFetch && this.discoveredAgent) {
|
|
1706
1753
|
return this.discoveredAgent;
|
|
1707
1754
|
}
|
|
1755
|
+
if (!usesScopedFetch && !this.discoveredEndpoint && this.config.discoveryCache) {
|
|
1756
|
+
await this.adoptSharedEndpoint(options);
|
|
1757
|
+
if (this.discoveredEndpoint && (this.discoveredEndpointEpoch !== this.sharedInvalidationEpoch(this.sharedDiscoveryKey(options)) || (this.discoveredEndpointExpiresAt ?? 0) <= Date.now())) {
|
|
1758
|
+
this.discoveredEndpoint = void 0;
|
|
1759
|
+
this.discoveredAgent = void 0;
|
|
1760
|
+
this.discoveredMcpEra = void 0;
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1708
1763
|
if (!usesScopedFetch && this.discoveredEndpoint) {
|
|
1709
|
-
|
|
1764
|
+
const adoptedAgent = {
|
|
1710
1765
|
...this.normalizedAgent,
|
|
1711
1766
|
agent_uri: this.discoveredEndpoint
|
|
1712
1767
|
};
|
|
1768
|
+
this.discoveredAgent = adoptedAgent;
|
|
1713
1769
|
if (this.normalizedAgent.oauth_tokens && !this.normalizedAgent.oauth_client_credentials) {
|
|
1714
1770
|
const { shareNonInteractiveOAuthProvider } = await import("../auth/oauth/provider-cache.js");
|
|
1715
|
-
shareNonInteractiveOAuthProvider(this.normalizedAgent,
|
|
1771
|
+
shareNonInteractiveOAuthProvider(this.normalizedAgent, adoptedAgent);
|
|
1716
1772
|
}
|
|
1717
|
-
return
|
|
1773
|
+
return adoptedAgent;
|
|
1718
1774
|
}
|
|
1719
1775
|
if (this.normalizedAgent.oauth_client_credentials) {
|
|
1720
1776
|
const { ensureClientCredentialsTokens, getAgentStorage } = await import("../auth/oauth/index.js");
|
|
@@ -1725,26 +1781,59 @@ class SingleAgentClient {
|
|
|
1725
1781
|
signal: options?.signal
|
|
1726
1782
|
});
|
|
1727
1783
|
}
|
|
1784
|
+
const endpointEpoch = this.discoveryEpochSnapshot(options);
|
|
1728
1785
|
const discoveredEndpoint = await this.discoverMCPEndpoint(this.normalizedAgent.agent_uri, options);
|
|
1729
1786
|
if (usesScopedFetch) {
|
|
1730
|
-
const
|
|
1787
|
+
const discoveredAgent2 = { ...this.normalizedAgent, agent_uri: discoveredEndpoint };
|
|
1731
1788
|
if (this.normalizedAgent.oauth_tokens && !this.normalizedAgent.oauth_client_credentials) {
|
|
1732
1789
|
const { shareNonInteractiveOAuthProvider } = await import("../auth/oauth/provider-cache.js");
|
|
1733
|
-
shareNonInteractiveOAuthProvider(this.normalizedAgent,
|
|
1790
|
+
shareNonInteractiveOAuthProvider(this.normalizedAgent, discoveredAgent2);
|
|
1734
1791
|
}
|
|
1735
|
-
return
|
|
1792
|
+
return discoveredAgent2;
|
|
1793
|
+
}
|
|
1794
|
+
if (endpointEpoch && !this.discoveryEpochIs(endpointEpoch)) {
|
|
1795
|
+
return { ...this.normalizedAgent, agent_uri: discoveredEndpoint };
|
|
1736
1796
|
}
|
|
1737
1797
|
this.discoveredEndpoint = discoveredEndpoint;
|
|
1738
|
-
|
|
1739
|
-
|
|
1798
|
+
if (this.config.discoveryCache) {
|
|
1799
|
+
this.discoveredEndpointKey = this.sharedDiscoveryKey(options);
|
|
1800
|
+
this.discoveredEndpointEpoch = endpointEpoch?.shared;
|
|
1801
|
+
this.discoveredEndpointExpiresAt = Date.now() + (0, import_agent_discovery_cache.resolveAgentDiscoveryTtlMs)(this.config.discoveryCache.ttlMs);
|
|
1802
|
+
const stored = await this.writeSharedDiscovery(
|
|
1803
|
+
options,
|
|
1804
|
+
{
|
|
1805
|
+
endpoint: {
|
|
1806
|
+
agentUri: discoveredEndpoint,
|
|
1807
|
+
...this.discoveredMcpEra && { mcpEra: this.discoveredMcpEra }
|
|
1808
|
+
}
|
|
1809
|
+
},
|
|
1810
|
+
false,
|
|
1811
|
+
endpointEpoch
|
|
1812
|
+
);
|
|
1813
|
+
if (endpointEpoch && !this.discoveryEpochIs(endpointEpoch)) {
|
|
1814
|
+
if (this.discoveredEndpoint === discoveredEndpoint && this.discoveredEndpointEpoch === endpointEpoch.shared) {
|
|
1815
|
+
this.discoveredEndpoint = void 0;
|
|
1816
|
+
this.discoveredEndpointKey = void 0;
|
|
1817
|
+
this.discoveredEndpointEpoch = void 0;
|
|
1818
|
+
this.discoveredEndpointExpiresAt = void 0;
|
|
1819
|
+
if (this.discoveredAgent?.agent_uri === discoveredEndpoint) this.discoveredAgent = void 0;
|
|
1820
|
+
this.discoveredMcpEra = void 0;
|
|
1821
|
+
}
|
|
1822
|
+
return { ...this.normalizedAgent, agent_uri: discoveredEndpoint };
|
|
1823
|
+
}
|
|
1824
|
+
if (stored && this.discoveredEndpoint === discoveredEndpoint) this.discoveredEndpointExpiresAt = stored.expiresAt;
|
|
1825
|
+
}
|
|
1826
|
+
this.canonicalBaseUrl = this.computeBaseUrl(discoveredEndpoint);
|
|
1827
|
+
const discoveredAgent = {
|
|
1740
1828
|
...this.normalizedAgent,
|
|
1741
|
-
agent_uri:
|
|
1829
|
+
agent_uri: discoveredEndpoint
|
|
1742
1830
|
};
|
|
1831
|
+
this.discoveredAgent = discoveredAgent;
|
|
1743
1832
|
if (this.normalizedAgent.oauth_tokens && !this.normalizedAgent.oauth_client_credentials) {
|
|
1744
1833
|
const { shareNonInteractiveOAuthProvider } = await import("../auth/oauth/provider-cache.js");
|
|
1745
|
-
shareNonInteractiveOAuthProvider(this.normalizedAgent,
|
|
1834
|
+
shareNonInteractiveOAuthProvider(this.normalizedAgent, discoveredAgent);
|
|
1746
1835
|
}
|
|
1747
|
-
return
|
|
1836
|
+
return discoveredAgent;
|
|
1748
1837
|
}
|
|
1749
1838
|
/**
|
|
1750
1839
|
* Ensure A2A canonical URL is resolved (lazy initialization)
|
|
@@ -3214,6 +3303,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
3214
3303
|
)
|
|
3215
3304
|
);
|
|
3216
3305
|
(0, import_abort2.throwIfAborted)(effectiveOptions?.signal);
|
|
3306
|
+
if (!result.success) await this.invalidateDiscoveryOnCapabilityError(result.adcpError?.code, effectiveOptions);
|
|
3217
3307
|
const postAdapterLogs = [...inputSchemaStripLogs, ...v25DriftLogs];
|
|
3218
3308
|
if (postAdapterLogs.length > 0) {
|
|
3219
3309
|
result.debug_logs = [...result.debug_logs ?? [], ...postAdapterLogs];
|
|
@@ -5722,6 +5812,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
5722
5812
|
beforeDispatch,
|
|
5723
5813
|
deferredClientContext
|
|
5724
5814
|
);
|
|
5815
|
+
if (!result.success) await this.invalidateDiscoveryOnCapabilityError(result.adcpError?.code, effectiveOptions);
|
|
5725
5816
|
const postAdapterLogs = [...inputSchemaStripLogs, ...v25DriftLogs];
|
|
5726
5817
|
if (postAdapterLogs.length > 0) {
|
|
5727
5818
|
result.debug_logs = [...result.debug_logs ?? [], ...postAdapterLogs];
|
|
@@ -6287,6 +6378,26 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
6287
6378
|
tools
|
|
6288
6379
|
};
|
|
6289
6380
|
}
|
|
6381
|
+
const { withScopedLegacyConnection } = await import("../protocols/mcp.js");
|
|
6382
|
+
const scopedList = await withScopedLegacyConnection(
|
|
6383
|
+
connectOptions,
|
|
6384
|
+
"tools/list",
|
|
6385
|
+
(client) => withResponseSizeLimit(maxResponseBytes, () => client.listTools(mcpListParams, mcpRequestOptions))
|
|
6386
|
+
);
|
|
6387
|
+
if (scopedList) {
|
|
6388
|
+
return {
|
|
6389
|
+
name: this.normalizedAgent.name,
|
|
6390
|
+
description: void 0,
|
|
6391
|
+
protocol: this.normalizedAgent.protocol,
|
|
6392
|
+
url: agent.agent_uri,
|
|
6393
|
+
tools: scopedList.value.tools.map((tool) => ({
|
|
6394
|
+
name: tool.name,
|
|
6395
|
+
description: tool.description,
|
|
6396
|
+
inputSchema: tool.inputSchema,
|
|
6397
|
+
parameters: tool.inputSchema?.properties ? Object.keys(tool.inputSchema.properties) : []
|
|
6398
|
+
}))
|
|
6399
|
+
};
|
|
6400
|
+
}
|
|
6290
6401
|
const { client: mcpClient } = await connectMCP(connectOptions);
|
|
6291
6402
|
try {
|
|
6292
6403
|
const toolsList = await withResponseSizeLimit(
|
|
@@ -6400,12 +6511,98 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
6400
6511
|
this.cachedCapabilities = void 0;
|
|
6401
6512
|
this.cachedToolSchemas = void 0;
|
|
6402
6513
|
this.primedCapabilitiesExpiresAt = void 0;
|
|
6514
|
+
this.capabilitiesFromSharedCache = false;
|
|
6515
|
+
}
|
|
6516
|
+
const effectiveSharedKey = this.config.discoveryCache && !usesScopedFetch && this.cachedCapabilities ? this.sharedDiscoveryKey(options) : void 0;
|
|
6517
|
+
if (this.config.discoveryCache && !usesScopedFetch && this.cachedCapabilities && (this.sharedEvidenceKey !== effectiveSharedKey || effectiveSharedKey !== void 0 && this.sharedEvidenceEpoch !== void 0 && this.sharedEvidenceEpoch !== this.sharedInvalidationEpoch(effectiveSharedKey))) {
|
|
6518
|
+
this.cachedCapabilities = void 0;
|
|
6519
|
+
this.cachedToolSchemas = void 0;
|
|
6520
|
+
this.primedCapabilitiesExpiresAt = void 0;
|
|
6521
|
+
this.capabilitiesFromSharedCache = false;
|
|
6403
6522
|
}
|
|
6404
6523
|
if (!usesScopedFetch && this.cachedCapabilities) {
|
|
6405
6524
|
if (discoveryContext) discoveryContext.toolSchemas = this.cachedToolSchemas;
|
|
6406
6525
|
this.maybeWarnV2Sunset(this.cachedCapabilities);
|
|
6407
6526
|
return this.cachedCapabilities;
|
|
6408
6527
|
}
|
|
6528
|
+
if (!usesScopedFetch && this.config.discoveryCache) {
|
|
6529
|
+
return this.discoverCapabilitiesThroughSharedCache(options, usesScopedFetch, discoveryContext);
|
|
6530
|
+
}
|
|
6531
|
+
return this.discoverCapabilitiesLive(options, usesScopedFetch, discoveryContext);
|
|
6532
|
+
}
|
|
6533
|
+
/**
|
|
6534
|
+
* Serve capabilities from the shared `discoveryCache`, or discover them live
|
|
6535
|
+
* as the single in-process "leader" for this cache key. Concurrent clients
|
|
6536
|
+
* for the same key wait for the leader under their *own* signal and deadline;
|
|
6537
|
+
* a leader that fails or is cancelled never fails its followers, which then
|
|
6538
|
+
* discover for themselves.
|
|
6539
|
+
*/
|
|
6540
|
+
async discoverCapabilitiesThroughSharedCache(options, usesScopedFetch, discoveryContext) {
|
|
6541
|
+
const config = this.config.discoveryCache;
|
|
6542
|
+
const key = this.sharedDiscoveryKey(options);
|
|
6543
|
+
if (!key) return this.discoverCapabilitiesLive(options, usesScopedFetch, discoveryContext);
|
|
6544
|
+
let flights = sharedDiscoveryFlights.get(config.cache);
|
|
6545
|
+
if (!flights) {
|
|
6546
|
+
flights = /* @__PURE__ */ new Map();
|
|
6547
|
+
sharedDiscoveryFlights.set(config.cache, flights);
|
|
6548
|
+
}
|
|
6549
|
+
for (let attempt = 0; ; attempt++) {
|
|
6550
|
+
const readEpoch = this.discoveryEpochSnapshot(options);
|
|
6551
|
+
const entry = await this.readSharedDiscovery(options);
|
|
6552
|
+
const installed = entry && (!readEpoch || this.discoveryEpochIs(readEpoch)) && this.installSharedCapabilities(entry, key, discoveryContext);
|
|
6553
|
+
if (installed) return installed;
|
|
6554
|
+
const flight = flights.get(key);
|
|
6555
|
+
if (flight && attempt < MAX_SHARED_DISCOVERY_WAITS) {
|
|
6556
|
+
const requestTimeoutMs = (0, import_abort2.resolveRequestTimeoutMs)(
|
|
6557
|
+
options?.transport?.requestTimeoutMs ?? this.config.transport?.requestTimeoutMs
|
|
6558
|
+
);
|
|
6559
|
+
await (0, import_abort2.withAbortSignal)([options?.signal], requestTimeoutMs, () => flight);
|
|
6560
|
+
continue;
|
|
6561
|
+
}
|
|
6562
|
+
let finish;
|
|
6563
|
+
const mine = new Promise((resolve) => finish = resolve);
|
|
6564
|
+
const ownsFlight = !flights.has(key);
|
|
6565
|
+
if (ownsFlight) flights.set(key, mine);
|
|
6566
|
+
try {
|
|
6567
|
+
return await this.discoverCapabilitiesLive(options, usesScopedFetch, discoveryContext);
|
|
6568
|
+
} finally {
|
|
6569
|
+
if (ownsFlight) {
|
|
6570
|
+
flights.delete(key);
|
|
6571
|
+
}
|
|
6572
|
+
finish();
|
|
6573
|
+
}
|
|
6574
|
+
}
|
|
6575
|
+
}
|
|
6576
|
+
/** Install capabilities from a shared entry; `undefined` when the entry is not usable evidence. */
|
|
6577
|
+
installSharedCapabilities(entry, key, discoveryContext) {
|
|
6578
|
+
const capabilities = entry.capabilities;
|
|
6579
|
+
if (!isCapabilityEvidence(capabilities) || capabilities._synthetic) return void 0;
|
|
6580
|
+
const toolSchemas = entry.toolSchemas;
|
|
6581
|
+
const hasToolEvidence = toolSchemas !== void 0 || Array.isArray(capabilities.discoveredTools);
|
|
6582
|
+
if (!hasToolEvidence) return void 0;
|
|
6583
|
+
if (toolSchemas !== void 0 && !isToolSchemaRecord(toolSchemas)) {
|
|
6584
|
+
return void 0;
|
|
6585
|
+
}
|
|
6586
|
+
let installed;
|
|
6587
|
+
let schemas;
|
|
6588
|
+
try {
|
|
6589
|
+
installed = structuredClone(capabilities);
|
|
6590
|
+
schemas = toolSchemas ? new Map(Object.entries(toolSchemas).map(([tool, properties]) => [tool, structuredClone(properties)])) : void 0;
|
|
6591
|
+
} catch {
|
|
6592
|
+
return void 0;
|
|
6593
|
+
}
|
|
6594
|
+
this.cachedCapabilities = installed;
|
|
6595
|
+
this.cachedToolSchemas = schemas;
|
|
6596
|
+
this.primedCapabilitiesExpiresAt = entry.expiresAt;
|
|
6597
|
+
this.capabilitiesFromSharedCache = true;
|
|
6598
|
+
this.recordSharedEvidence(key);
|
|
6599
|
+
if (discoveryContext) discoveryContext.toolSchemas = this.cachedToolSchemas;
|
|
6600
|
+
this.maybeWarnV2Sunset(installed);
|
|
6601
|
+
return installed;
|
|
6602
|
+
}
|
|
6603
|
+
async discoverCapabilitiesLive(options, usesScopedFetch, discoveryContext) {
|
|
6604
|
+
const startedAtEpoch = this.discoveryEpochSnapshot(options);
|
|
6605
|
+
const superseded = () => startedAtEpoch !== void 0 && !this.discoveryEpochIs(startedAtEpoch);
|
|
6409
6606
|
const agentInfo = await this.getAgentInfo(options);
|
|
6410
6607
|
const tools = agentInfo.tools.map((t) => ({
|
|
6411
6608
|
name: t.name,
|
|
@@ -6415,7 +6612,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
6415
6612
|
agentInfo.tools.filter((t) => t.inputSchema?.properties).map((t) => [t.name, t.inputSchema.properties])
|
|
6416
6613
|
);
|
|
6417
6614
|
if (discoveryContext) discoveryContext.toolSchemas = discoveredToolSchemas;
|
|
6418
|
-
if (!usesScopedFetch) this.cachedToolSchemas = discoveredToolSchemas;
|
|
6615
|
+
if (!usesScopedFetch && !superseded()) this.cachedToolSchemas = discoveredToolSchemas;
|
|
6419
6616
|
const advertisesCapabilitiesTool = tools.some((t) => t.name === "get_adcp_capabilities");
|
|
6420
6617
|
const officialA2ALifecycle = this.normalizedAgent.protocol === "a2a" && tools.some((tool) => ["tasks/get", "get_task_status", "list_tasks"].includes(tool.name));
|
|
6421
6618
|
const hasCapabilitiesTool = advertisesCapabilitiesTool || officialA2ALifecycle;
|
|
@@ -6447,7 +6644,31 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
6447
6644
|
}
|
|
6448
6645
|
if (result.success && result.data) {
|
|
6449
6646
|
const capabilities2 = (0, import_capabilities.augmentCapabilitiesFromTools)((0, import_capabilities.parseCapabilitiesResponse)(result.data), tools);
|
|
6450
|
-
if (!usesScopedFetch
|
|
6647
|
+
if (!usesScopedFetch && !superseded()) {
|
|
6648
|
+
this.cachedCapabilities = capabilities2;
|
|
6649
|
+
this.capabilitiesFromSharedCache = false;
|
|
6650
|
+
if (!capabilities2._synthetic && this.config.discoveryCache) {
|
|
6651
|
+
this.recordSharedEvidence(this.sharedDiscoveryKey(options));
|
|
6652
|
+
const stored = await this.writeSharedDiscovery(
|
|
6653
|
+
options,
|
|
6654
|
+
{
|
|
6655
|
+
capabilities: structuredClone(capabilities2),
|
|
6656
|
+
toolSchemas: Object.fromEntries(discoveredToolSchemas)
|
|
6657
|
+
},
|
|
6658
|
+
false,
|
|
6659
|
+
startedAtEpoch
|
|
6660
|
+
);
|
|
6661
|
+
if (superseded()) {
|
|
6662
|
+
if (this.cachedCapabilities === capabilities2) {
|
|
6663
|
+
this.cachedCapabilities = void 0;
|
|
6664
|
+
this.cachedToolSchemas = void 0;
|
|
6665
|
+
this.primedCapabilitiesExpiresAt = void 0;
|
|
6666
|
+
}
|
|
6667
|
+
} else {
|
|
6668
|
+
this.primedCapabilitiesExpiresAt = stored?.expiresAt ?? Date.now() + (0, import_agent_discovery_cache.resolveAgentDiscoveryTtlMs)(this.config.discoveryCache.ttlMs);
|
|
6669
|
+
}
|
|
6670
|
+
}
|
|
6671
|
+
}
|
|
6451
6672
|
this.maybeWarnV2Sunset(capabilities2);
|
|
6452
6673
|
return capabilities2;
|
|
6453
6674
|
}
|
|
@@ -6466,7 +6687,11 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
6466
6687
|
majorVersions: parsed.majorVersions.includes(3) ? parsed.majorVersions : [3]
|
|
6467
6688
|
};
|
|
6468
6689
|
const capabilities2 = (0, import_capabilities.augmentCapabilitiesFromTools)(v3Capabilities, tools);
|
|
6469
|
-
if (!usesScopedFetch
|
|
6690
|
+
if (!usesScopedFetch && !superseded()) {
|
|
6691
|
+
this.cachedCapabilities = capabilities2;
|
|
6692
|
+
this.capabilitiesFromSharedCache = false;
|
|
6693
|
+
this.recordSharedEvidence(this.sharedDiscoveryKey(options));
|
|
6694
|
+
}
|
|
6470
6695
|
this.maybeWarnV2Sunset(capabilities2);
|
|
6471
6696
|
return capabilities2;
|
|
6472
6697
|
}
|
|
@@ -6490,7 +6715,11 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
6490
6715
|
}
|
|
6491
6716
|
if (advertisesCapabilitiesTool) {
|
|
6492
6717
|
const capabilities2 = (0, import_capabilities.augmentCapabilitiesFromTools)((0, import_capabilities.buildSyntheticV3Capabilities)(tools), tools);
|
|
6493
|
-
if (!usesScopedFetch
|
|
6718
|
+
if (!usesScopedFetch && !superseded()) {
|
|
6719
|
+
this.cachedCapabilities = capabilities2;
|
|
6720
|
+
this.capabilitiesFromSharedCache = false;
|
|
6721
|
+
this.recordSharedEvidence(this.sharedDiscoveryKey(options));
|
|
6722
|
+
}
|
|
6494
6723
|
this.maybeWarnV2Sunset(capabilities2);
|
|
6495
6724
|
return capabilities2;
|
|
6496
6725
|
}
|
|
@@ -6499,7 +6728,11 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
6499
6728
|
`[AdCP] Agent "${this.agent.id}" detected as v2 (no get_adcp_capabilities tool). Tools: [${tools.map((t) => t.name).join(", ")}]`
|
|
6500
6729
|
);
|
|
6501
6730
|
const capabilities = (0, import_capabilities.buildSyntheticCapabilities)(tools);
|
|
6502
|
-
if (!usesScopedFetch
|
|
6731
|
+
if (!usesScopedFetch && !superseded()) {
|
|
6732
|
+
this.cachedCapabilities = capabilities;
|
|
6733
|
+
this.capabilitiesFromSharedCache = false;
|
|
6734
|
+
this.recordSharedEvidence(this.sharedDiscoveryKey(options));
|
|
6735
|
+
}
|
|
6503
6736
|
return capabilities;
|
|
6504
6737
|
}
|
|
6505
6738
|
/**
|
|
@@ -6570,6 +6803,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
6570
6803
|
this.cachedCapabilities = void 0;
|
|
6571
6804
|
this.cachedToolSchemas = void 0;
|
|
6572
6805
|
this.primedCapabilitiesExpiresAt = void 0;
|
|
6806
|
+
this.capabilitiesFromSharedCache = false;
|
|
6573
6807
|
return false;
|
|
6574
6808
|
}
|
|
6575
6809
|
try {
|
|
@@ -6578,6 +6812,8 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
6578
6812
|
].map((name) => ({ name }));
|
|
6579
6813
|
this.cachedCapabilities = (0, import_capabilities.augmentCapabilitiesFromTools)(structuredClone(capabilities), observedTools);
|
|
6580
6814
|
this.primedCapabilitiesExpiresAt = expiresAt;
|
|
6815
|
+
this.capabilitiesFromSharedCache = false;
|
|
6816
|
+
this.recordSharedEvidence(this.sharedDiscoveryKey(), true);
|
|
6581
6817
|
this.cachedToolSchemas = snapshot.toolSchemas ? new Map(
|
|
6582
6818
|
Object.entries(snapshot.toolSchemas).map(([tool, properties]) => [
|
|
6583
6819
|
tool,
|
|
@@ -6592,6 +6828,396 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
6592
6828
|
return false;
|
|
6593
6829
|
}
|
|
6594
6830
|
}
|
|
6831
|
+
/** Which kind of credential this client presents (never its value), so an unauthenticated client cannot adopt an authenticated one's evidence. */
|
|
6832
|
+
discoveryCredentialKind() {
|
|
6833
|
+
const agent = this.normalizedAgent;
|
|
6834
|
+
if (agent.oauth_client_credentials) return "oauth-client-credentials";
|
|
6835
|
+
if (agent.oauth_tokens) return "oauth";
|
|
6836
|
+
if (agent.auth_token) return "bearer";
|
|
6837
|
+
const headerNames = Object.keys(agent.headers ?? {}).map((name) => name.toLowerCase());
|
|
6838
|
+
return headerNames.includes("authorization") || headerNames.includes("x-adcp-auth") ? "header" : "none";
|
|
6839
|
+
}
|
|
6840
|
+
/** Epoch of this client's evidence for the call's effective shared key; `undefined` without a shared cache. */
|
|
6841
|
+
discoveryEpochSnapshot(options) {
|
|
6842
|
+
const key = this.sharedDiscoveryKey(options);
|
|
6843
|
+
if (!key || !this.config.discoveryCache) return void 0;
|
|
6844
|
+
return { local: this.discoveryEpoch, shared: this.sharedInvalidationEpoch(key), key };
|
|
6845
|
+
}
|
|
6846
|
+
discoveryEpochIs(epoch) {
|
|
6847
|
+
return epoch.local === this.discoveryEpoch && epoch.shared === this.sharedInvalidationEpoch(epoch.key);
|
|
6848
|
+
}
|
|
6849
|
+
/** The latest invalidation that applies to `key`: its own, combined with the cache's floor of forgotten ones. */
|
|
6850
|
+
sharedInvalidationRecord(key) {
|
|
6851
|
+
const cache = this.config.discoveryCache.cache;
|
|
6852
|
+
const record = sharedInvalidations.get(cache)?.get(key);
|
|
6853
|
+
const floor = sharedInvalidationFloors.get(cache);
|
|
6854
|
+
if (!floor) return record;
|
|
6855
|
+
if (!record) return floor;
|
|
6856
|
+
return { epoch: Math.max(record.epoch, floor.epoch), at: Math.max(record.at, floor.at) };
|
|
6857
|
+
}
|
|
6858
|
+
sharedInvalidationEpoch(key) {
|
|
6859
|
+
return this.sharedInvalidationRecord(key)?.epoch ?? 0;
|
|
6860
|
+
}
|
|
6861
|
+
bumpSharedInvalidationEpoch(key) {
|
|
6862
|
+
const cache = this.config.discoveryCache.cache;
|
|
6863
|
+
let records = sharedInvalidations.get(cache);
|
|
6864
|
+
if (!records) {
|
|
6865
|
+
records = /* @__PURE__ */ new Map();
|
|
6866
|
+
sharedInvalidations.set(cache, records);
|
|
6867
|
+
}
|
|
6868
|
+
const now = Date.now();
|
|
6869
|
+
records.delete(key);
|
|
6870
|
+
records.set(key, { epoch: ++sharedInvalidationCounter, at: now });
|
|
6871
|
+
for (const [oldKey, record] of records) {
|
|
6872
|
+
if (records.size <= MAX_SHARED_INVALIDATION_RECORDS && record.at + import_agent_discovery_cache.MAX_AGENT_DISCOVERY_TTL_MS > now) break;
|
|
6873
|
+
const floor = sharedInvalidationFloors.get(cache);
|
|
6874
|
+
sharedInvalidationFloors.set(cache, {
|
|
6875
|
+
epoch: Math.max(record.epoch, floor?.epoch ?? 0),
|
|
6876
|
+
at: Math.max(record.at, floor?.at ?? 0)
|
|
6877
|
+
});
|
|
6878
|
+
records.delete(oldKey);
|
|
6879
|
+
}
|
|
6880
|
+
}
|
|
6881
|
+
/**
|
|
6882
|
+
* Remember which key the local capability evidence belongs to and, unless it
|
|
6883
|
+
* is application-owned (`primeCapabilities`), the shared invalidation epoch it
|
|
6884
|
+
* was obtained under. Application-owned evidence keeps its caller-declared
|
|
6885
|
+
* freshness and is not discarded by another instance's invalidation.
|
|
6886
|
+
*/
|
|
6887
|
+
recordSharedEvidence(key, applicationOwned = false) {
|
|
6888
|
+
this.sharedEvidenceKey = key;
|
|
6889
|
+
this.sharedEvidenceEpoch = key && this.config.discoveryCache && !applicationOwned ? this.sharedInvalidationEpoch(key) : void 0;
|
|
6890
|
+
}
|
|
6891
|
+
/** Non-secret fingerprint of the request-signing identity, so keys never mix signing identities. */
|
|
6892
|
+
discoverySigningFingerprint() {
|
|
6893
|
+
const signing = this.normalizedAgent.request_signing;
|
|
6894
|
+
if (!signing) return void 0;
|
|
6895
|
+
const provider = signing.kind === "provider" ? signing.provider : void 0;
|
|
6896
|
+
return {
|
|
6897
|
+
kind: signing.kind ?? "inline",
|
|
6898
|
+
agentUrl: signing.agent_url ?? null,
|
|
6899
|
+
kid: (provider ? provider.keyid : signing.kid) ?? null,
|
|
6900
|
+
alg: (provider ? provider.algorithm : signing.alg) ?? null,
|
|
6901
|
+
alwaysSign: signing.always_sign ?? null,
|
|
6902
|
+
signSupported: signing.sign_supported ?? null
|
|
6903
|
+
};
|
|
6904
|
+
}
|
|
6905
|
+
/**
|
|
6906
|
+
* Shared-discovery key for the effective transport policy of this call, or
|
|
6907
|
+
* `undefined` when sharing is off or the call uses a scoped `trustedFetchFn`
|
|
6908
|
+
* (whose network boundary is per-call, so its evidence is never shared).
|
|
6909
|
+
*/
|
|
6910
|
+
sharedDiscoveryKey(options) {
|
|
6911
|
+
const config = this.config.discoveryCache;
|
|
6912
|
+
if (!config) return void 0;
|
|
6913
|
+
const transport = (0, import_protocols.normalizeTransportOptions)(options?.transport ?? this.config.transport);
|
|
6914
|
+
if (transport?.trustedFetchFn !== void 0) return void 0;
|
|
6915
|
+
return (0, import_agent_discovery_cache.agentDiscoveryCacheKey)({
|
|
6916
|
+
protocol: this.normalizedAgent.protocol,
|
|
6917
|
+
agentUri: this.normalizedAgent.agent_uri,
|
|
6918
|
+
adcpVersion: this.resolvedAdcpVersion,
|
|
6919
|
+
wireAdcpVersion: this.config.wireAdcpVersion,
|
|
6920
|
+
authIdentity: config.authIdentity,
|
|
6921
|
+
credentialKind: this.discoveryCredentialKind(),
|
|
6922
|
+
headers: (0, import_mcp_call_context.withAmbientIdentityHeaders)(this.normalizedAgent.headers),
|
|
6923
|
+
signing: this.discoverySigningFingerprint(),
|
|
6924
|
+
allowPrivateIp: transport?.allowPrivateIp,
|
|
6925
|
+
maxResponseBytes: transport?.maxResponseBytes
|
|
6926
|
+
});
|
|
6927
|
+
}
|
|
6928
|
+
/**
|
|
6929
|
+
* Run a shared-cache operation under the caller's signal and a fixed backend
|
|
6930
|
+
* deadline, so an unresponsive store can neither make a call uncancellable nor
|
|
6931
|
+
* stall it beyond {@link SHARED_DISCOVERY_CACHE_TIMEOUT_MS}. Rejects on the
|
|
6932
|
+
* caller's abort or when the backend fails or times out; callers decide which
|
|
6933
|
+
* of those is a miss.
|
|
6934
|
+
*/
|
|
6935
|
+
boundedCacheOperation(operation, signal) {
|
|
6936
|
+
return (0, import_abort2.withAbortSignal)([signal], SHARED_DISCOVERY_CACHE_TIMEOUT_MS, () => Promise.resolve().then(operation));
|
|
6937
|
+
}
|
|
6938
|
+
/**
|
|
6939
|
+
* Run one backend mutation (or read-modify-write) for a shared key strictly
|
|
6940
|
+
* after every earlier mutation of that key in this process has actually
|
|
6941
|
+
* settled. The caller's wait is still bounded: an unresponsive backend makes
|
|
6942
|
+
* the caller see a miss, but later mutations stay queued behind the hung
|
|
6943
|
+
* operation, so an old callback can never land after a newer one.
|
|
6944
|
+
*
|
|
6945
|
+
* The queue is bounded. A `droppable` mutation (a write or cleanup) is
|
|
6946
|
+
* abandoned when its caller stopped waiting before it started, and is refused
|
|
6947
|
+
* when the key's queue is full; refusal is a failed write, never a call
|
|
6948
|
+
* failure. A `delete` is never refused for a known key: while one is queued
|
|
6949
|
+
* and not yet started, a newer invalidation joins it. Only for a new key beyond
|
|
6950
|
+
* the key cap is a delete refused — the invalidation tombstone still hides the
|
|
6951
|
+
* entry from this process's readers.
|
|
6952
|
+
*/
|
|
6953
|
+
serializedCacheMutation(key, operation, signal, kind = "droppable") {
|
|
6954
|
+
const cache = this.config.discoveryCache.cache;
|
|
6955
|
+
let chains = sharedMutationChains.get(cache);
|
|
6956
|
+
if (!chains) {
|
|
6957
|
+
chains = /* @__PURE__ */ new Map();
|
|
6958
|
+
sharedMutationChains.set(cache, chains);
|
|
6959
|
+
}
|
|
6960
|
+
let queue = chains.get(key);
|
|
6961
|
+
if (!queue && chains.size >= MAX_SHARED_MUTATION_KEYS) {
|
|
6962
|
+
return Promise.reject(new Error("Shared discovery cache mutation queue is full."));
|
|
6963
|
+
}
|
|
6964
|
+
if (kind === "delete" && queue?.waitingDelete && !queue.waitingDelete.started) {
|
|
6965
|
+
const joined = queue.waitingDelete.promise;
|
|
6966
|
+
return this.boundedCacheOperation(() => joined, signal);
|
|
6967
|
+
}
|
|
6968
|
+
if (kind === "droppable" && queue && queue.pending >= MAX_PENDING_SHARED_MUTATIONS_PER_KEY) {
|
|
6969
|
+
return Promise.reject(new Error("Shared discovery cache mutation queue is full."));
|
|
6970
|
+
}
|
|
6971
|
+
if (!queue) {
|
|
6972
|
+
queue = { tail: Promise.resolve(), pending: 0 };
|
|
6973
|
+
chains.set(key, queue);
|
|
6974
|
+
}
|
|
6975
|
+
const current = queue;
|
|
6976
|
+
const state = { abandoned: false, started: false };
|
|
6977
|
+
const run = current.tail.then(() => {
|
|
6978
|
+
if (kind === "droppable" && state.abandoned) throw new Error("Shared discovery cache mutation abandoned.");
|
|
6979
|
+
state.started = true;
|
|
6980
|
+
if (current.waitingDelete?.promise === run) current.waitingDelete.started = true;
|
|
6981
|
+
return operation();
|
|
6982
|
+
});
|
|
6983
|
+
current.pending++;
|
|
6984
|
+
if (kind === "delete") current.waitingDelete = { promise: run, started: false };
|
|
6985
|
+
const tail = run.then(
|
|
6986
|
+
() => void 0,
|
|
6987
|
+
() => void 0
|
|
6988
|
+
);
|
|
6989
|
+
current.tail = tail;
|
|
6990
|
+
void tail.then(() => {
|
|
6991
|
+
current.pending--;
|
|
6992
|
+
if (current.waitingDelete?.promise === run) current.waitingDelete = void 0;
|
|
6993
|
+
if (current.pending === 0) {
|
|
6994
|
+
if (chains.get(key) === current) chains.delete(key);
|
|
6995
|
+
if (chains.size === 0 && sharedMutationChains.get(cache) === chains) sharedMutationChains.delete(cache);
|
|
6996
|
+
}
|
|
6997
|
+
});
|
|
6998
|
+
return this.boundedCacheOperation(() => run, signal).catch((error) => {
|
|
6999
|
+
state.abandoned = true;
|
|
7000
|
+
throw error;
|
|
7001
|
+
});
|
|
7002
|
+
}
|
|
7003
|
+
/** Is this stored entry structurally sound and not expired (before any caller-TTL cap)? */
|
|
7004
|
+
isLiveSharedEntry(entry, now) {
|
|
7005
|
+
return Number.isFinite(entry.expiresAt) && Number.isFinite(entry.observedAt) && entry.expiresAt >= entry.observedAt && entry.expiresAt > now;
|
|
7006
|
+
}
|
|
7007
|
+
/**
|
|
7008
|
+
* Read a fresh, structurally valid shared entry. A backend failure or
|
|
7009
|
+
* timeout is a miss, never a call failure; the caller's own abort propagates.
|
|
7010
|
+
*/
|
|
7011
|
+
async readSharedDiscovery(options) {
|
|
7012
|
+
const key = this.sharedDiscoveryKey(options);
|
|
7013
|
+
if (!key) return void 0;
|
|
7014
|
+
const cache = this.config.discoveryCache.cache;
|
|
7015
|
+
const epoch = this.discoveryEpochSnapshot(options);
|
|
7016
|
+
try {
|
|
7017
|
+
const entry = await this.boundedCacheOperation(() => cache.get(key), options?.signal);
|
|
7018
|
+
if (epoch && !this.discoveryEpochIs(epoch)) return void 0;
|
|
7019
|
+
if (!entry) return void 0;
|
|
7020
|
+
const invalidation = this.sharedInvalidationRecord(key);
|
|
7021
|
+
if (invalidation && entry.observedAt <= invalidation.at) return void 0;
|
|
7022
|
+
const now = Date.now();
|
|
7023
|
+
if (!this.isLiveSharedEntry(entry, now)) {
|
|
7024
|
+
await this.serializedCacheMutation(
|
|
7025
|
+
key,
|
|
7026
|
+
async () => {
|
|
7027
|
+
const current = await cache.get(key);
|
|
7028
|
+
if (current && !this.isLiveSharedEntry(current, Date.now())) await cache.delete(key);
|
|
7029
|
+
},
|
|
7030
|
+
options?.signal
|
|
7031
|
+
);
|
|
7032
|
+
return void 0;
|
|
7033
|
+
}
|
|
7034
|
+
if (entry.observedAt > now + SHARED_DISCOVERY_CLOCK_SKEW_MS) return void 0;
|
|
7035
|
+
const callerExpiresAt = entry.observedAt + (0, import_agent_discovery_cache.resolveAgentDiscoveryTtlMs)(this.config.discoveryCache.ttlMs);
|
|
7036
|
+
if (!(callerExpiresAt > now)) return void 0;
|
|
7037
|
+
return callerExpiresAt < entry.expiresAt ? { ...entry, expiresAt: callerExpiresAt } : entry;
|
|
7038
|
+
} catch {
|
|
7039
|
+
(0, import_abort2.throwIfAborted)(options?.signal);
|
|
7040
|
+
return void 0;
|
|
7041
|
+
}
|
|
7042
|
+
}
|
|
7043
|
+
/**
|
|
7044
|
+
* Merge fresh evidence into the shared entry; the merged entry never outlives
|
|
7045
|
+
* its oldest part. Returns the stored entry, or `undefined` when it was not
|
|
7046
|
+
* stored: automatic writes
|
|
7047
|
+
* ignore a `false` (a failed write only costs a later rediscovery), while
|
|
7048
|
+
* {@link primeDiscoveryCache} reports it.
|
|
7049
|
+
*/
|
|
7050
|
+
async writeSharedDiscovery(options, patch, replace = false, epoch = this.discoveryEpochSnapshot(options)) {
|
|
7051
|
+
const key = this.sharedDiscoveryKey(options);
|
|
7052
|
+
if (!key) return void 0;
|
|
7053
|
+
if (patch.endpoint && !this.isDiscoverableEndpoint(patch.endpoint.agentUri)) {
|
|
7054
|
+
patch = { capabilities: patch.capabilities, toolSchemas: patch.toolSchemas };
|
|
7055
|
+
if (!patch.capabilities && !patch.toolSchemas) return void 0;
|
|
7056
|
+
}
|
|
7057
|
+
const config = this.config.discoveryCache;
|
|
7058
|
+
const stale = () => epoch !== void 0 && !this.discoveryEpochIs(epoch);
|
|
7059
|
+
try {
|
|
7060
|
+
return await this.serializedCacheMutation(
|
|
7061
|
+
key,
|
|
7062
|
+
async () => {
|
|
7063
|
+
if (stale()) return void 0;
|
|
7064
|
+
const invalidation = this.sharedInvalidationRecord(key);
|
|
7065
|
+
const now = Math.max(Date.now(), (invalidation?.at ?? 0) + 1);
|
|
7066
|
+
let existing;
|
|
7067
|
+
if (!replace) {
|
|
7068
|
+
const raw = await config.cache.get(key);
|
|
7069
|
+
if (raw && this.isLiveSharedEntry(raw, now) && raw.observedAt <= now + SHARED_DISCOVERY_CLOCK_SKEW_MS && !(invalidation && raw.observedAt <= invalidation.at)) {
|
|
7070
|
+
const endpointObservedAt = raw.endpoint?.observedAt ?? raw.observedAt;
|
|
7071
|
+
existing = { ...raw };
|
|
7072
|
+
if (existing.endpoint && (!this.isDiscoverableEndpoint(existing.endpoint.agentUri) || invalidation && endpointObservedAt <= invalidation.at))
|
|
7073
|
+
delete existing.endpoint;
|
|
7074
|
+
}
|
|
7075
|
+
if (stale()) return void 0;
|
|
7076
|
+
}
|
|
7077
|
+
const restartsClock = !existing || patch.capabilities !== void 0;
|
|
7078
|
+
const ttl = (0, import_agent_discovery_cache.resolveAgentDiscoveryTtlMs)(config.ttlMs);
|
|
7079
|
+
const entry = {
|
|
7080
|
+
...existing?.capabilities && { capabilities: existing.capabilities },
|
|
7081
|
+
...existing?.toolSchemas && { toolSchemas: existing.toolSchemas },
|
|
7082
|
+
...existing?.endpoint && { endpoint: existing.endpoint },
|
|
7083
|
+
...patch.endpoint && { endpoint: { ...patch.endpoint, observedAt: now } },
|
|
7084
|
+
...patch.capabilities && { capabilities: patch.capabilities },
|
|
7085
|
+
...patch.toolSchemas && { toolSchemas: patch.toolSchemas },
|
|
7086
|
+
observedAt: restartsClock || !existing ? now : Math.min(existing.observedAt, now),
|
|
7087
|
+
expiresAt: restartsClock || !existing ? now + ttl : Math.min(existing.expiresAt, now + ttl)
|
|
7088
|
+
};
|
|
7089
|
+
await config.cache.set(key, structuredClone(entry));
|
|
7090
|
+
return stale() ? void 0 : entry;
|
|
7091
|
+
},
|
|
7092
|
+
options?.signal
|
|
7093
|
+
);
|
|
7094
|
+
} catch {
|
|
7095
|
+
return void 0;
|
|
7096
|
+
}
|
|
7097
|
+
}
|
|
7098
|
+
/** Is `agentUri` a credential-free URL on the configured agent's origin (all discovery ever tries)? */
|
|
7099
|
+
isDiscoverableEndpoint(agentUri) {
|
|
7100
|
+
if (typeof agentUri !== "string") return false;
|
|
7101
|
+
try {
|
|
7102
|
+
const candidate = new URL(agentUri);
|
|
7103
|
+
return candidate.username === "" && candidate.password === "" && candidate.search === "" && candidate.hash === "" && candidate.origin === new URL(this.normalizedAgent.agent_uri).origin;
|
|
7104
|
+
} catch {
|
|
7105
|
+
return false;
|
|
7106
|
+
}
|
|
7107
|
+
}
|
|
7108
|
+
/** Adopt a previously discovered MCP endpoint instead of re-probing the agent. */
|
|
7109
|
+
async adoptSharedEndpoint(options) {
|
|
7110
|
+
const readEpoch = this.discoveryEpochSnapshot(options);
|
|
7111
|
+
const entry = await this.readSharedDiscovery(options);
|
|
7112
|
+
if (readEpoch && !this.discoveryEpochIs(readEpoch)) return;
|
|
7113
|
+
const endpoint = entry?.endpoint;
|
|
7114
|
+
if (!entry || !endpoint || !this.isDiscoverableEndpoint(endpoint.agentUri)) return;
|
|
7115
|
+
const observedAt = Number.isFinite(endpoint.observedAt) ? endpoint.observedAt : entry.observedAt;
|
|
7116
|
+
const sharedKey = this.sharedDiscoveryKey(options);
|
|
7117
|
+
const tombstone = sharedKey ? this.sharedInvalidationRecord(sharedKey) : void 0;
|
|
7118
|
+
if (tombstone && observedAt <= tombstone.at) return;
|
|
7119
|
+
const expiresAt = Math.min(
|
|
7120
|
+
entry.expiresAt,
|
|
7121
|
+
observedAt + (0, import_agent_discovery_cache.resolveAgentDiscoveryTtlMs)(this.config.discoveryCache.ttlMs)
|
|
7122
|
+
);
|
|
7123
|
+
if (!(expiresAt > Date.now()) || observedAt > Date.now() + SHARED_DISCOVERY_CLOCK_SKEW_MS) return;
|
|
7124
|
+
this.discoveredEndpoint = endpoint.agentUri;
|
|
7125
|
+
this.discoveredEndpointKey = this.sharedDiscoveryKey(options);
|
|
7126
|
+
this.discoveredEndpointEpoch = this.discoveredEndpointKey ? this.sharedInvalidationEpoch(this.discoveredEndpointKey) : void 0;
|
|
7127
|
+
this.discoveredEndpointExpiresAt = expiresAt;
|
|
7128
|
+
this.canonicalBaseUrl = this.computeBaseUrl(endpoint.agentUri);
|
|
7129
|
+
if (endpoint.mcpEra === "legacy" || endpoint.mcpEra === "modern") {
|
|
7130
|
+
this.discoveredMcpEra = endpoint.mcpEra;
|
|
7131
|
+
this.discoveredMcpEraAt = observedAt;
|
|
7132
|
+
}
|
|
7133
|
+
}
|
|
7134
|
+
/**
|
|
7135
|
+
* Drop discovery evidence for this client: its in-memory capability and
|
|
7136
|
+
* tool-schema caches, the discovered endpoint, and the shared
|
|
7137
|
+
* `discoveryCache` entry (when configured). The next call rediscovers.
|
|
7138
|
+
*
|
|
7139
|
+
* Call this when you learn the seller changed (a deploy, a version bump, a
|
|
7140
|
+
* capability-dependent error you observed). The SDK also invalidates by
|
|
7141
|
+
* itself when a feature check fails against shared evidence, and when a
|
|
7142
|
+
* seller answers with a version or capability error.
|
|
7143
|
+
*/
|
|
7144
|
+
async invalidateDiscoveryCache(options) {
|
|
7145
|
+
this.cachedCapabilities = void 0;
|
|
7146
|
+
this.cachedToolSchemas = void 0;
|
|
7147
|
+
this.primedCapabilitiesExpiresAt = void 0;
|
|
7148
|
+
this.capabilitiesFromSharedCache = false;
|
|
7149
|
+
this.capabilityEvidenceScopeKey = (0, import_node_crypto.randomUUID)();
|
|
7150
|
+
this.discoveryEpoch++;
|
|
7151
|
+
if (this.normalizedAgent._needsDiscovery) {
|
|
7152
|
+
this.discoveredEndpoint = void 0;
|
|
7153
|
+
this.discoveredAgent = void 0;
|
|
7154
|
+
this.discoveredMcpEra = void 0;
|
|
7155
|
+
this.discoveredEndpointKey = void 0;
|
|
7156
|
+
this.discoveredEndpointEpoch = void 0;
|
|
7157
|
+
this.discoveredEndpointExpiresAt = void 0;
|
|
7158
|
+
}
|
|
7159
|
+
const key = this.sharedDiscoveryKey(options);
|
|
7160
|
+
if (!key) return;
|
|
7161
|
+
this.bumpSharedInvalidationEpoch(key);
|
|
7162
|
+
try {
|
|
7163
|
+
const cache = this.config.discoveryCache.cache;
|
|
7164
|
+
await this.serializedCacheMutation(key, () => cache.delete(key), void 0, "delete");
|
|
7165
|
+
} catch {
|
|
7166
|
+
}
|
|
7167
|
+
}
|
|
7168
|
+
/**
|
|
7169
|
+
* Pre-seed the shared `discoveryCache` with capability evidence the caller
|
|
7170
|
+
* already holds (for example from a registry sync), so no client sharing
|
|
7171
|
+
* this identity probes the seller within the TTL. Unlike
|
|
7172
|
+
* {@link primeCapabilities} the seeded evidence outlives this instance.
|
|
7173
|
+
*
|
|
7174
|
+
* Returns `true` only once the backing cache has accepted the entry. Returns
|
|
7175
|
+
* `false` — having seeded nothing — when sharing is not configured, the
|
|
7176
|
+
* client uses a scoped `trustedFetchFn`, or the evidence is synthetic,
|
|
7177
|
+
* malformed or not cloneable. When the cache rejects the write or does not
|
|
7178
|
+
* answer within the backend deadline, the result is also `false`, but the
|
|
7179
|
+
* outcome is indeterminate: a write already handed to the backend may still
|
|
7180
|
+
* land, whereas one still queued behind earlier operations is dropped. Treat
|
|
7181
|
+
* `false` as "not confirmed", and seed again (or invalidate) rather than
|
|
7182
|
+
* assuming the cache is empty. Seed `endpoint` as well
|
|
7183
|
+
* to skip the endpoint probe on the first call; without it that probe still
|
|
7184
|
+
* runs once per cold client.
|
|
7185
|
+
*/
|
|
7186
|
+
async primeDiscoveryCache(seed) {
|
|
7187
|
+
const key = this.sharedDiscoveryKey();
|
|
7188
|
+
const capabilities = seed?.capabilities;
|
|
7189
|
+
if (!key || !isCapabilityEvidence(capabilities) || capabilities._synthetic) return false;
|
|
7190
|
+
const toolSchemas = seed.toolSchemas;
|
|
7191
|
+
if (toolSchemas !== void 0 && !isToolSchemaRecord(toolSchemas)) {
|
|
7192
|
+
return false;
|
|
7193
|
+
}
|
|
7194
|
+
if (toolSchemas === void 0 && !Array.isArray(capabilities.discoveredTools)) return false;
|
|
7195
|
+
if (seed.endpoint !== void 0 && !this.isDiscoverableEndpoint(seed.endpoint.agentUri)) return false;
|
|
7196
|
+
try {
|
|
7197
|
+
const stored = await this.writeSharedDiscovery(
|
|
7198
|
+
void 0,
|
|
7199
|
+
{
|
|
7200
|
+
capabilities: structuredClone(capabilities),
|
|
7201
|
+
...toolSchemas && { toolSchemas: structuredClone(toolSchemas) },
|
|
7202
|
+
...seed.endpoint && {
|
|
7203
|
+
endpoint: {
|
|
7204
|
+
agentUri: seed.endpoint.agentUri,
|
|
7205
|
+
...seed.endpoint.mcpEra && { mcpEra: seed.endpoint.mcpEra }
|
|
7206
|
+
}
|
|
7207
|
+
}
|
|
7208
|
+
},
|
|
7209
|
+
true
|
|
7210
|
+
);
|
|
7211
|
+
return stored !== void 0;
|
|
7212
|
+
} catch {
|
|
7213
|
+
return false;
|
|
7214
|
+
}
|
|
7215
|
+
}
|
|
7216
|
+
/** Drop shared evidence when a seller answers with an error that says our cached view of it is stale. */
|
|
7217
|
+
async invalidateDiscoveryOnCapabilityError(code, options) {
|
|
7218
|
+
if (!this.config.discoveryCache || !code || !CAPABILITY_STALE_ERROR_CODES.has(code)) return;
|
|
7219
|
+
await this.invalidateDiscoveryCache(options);
|
|
7220
|
+
}
|
|
6595
7221
|
/**
|
|
6596
7222
|
* Emit a one-time warning when the agent reports v2 capabilities.
|
|
6597
7223
|
*
|
|
@@ -6740,8 +7366,21 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
6740
7366
|
* with an actionable error message.
|
|
6741
7367
|
*/
|
|
6742
7368
|
async require(...features) {
|
|
6743
|
-
|
|
6744
|
-
|
|
7369
|
+
await this.assertFeaturesSupported(features);
|
|
7370
|
+
}
|
|
7371
|
+
/**
|
|
7372
|
+
* Throw {@link FeatureUnsupportedError} when a feature is missing, deciding on
|
|
7373
|
+
* live capabilities when the refusal would rest on shared evidence that may
|
|
7374
|
+
* predate a seller upgrade.
|
|
7375
|
+
*/
|
|
7376
|
+
async assertFeaturesSupported(requiredFeatures, options) {
|
|
7377
|
+
let capabilities = await this.getCapabilities(options);
|
|
7378
|
+
let missing = requiredFeatures.filter((f) => !(0, import_capabilities.resolveFeature)(capabilities, f));
|
|
7379
|
+
if (missing.length > 0 && this.capabilitiesFromSharedCache) {
|
|
7380
|
+
await this.invalidateDiscoveryCache(options);
|
|
7381
|
+
capabilities = await this.getCapabilities(options);
|
|
7382
|
+
missing = requiredFeatures.filter((f) => !(0, import_capabilities.resolveFeature)(capabilities, f));
|
|
7383
|
+
}
|
|
6745
7384
|
if (missing.length > 0) {
|
|
6746
7385
|
throw new import_errors.FeatureUnsupportedError(missing, (0, import_capabilities.listDeclaredFeatures)(capabilities), this.agent.agent_uri);
|
|
6747
7386
|
}
|
|
@@ -6754,7 +7393,10 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
6754
7393
|
this.cachedCapabilities = void 0;
|
|
6755
7394
|
this.cachedToolSchemas = void 0;
|
|
6756
7395
|
this.primedCapabilitiesExpiresAt = void 0;
|
|
7396
|
+
this.capabilitiesFromSharedCache = false;
|
|
6757
7397
|
this.capabilityEvidenceScopeKey = (0, import_node_crypto.randomUUID)();
|
|
7398
|
+
this.discoveryEpoch++;
|
|
7399
|
+
if (this.config.discoveryCache) await this.invalidateDiscoveryCache();
|
|
6758
7400
|
return this.getCapabilities();
|
|
6759
7401
|
}
|
|
6760
7402
|
/**
|
|
@@ -6767,11 +7409,7 @@ Hint: this usually means agent_uri does not include the MCP endpoint path. The S
|
|
|
6767
7409
|
if (this.config.validateFeatures === false) return;
|
|
6768
7410
|
const requiredFeatures = import_capabilities.TASK_FEATURE_MAP[taskName];
|
|
6769
7411
|
if (!requiredFeatures || requiredFeatures.length === 0) return;
|
|
6770
|
-
|
|
6771
|
-
const missing = requiredFeatures.filter((f) => !(0, import_capabilities.resolveFeature)(capabilities, f));
|
|
6772
|
-
if (missing.length > 0) {
|
|
6773
|
-
throw new import_errors.FeatureUnsupportedError(missing, (0, import_capabilities.listDeclaredFeatures)(capabilities), this.agent.agent_uri);
|
|
6774
|
-
}
|
|
7412
|
+
await this.assertFeaturesSupported(requiredFeatures, options);
|
|
6775
7413
|
}
|
|
6776
7414
|
/**
|
|
6777
7415
|
* Fail version-incompatible request shapes before schema validation.
|