@adcp/sdk 9.3.0 → 9.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/lib/core/AgentClient.d.ts +2 -2
  2. package/dist/lib/core/AgentClient.d.ts.map +1 -1
  3. package/dist/lib/core/AgentClient.js +4 -4
  4. package/dist/lib/core/AgentClient.js.map +1 -1
  5. package/dist/lib/core/ConversationTypes.d.ts +7 -0
  6. package/dist/lib/core/ConversationTypes.d.ts.map +1 -1
  7. package/dist/lib/core/SingleAgentClient.d.ts +9 -5
  8. package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
  9. package/dist/lib/core/SingleAgentClient.js +117 -52
  10. package/dist/lib/core/SingleAgentClient.js.map +1 -1
  11. package/dist/lib/core/TaskExecutor.d.ts +1 -1
  12. package/dist/lib/core/TaskExecutor.d.ts.map +1 -1
  13. package/dist/lib/core/TaskExecutor.js +15 -4
  14. package/dist/lib/core/TaskExecutor.js.map +1 -1
  15. package/dist/lib/discovery/inline-publisher-properties.js +10 -3
  16. package/dist/lib/discovery/inline-publisher-properties.js.map +1 -1
  17. package/dist/lib/discovery/resolve-agent-properties.d.ts +39 -11
  18. package/dist/lib/discovery/resolve-agent-properties.d.ts.map +1 -1
  19. package/dist/lib/discovery/resolve-agent-properties.js +136 -16
  20. package/dist/lib/discovery/resolve-agent-properties.js.map +1 -1
  21. package/dist/lib/discovery/types.d.ts +9 -2
  22. package/dist/lib/discovery/types.d.ts.map +1 -1
  23. package/dist/lib/index.d.ts +1 -1
  24. package/dist/lib/index.d.ts.map +1 -1
  25. package/dist/lib/index.js +14 -12
  26. package/dist/lib/index.js.map +1 -1
  27. package/dist/lib/protocols/a2a.d.ts +1 -1
  28. package/dist/lib/protocols/a2a.d.ts.map +1 -1
  29. package/dist/lib/protocols/a2a.js +66 -35
  30. package/dist/lib/protocols/a2a.js.map +1 -1
  31. package/dist/lib/protocols/abort.d.ts +10 -0
  32. package/dist/lib/protocols/abort.d.ts.map +1 -0
  33. package/dist/lib/protocols/abort.js +107 -0
  34. package/dist/lib/protocols/abort.js.map +1 -0
  35. package/dist/lib/protocols/index.d.ts +10 -0
  36. package/dist/lib/protocols/index.d.ts.map +1 -1
  37. package/dist/lib/protocols/index.js +33 -9
  38. package/dist/lib/protocols/index.js.map +1 -1
  39. package/dist/lib/protocols/mcp-tasks.d.ts +4 -0
  40. package/dist/lib/protocols/mcp-tasks.d.ts.map +1 -1
  41. package/dist/lib/protocols/mcp-tasks.js +27 -11
  42. package/dist/lib/protocols/mcp-tasks.js.map +1 -1
  43. package/dist/lib/protocols/mcp.d.ts +14 -2
  44. package/dist/lib/protocols/mcp.d.ts.map +1 -1
  45. package/dist/lib/protocols/mcp.js +116 -43
  46. package/dist/lib/protocols/mcp.js.map +1 -1
  47. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  48. package/dist/lib/signing/agent-fetch.d.ts +5 -4
  49. package/dist/lib/signing/agent-fetch.d.ts.map +1 -1
  50. package/dist/lib/signing/agent-fetch.js +31 -4
  51. package/dist/lib/signing/agent-fetch.js.map +1 -1
  52. package/dist/lib/signing/capability-priming.d.ts.map +1 -1
  53. package/dist/lib/signing/capability-priming.js +5 -1
  54. package/dist/lib/signing/capability-priming.js.map +1 -1
  55. package/dist/lib/signing/verifier.d.ts.map +1 -1
  56. package/dist/lib/signing/verifier.js +10 -37
  57. package/dist/lib/signing/verifier.js.map +1 -1
  58. package/dist/lib/signing/webhook-auth-detection.d.ts +10 -0
  59. package/dist/lib/signing/webhook-auth-detection.d.ts.map +1 -0
  60. package/dist/lib/signing/webhook-auth-detection.js +37 -0
  61. package/dist/lib/signing/webhook-auth-detection.js.map +1 -0
  62. package/dist/lib/testing/client.js +3 -3
  63. package/dist/lib/testing/client.js.map +1 -1
  64. package/dist/lib/testing/types.d.ts +2 -0
  65. package/dist/lib/testing/types.d.ts.map +1 -1
  66. package/dist/lib/version.d.ts +3 -3
  67. package/dist/lib/version.js +3 -3
  68. package/package.json +1 -1
@@ -46,6 +46,7 @@ const idempotency_1 = require("../utils/idempotency");
46
46
  const TaskExecutor_1 = require("./TaskExecutor");
47
47
  const match_1 = require("./match");
48
48
  const auth_1 = require("../auth");
49
+ const abort_1 = require("../protocols/abort");
49
50
  const errors_1 = require("../errors");
50
51
  const net_1 = require("../net");
51
52
  const authorization_required_1 = require("../auth/oauth/authorization-required");
@@ -55,6 +56,7 @@ const webhooks_1 = require("../webhooks");
55
56
  const response_unwrapper_1 = require("../utils/response-unwrapper");
56
57
  const a2a_discovery_1 = require("../utils/a2a-discovery");
57
58
  const crypto = __importStar(require("crypto"));
59
+ const abort_2 = require("../protocols/abort");
58
60
  const capabilities_1 = require("../utils/capabilities");
59
61
  const request_normalizer_1 = require("../utils/request-normalizer");
60
62
  const validate_user_agent_1 = require("../utils/validate-user-agent");
@@ -313,7 +315,8 @@ class SingleAgentClient {
313
315
  * Returns the agent config with the discovered endpoint.
314
316
  * Also computes the canonical base URL by stripping /mcp suffix.
315
317
  */
316
- async ensureEndpointDiscovered() {
318
+ async ensureEndpointDiscovered(options) {
319
+ (0, abort_2.throwIfAborted)(options?.signal);
317
320
  const needsDiscovery = this.normalizedAgent._needsDiscovery;
318
321
  if (!needsDiscovery) {
319
322
  return this.normalizedAgent;
@@ -330,7 +333,7 @@ class SingleAgentClient {
330
333
  return this.discoveredAgent;
331
334
  }
332
335
  // Perform discovery
333
- this.discoveredEndpoint = await this.discoverMCPEndpoint(this.normalizedAgent.agent_uri);
336
+ this.discoveredEndpoint = await this.discoverMCPEndpoint(this.normalizedAgent.agent_uri, options);
334
337
  // Compute canonical base URL by stripping /mcp suffix
335
338
  this.canonicalBaseUrl = this.computeBaseUrl(this.discoveredEndpoint);
336
339
  this.discoveredAgent = {
@@ -345,7 +348,8 @@ class SingleAgentClient {
345
348
  * Fetches the agent card and extracts the canonical URL.
346
349
  * Returns the agent config with the canonical URL.
347
350
  */
348
- async ensureCanonicalUrlResolved() {
351
+ async ensureCanonicalUrlResolved(options) {
352
+ (0, abort_2.throwIfAborted)(options?.signal);
349
353
  const needsCanonicalUrl = this.normalizedAgent._needsCanonicalUrl;
350
354
  if (!needsCanonicalUrl) {
351
355
  return this.normalizedAgent;
@@ -358,7 +362,7 @@ class SingleAgentClient {
358
362
  };
359
363
  }
360
364
  // Fetch agent card to get canonical URL
361
- const canonicalUrl = await this.fetchA2ACanonicalUrl(this.normalizedAgent.agent_uri);
365
+ const canonicalUrl = await this.fetchA2ACanonicalUrl(this.normalizedAgent.agent_uri, options);
362
366
  this.canonicalBaseUrl = canonicalUrl;
363
367
  return {
364
368
  ...this.normalizedAgent,
@@ -372,7 +376,7 @@ class SingleAgentClient {
372
376
  * - If the agent card fetch returns 401, throw AuthenticationRequiredError
373
377
  * - Check for OAuth metadata to provide helpful guidance
374
378
  */
375
- async fetchA2ACanonicalUrl(agentUri) {
379
+ async fetchA2ACanonicalUrl(agentUri, readOptions) {
376
380
  const clientModule = require('@a2a-js/sdk/client');
377
381
  const A2AClient = clientModule.A2AClient;
378
382
  // adcp-client#1804 — wrap A2A card discovery in withResponseSizeLimit so
@@ -381,20 +385,22 @@ class SingleAgentClient {
381
385
  // active ALS slot enforces the cap on the wire call. Matches the same
382
386
  // pattern in `getAgentInfo` (closed #1799 via PR #1802).
383
387
  const { withResponseSizeLimit, wrapFetchWithSizeLimit } = await Promise.resolve().then(() => __importStar(require('../protocols/responseSizeLimit')));
384
- const maxResponseBytes = this.config.transport?.maxResponseBytes;
388
+ const transport = readOptions?.transport ?? this.config.transport;
389
+ const maxResponseBytes = transport?.maxResponseBytes;
390
+ const requestTimeoutMs = (0, abort_2.resolveRequestTimeoutMs)(transport?.requestTimeoutMs, abort_2.DEFAULT_REQUEST_TIMEOUT_MS);
385
391
  const sizeLimitedFetch = wrapFetchWithSizeLimit((input, init) => fetch(input, init));
386
392
  const authToken = this.normalizedAgent.auth_token;
387
393
  let got401 = false;
388
- const fetchImpl = async (url, options) => {
394
+ const fetchImpl = async (url, requestInit) => {
389
395
  const headers = {
390
- ...options?.headers,
396
+ ...requestInit?.headers,
391
397
  ...this.normalizedAgent.headers,
392
398
  ...(authToken && {
393
399
  Authorization: `Bearer ${authToken}`,
394
400
  'x-adcp-auth': authToken,
395
401
  }),
396
402
  };
397
- const response = await sizeLimitedFetch(url, { ...options, headers });
403
+ const response = await (0, abort_2.withAbortSignal)([readOptions?.signal, requestInit?.signal], requestTimeoutMs, signal => sizeLimitedFetch(url, { ...requestInit, headers, signal }));
398
404
  // Track 401 errors for later handling
399
405
  if (response.status === 401) {
400
406
  got401 = true;
@@ -481,18 +487,25 @@ class SingleAgentClient {
481
487
  *
482
488
  * Note: This is async and called lazily on first agent interaction
483
489
  */
484
- async discoverMCPEndpoint(providedUri) {
490
+ async discoverMCPEndpoint(providedUri, options) {
491
+ (0, abort_2.throwIfAborted)(options?.signal);
485
492
  const { connectMCPWithFallback } = await Promise.resolve().then(() => __importStar(require('../protocols/mcp')));
486
493
  const authToken = this.agent.auth_token;
487
494
  const agentHeaders = this.agent.headers;
488
495
  const authHeaders = { ...agentHeaders, ...(0, auth_1.createMCPAuthHeaders)(authToken) };
489
496
  const testEndpoint = async (url) => {
490
497
  try {
491
- const client = await connectMCPWithFallback(new URL(url), authHeaders);
498
+ const client = await connectMCPWithFallback(new URL(url), authHeaders, [], 'endpoint discovery', undefined, {
499
+ signal: options?.signal,
500
+ requestTimeoutMs: options?.transport?.requestTimeoutMs ?? this.config.transport?.requestTimeoutMs,
501
+ });
492
502
  await client.close();
493
503
  return { success: true };
494
504
  }
495
505
  catch (error) {
506
+ if ((0, abort_1.isAbortOrTimeoutError)(error)) {
507
+ throw error;
508
+ }
496
509
  if ((0, errors_1.is401Error)(error)) {
497
510
  return { success: false, status: 401, error };
498
511
  }
@@ -1041,6 +1054,7 @@ class SingleAgentClient {
1041
1054
  * Automatically adapts requests for v2 servers and normalizes responses.
1042
1055
  */
1043
1056
  async executeAndHandle(taskType, handlerName, params, inputHandler, options) {
1057
+ (0, abort_2.throwIfAborted)(options?.signal);
1044
1058
  // Normalize params for backwards compatibility before validation
1045
1059
  let normalizedParams = (0, request_normalizer_1.normalizeRequestParams)(taskType, params, {
1046
1060
  skipIdempotencyAutoInject: options?.skipIdempotencyAutoInject,
@@ -1075,17 +1089,17 @@ class SingleAgentClient {
1075
1089
  this.validateRequest(taskType, normalizedParams);
1076
1090
  }
1077
1091
  // Validate required features before sending request
1078
- await this.validateTaskFeatures(taskType);
1092
+ await this.validateTaskFeatures(taskType, options);
1079
1093
  // Guard mutating calls against pre-v3 sellers when opted in.
1080
1094
  if (this.config.requireV3ForMutations && (0, idempotency_1.isMutatingTask)(taskType)) {
1081
- await this.requireSupportedMajor(taskType);
1095
+ await this.requireSupportedMajor(taskType, options);
1082
1096
  }
1083
1097
  // Check for v3 features used against v2 servers - return empty result if unsupported
1084
- const earlyResult = await this.getEarlyResultForUnsupportedFeatures(taskType, normalizedParams);
1098
+ const earlyResult = await this.getEarlyResultForUnsupportedFeatures(taskType, normalizedParams, options);
1085
1099
  if (earlyResult) {
1086
1100
  return (0, match_1.attachMatch)(earlyResult);
1087
1101
  }
1088
- const agent = await this.ensureEndpointDiscovered();
1102
+ const agent = await this.ensureEndpointDiscovered(options);
1089
1103
  // Schema-driven pre-send validation runs on the unadapted v3 shape so
1090
1104
  // wire-format adapters (e.g. adaptGetProductsRequestForV2) don't strip
1091
1105
  // v3-only fields out from under the v3 bundled schema. Skip the entire
@@ -1095,7 +1109,7 @@ class SingleAgentClient {
1095
1109
  this.executor.validateRequest(taskType, normalizedParams);
1096
1110
  }
1097
1111
  // Adapt request for the detected server and AdCP protocol versions.
1098
- const serverVersion = await this.detectServerVersion();
1112
+ const serverVersion = await this.detectServerVersion(options);
1099
1113
  const inputSchemaStripLogs = [];
1100
1114
  const { params: adaptedParams, driftLogs: adaptDriftLogs } = this.adaptRequest(taskType, normalizedParams, serverVersion, inputSchemaStripLogs);
1101
1115
  // Symmetric to the pre-adapter v3 pass above: when the adapter
@@ -1584,13 +1598,13 @@ class SingleAgentClient {
1584
1598
  *
1585
1599
  * @returns TaskResult with empty data if v3 features are unsupported, null to proceed normally
1586
1600
  */
1587
- async getEarlyResultForUnsupportedFeatures(taskType, params) {
1601
+ async getEarlyResultForUnsupportedFeatures(taskType, params, options) {
1588
1602
  // Only check for tasks that have v3-specific features
1589
1603
  if (taskType !== 'get_products') {
1590
1604
  return null;
1591
1605
  }
1592
1606
  // Get capabilities to check what the server supports
1593
- const capabilities = await this.getCapabilities();
1607
+ const capabilities = await this.getCapabilities(options);
1594
1608
  // If server is v3, all features are supported - proceed normally
1595
1609
  if (capabilities.version === 'v3') {
1596
1610
  return null;
@@ -1867,7 +1881,7 @@ class SingleAgentClient {
1867
1881
  * @param options - Task execution options
1868
1882
  */
1869
1883
  async getAdcpCapabilities(params, inputHandler, options) {
1870
- const agent = await this.ensureEndpointDiscovered();
1884
+ const agent = await this.ensureEndpointDiscovered(options);
1871
1885
  this.executor.validateRequest('get_adcp_capabilities', params);
1872
1886
  return this.executor.executeTask(agent, 'get_adcp_capabilities', params, inputHandler, options);
1873
1887
  }
@@ -1996,6 +2010,7 @@ class SingleAgentClient {
1996
2010
  * ```
1997
2011
  */
1998
2012
  async executeTask(taskName, params, inputHandler, options) {
2013
+ (0, abort_2.throwIfAborted)(options?.signal);
1999
2014
  const startTime = Date.now();
2000
2015
  try {
2001
2016
  const normalizedParams = (0, request_normalizer_1.normalizeRequestParams)(taskName, params, {
@@ -2007,11 +2022,11 @@ class SingleAgentClient {
2007
2022
  // (get_products / get_signals). `effectiveOptions` carries disableWebhook
2008
2023
  // so no push_notification_config reaches a seller that can't accept it.
2009
2024
  const { options: effectiveOptions, driftLog: webhookDriftLog } = this.suppressPre31DiscoveryWebhook(taskName, options);
2010
- await this.validateTaskFeatures(taskName);
2025
+ await this.validateTaskFeatures(taskName, options);
2011
2026
  if (this.config.requireV3ForMutations && (0, idempotency_1.isMutatingTask)(taskName)) {
2012
- await this.requireSupportedMajor(taskName);
2027
+ await this.requireSupportedMajor(taskName, options);
2013
2028
  }
2014
- const agent = await this.ensureEndpointDiscovered();
2029
+ const agent = await this.ensureEndpointDiscovered(options);
2015
2030
  // Schema-driven pre-send validation runs on the unadapted v3 shape so
2016
2031
  // wire-format adapters (e.g. adaptGetProductsRequestForV2) don't strip
2017
2032
  // v3-only fields out from under the v3 bundled schema. Skip the entire
@@ -2021,7 +2036,7 @@ class SingleAgentClient {
2021
2036
  this.executor.validateRequest(taskName, normalizedParams);
2022
2037
  }
2023
2038
  // Adapt request for the detected server and AdCP protocol versions.
2024
- const serverVersion = await this.detectServerVersion();
2039
+ const serverVersion = await this.detectServerVersion(options);
2025
2040
  const inputSchemaStripLogs = [];
2026
2041
  const { params: adaptedParams, driftLogs: adaptDriftLogs } = this.adaptRequest(taskName, normalizedParams, serverVersion, inputSchemaStripLogs);
2027
2042
  // Symmetric warn-only post-adapter pass against the v2.5 schema bundle.
@@ -2055,7 +2070,8 @@ class SingleAgentClient {
2055
2070
  if (error instanceof errors_1.AuthenticationRequiredError ||
2056
2071
  error instanceof errors_1.TaskTimeoutError ||
2057
2072
  error instanceof errors_1.VersionUnsupportedError ||
2058
- error instanceof errors_1.FeatureUnsupportedError) {
2073
+ error instanceof errors_1.FeatureUnsupportedError ||
2074
+ (0, abort_1.isAbortOrTimeoutError)(error)) {
2059
2075
  throw error;
2060
2076
  }
2061
2077
  // Unexpected pre-flight errors (e.g. a TypeError from response parsing
@@ -2408,17 +2424,25 @@ class SingleAgentClient {
2408
2424
  * });
2409
2425
  * ```
2410
2426
  */
2411
- async getAgentInfo() {
2427
+ async getAgentInfo(options) {
2412
2428
  // adcp-client#1799 — wrap every wire call in the response-size cap so
2413
2429
  // `transport.maxResponseBytes` extends to discovery / tools-list bodies.
2414
2430
  // `withResponseSizeLimit` is a no-op when no cap is configured.
2415
2431
  const { withResponseSizeLimit } = await Promise.resolve().then(() => __importStar(require('../protocols/responseSizeLimit')));
2416
- const maxResponseBytes = this.config.transport?.maxResponseBytes;
2432
+ (0, abort_2.throwIfAborted)(options?.signal);
2433
+ const transport = options?.transport ?? this.config.transport;
2434
+ const maxResponseBytes = transport?.maxResponseBytes;
2435
+ const requestTimeoutMs = (0, abort_2.resolveRequestTimeoutMs)(transport?.requestTimeoutMs, abort_2.DEFAULT_REQUEST_TIMEOUT_MS);
2436
+ const clientRequestTimeoutMs = (0, abort_2.resolveClientRequestTimeoutMs)(transport?.requestTimeoutMs);
2437
+ const mcpRequestOptions = {
2438
+ ...(options?.signal && { signal: options.signal }),
2439
+ ...(clientRequestTimeoutMs !== undefined && { timeout: clientRequestTimeoutMs }),
2440
+ };
2417
2441
  if (this.normalizedAgent.protocol === 'mcp') {
2418
2442
  // In-process: use the pre-connected client instead of opening a new HTTP connection
2419
2443
  if (this.normalizedAgent._inProcessMcpClient) {
2420
2444
  const mcpClient = this.normalizedAgent._inProcessMcpClient;
2421
- const toolsList = await withResponseSizeLimit(maxResponseBytes, () => mcpClient.listTools());
2445
+ const toolsList = await withResponseSizeLimit(maxResponseBytes, () => mcpClient.listTools(undefined, mcpRequestOptions));
2422
2446
  const tools = toolsList.tools.map(tool => ({
2423
2447
  name: tool.name,
2424
2448
  description: tool.description,
@@ -2434,7 +2458,7 @@ class SingleAgentClient {
2434
2458
  };
2435
2459
  }
2436
2460
  // Discover endpoint if needed
2437
- const agent = await this.ensureEndpointDiscovered();
2461
+ const agent = await this.ensureEndpointDiscovered(options);
2438
2462
  // Use the shared connectMCP path so both static bearer AND saved OAuth
2439
2463
  // tokens work. OAuth takes the refresh-capable authProvider branch.
2440
2464
  // Header-only auth (basic, x-api-key, custom routing) lives on
@@ -2443,6 +2467,12 @@ class SingleAgentClient {
2443
2467
  // SDK doesn't emit a competing `Authorization: Bearer …`.
2444
2468
  const { connectMCP } = await Promise.resolve().then(() => __importStar(require('../protocols/mcp')));
2445
2469
  const connectOptions = { agentUrl: agent.agent_uri };
2470
+ if (options?.signal) {
2471
+ connectOptions.signal = options.signal;
2472
+ }
2473
+ if (transport?.requestTimeoutMs !== undefined) {
2474
+ connectOptions.requestTimeoutMs = transport.requestTimeoutMs;
2475
+ }
2446
2476
  if (this.normalizedAgent.headers && Object.keys(this.normalizedAgent.headers).length > 0) {
2447
2477
  connectOptions.customHeaders = this.normalizedAgent.headers;
2448
2478
  }
@@ -2457,7 +2487,7 @@ class SingleAgentClient {
2457
2487
  }
2458
2488
  const { client: mcpClient } = await connectMCP(connectOptions);
2459
2489
  try {
2460
- const toolsList = await withResponseSizeLimit(maxResponseBytes, () => mcpClient.listTools());
2490
+ const toolsList = await withResponseSizeLimit(maxResponseBytes, () => mcpClient.listTools(undefined, mcpRequestOptions));
2461
2491
  const tools = toolsList.tools.map(tool => ({
2462
2492
  name: tool.name,
2463
2493
  description: tool.description,
@@ -2491,17 +2521,39 @@ class SingleAgentClient {
2491
2521
  // calls native `fetch` directly and ignores `transport.maxResponseBytes`.
2492
2522
  const { wrapFetchWithSizeLimit } = await Promise.resolve().then(() => __importStar(require('../protocols/responseSizeLimit')));
2493
2523
  const authToken = this.normalizedAgent.auth_token;
2524
+ const agentHeaders = this.normalizedAgent.headers ?? {};
2494
2525
  const sizeLimitedFetch = wrapFetchWithSizeLimit((input, init) => fetch(input, init));
2495
- const fetchImpl = authToken
2496
- ? async (url, options) => {
2497
- const headers = {
2498
- ...options?.headers,
2499
- Authorization: `Bearer ${authToken}`,
2500
- 'x-adcp-auth': authToken,
2501
- };
2502
- return sizeLimitedFetch(url, { ...options, headers });
2526
+ const normalizeHeaders = (headers) => {
2527
+ const normalized = {};
2528
+ if (!headers)
2529
+ return normalized;
2530
+ if (headers instanceof Headers) {
2531
+ headers.forEach((value, key) => {
2532
+ normalized[key] = value;
2533
+ });
2534
+ }
2535
+ else if (Array.isArray(headers)) {
2536
+ for (const [key, value] of headers) {
2537
+ normalized[key] = value;
2538
+ }
2539
+ }
2540
+ else {
2541
+ Object.assign(normalized, headers);
2503
2542
  }
2504
- : (url, options) => sizeLimitedFetch(url, options);
2543
+ return normalized;
2544
+ };
2545
+ const buildHeaders = (requestInit) => ({
2546
+ ...normalizeHeaders(requestInit?.headers),
2547
+ ...agentHeaders,
2548
+ ...(authToken && {
2549
+ Authorization: `Bearer ${authToken}`,
2550
+ 'x-adcp-auth': authToken,
2551
+ }),
2552
+ });
2553
+ const fetchImpl = async (url, requestInit) => {
2554
+ const headers = buildHeaders(requestInit);
2555
+ return (0, abort_2.withAbortSignal)([options?.signal, requestInit?.signal], requestTimeoutMs, signal => sizeLimitedFetch(url, { ...requestInit, headers, signal }));
2556
+ };
2505
2557
  const cardUrls = (0, a2a_discovery_1.buildCardUrls)(this.normalizedAgent.agent_uri);
2506
2558
  let client;
2507
2559
  let lastCardError = new Error(`A2A agent card not found at ${cardUrls.join(', ')}`);
@@ -2559,14 +2611,15 @@ class SingleAgentClient {
2559
2611
  * }
2560
2612
  * ```
2561
2613
  */
2562
- async getCapabilities() {
2614
+ async getCapabilities(options) {
2615
+ (0, abort_2.throwIfAborted)(options?.signal);
2563
2616
  // Return cached if available
2564
2617
  if (this.cachedCapabilities) {
2565
2618
  this.maybeWarnV2Sunset(this.cachedCapabilities);
2566
2619
  return this.cachedCapabilities;
2567
2620
  }
2568
2621
  // First get tool list to support both detection methods
2569
- const agentInfo = await this.getAgentInfo();
2622
+ const agentInfo = await this.getAgentInfo(options);
2570
2623
  const tools = agentInfo.tools.map(t => ({
2571
2624
  name: t.name,
2572
2625
  description: t.description,
@@ -2585,8 +2638,15 @@ class SingleAgentClient {
2585
2638
  // because normalizeAgentConfig returns early when _inProcessMcpClient is set). The
2586
2639
  // executor then hits ProtocolClient.callTool which reads _inProcessMcpClient directly,
2587
2640
  // so the sentinel adcp-in-process:// URI never reaches validateAgentUrl.
2588
- const agent = await this.ensureEndpointDiscovered();
2589
- const result = await this.executor.executeTask(agent, 'get_adcp_capabilities', {}, undefined);
2641
+ const agent = await this.ensureEndpointDiscovered(options);
2642
+ const result = await this.executor.executeTask(agent, 'get_adcp_capabilities', {}, undefined, options);
2643
+ (0, abort_2.throwIfAborted)(options?.signal);
2644
+ const requestTimeoutMs = (0, abort_2.resolveRequestTimeoutMs)(options?.transport?.requestTimeoutMs ?? this.config.transport?.requestTimeoutMs);
2645
+ if (!result.success &&
2646
+ requestTimeoutMs !== undefined &&
2647
+ /\b(requesttimeout|timeout|timed out)\b/i.test(result.error ?? '')) {
2648
+ throw (0, abort_2.createTimeoutError)(requestTimeoutMs);
2649
+ }
2590
2650
  if (result.success && result.data) {
2591
2651
  this.cachedCapabilities = (0, capabilities_1.augmentCapabilitiesFromTools)((0, capabilities_1.parseCapabilitiesResponse)(result.data), tools);
2592
2652
  this.maybeWarnV2Sunset(this.cachedCapabilities);
@@ -2641,7 +2701,7 @@ class SingleAgentClient {
2641
2701
  `since the agent has the v3-only discovery tool. ` +
2642
2702
  `This client routes to v3 adapters, but calls reading capability details ` +
2643
2703
  `(idempotency TTL, supported_versions, feature flags) will fail until the agent ` +
2644
- `operator fixes the capabilities endpoint at ${this.agent.agent_uri}.`, {
2704
+ `operator fixes the capabilities endpoint.`, {
2645
2705
  success: result.success,
2646
2706
  hasError: !!result.error,
2647
2707
  hasData: !!result.data,
@@ -2651,15 +2711,16 @@ class SingleAgentClient {
2651
2711
  // Re-throw errors that indicate real infrastructure problems —
2652
2712
  // only fall through for tool-execution failures (the agent
2653
2713
  // advertises get_adcp_capabilities but can't actually serve it).
2654
- if (error instanceof errors_1.AuthenticationRequiredError || error instanceof errors_1.TaskTimeoutError) {
2714
+ if (error instanceof errors_1.AuthenticationRequiredError ||
2715
+ error instanceof errors_1.TaskTimeoutError ||
2716
+ (0, abort_1.isAbortOrTimeoutError)(error)) {
2655
2717
  throw error;
2656
2718
  }
2657
2719
  console.warn(`[AdCP] Agent "${this.agent.id}" advertises get_adcp_capabilities but the call ` +
2658
2720
  `threw — treating as v3 (synthetic) since the agent has the v3-only discovery tool. ` +
2659
2721
  `This client routes to v3 adapters, but calls reading capability details ` +
2660
2722
  `(idempotency TTL, supported_versions, feature flags) will fail until the agent ` +
2661
- `operator fixes the capabilities endpoint at ${this.agent.agent_uri}. ` +
2662
- `Error: ${error instanceof Error ? error.message : String(error)}`);
2723
+ `operator fixes the capabilities endpoint.`);
2663
2724
  }
2664
2725
  // Synthesize v3 capabilities from the tool list. Reached only when
2665
2726
  // the executor returned non-v3-shaped data, OR threw a non-auth
@@ -2750,8 +2811,8 @@ class SingleAgentClient {
2750
2811
  *
2751
2812
  * @returns 'v2' or 'v3' based on server capabilities
2752
2813
  */
2753
- async detectServerVersion() {
2754
- const capabilities = await this.getCapabilities();
2814
+ async detectServerVersion(options) {
2815
+ const capabilities = await this.getCapabilities(options);
2755
2816
  return capabilities.version;
2756
2817
  }
2757
2818
  /**
@@ -2848,13 +2909,17 @@ class SingleAgentClient {
2848
2909
  *
2849
2910
  * Skipped when validateFeatures is false or the task has no feature requirements.
2850
2911
  */
2851
- async validateTaskFeatures(taskName) {
2912
+ async validateTaskFeatures(taskName, options) {
2852
2913
  if (this.config.validateFeatures === false)
2853
2914
  return;
2854
2915
  const requiredFeatures = capabilities_1.TASK_FEATURE_MAP[taskName];
2855
2916
  if (!requiredFeatures || requiredFeatures.length === 0)
2856
2917
  return;
2857
- await this.require(...requiredFeatures);
2918
+ const capabilities = await this.getCapabilities(options);
2919
+ const missing = requiredFeatures.filter(f => !(0, capabilities_1.resolveFeature)(capabilities, f));
2920
+ if (missing.length > 0) {
2921
+ throw new errors_1.FeatureUnsupportedError(missing, (0, capabilities_1.listDeclaredFeatures)(capabilities), this.agent.agent_uri);
2922
+ }
2858
2923
  }
2859
2924
  /**
2860
2925
  * Fail version-incompatible request shapes before schema validation.
@@ -2968,10 +3033,10 @@ class SingleAgentClient {
2968
3033
  *
2969
3034
  * Throws `VersionUnsupportedError` with the specific reason on failure.
2970
3035
  */
2971
- async requireSupportedMajor(taskType = 'request') {
3036
+ async requireSupportedMajor(taskType = 'request', options) {
2972
3037
  if (this.isV2Allowed())
2973
3038
  return;
2974
- const capabilities = await this.getCapabilities();
3039
+ const capabilities = await this.getCapabilities(options);
2975
3040
  // Synthetic capabilities — no authoritative `get_adcp_capabilities`
2976
3041
  // response, so the version + idempotency-TTL fields couldn't be read.
2977
3042
  // Route as the synthesized version (v2 when the v3 discovery tool is