@vectros-ai/mcp-server 0.18.2 → 0.19.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/dist/cli.js CHANGED
@@ -26,7 +26,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  // src/server.ts
27
27
  var import_server = require("@modelcontextprotocol/sdk/server/index.js");
28
28
 
29
- // ../../node_modules/@vectros-ai/sdk/dist/index.mjs
29
+ // node_modules/@vectros-ai/sdk/dist/index.mjs
30
30
  var __defProp2 = Object.defineProperty;
31
31
  var __export = (target, all) => {
32
32
  for (var name in all)
@@ -47,6 +47,7 @@ __export(api_exports, {
47
47
  ContentTooLargeError: () => ContentTooLargeError,
48
48
  DocumentAskRequest: () => DocumentAskRequest,
49
49
  DocumentContextEvent: () => DocumentContextEvent,
50
+ DocumentExtraction: () => DocumentExtraction,
50
51
  DocumentLookupRequest: () => DocumentLookupRequest,
51
52
  DocumentPatchRequest: () => DocumentPatchRequest,
52
53
  DocumentRequest: () => DocumentRequest,
@@ -99,6 +100,7 @@ __export(api_exports, {
99
100
  UserExistsResponse: () => UserExistsResponse,
100
101
  UserRequest: () => UserRequest,
101
102
  UserResponse: () => UserResponse,
103
+ agents: () => agents_exports,
102
104
  auth: () => auth_exports,
103
105
  compliance: () => compliance_exports,
104
106
  documents: () => documents_exports,
@@ -364,6 +366,7 @@ var UnprocessableEntityError = class extends VectrosError {
364
366
  this.name = this.constructor.name;
365
367
  }
366
368
  };
369
+ var agents_exports = {};
367
370
  var auth_exports = {};
368
371
  var ErasureRequest;
369
372
  ((ErasureRequest2) => {
@@ -568,6 +571,18 @@ var DocumentContextEvent;
568
571
  DocumentContext: "document_context"
569
572
  };
570
573
  })(DocumentContextEvent || (DocumentContextEvent = {}));
574
+ var DocumentExtraction;
575
+ ((DocumentExtraction2) => {
576
+ DocumentExtraction2.Outcome = {
577
+ Ok: "OK",
578
+ Truncated: "TRUNCATED",
579
+ NoText: "NO_TEXT",
580
+ Encrypted: "ENCRYPTED",
581
+ Unsupported: "UNSUPPORTED",
582
+ TooLarge: "TOO_LARGE",
583
+ Unreadable: "UNREADABLE"
584
+ };
585
+ })(DocumentExtraction || (DocumentExtraction = {}));
571
586
  var DocumentRequest;
572
587
  ((DocumentRequest2) => {
573
588
  DocumentRequest2.IndexMode = {
@@ -1873,13 +1888,13 @@ function joinPathSegments(left, right) {
1873
1888
  }
1874
1889
  return `${left}/${right}`;
1875
1890
  }
1876
- function trimSlashes(str) {
1877
- if (!str) return str;
1891
+ function trimSlashes(str2) {
1892
+ if (!str2) return str2;
1878
1893
  let start = 0;
1879
- let end = str.length;
1880
- if (str.startsWith("/")) start = 1;
1881
- if (str.endsWith("/")) end = str.length - 1;
1882
- return start === 0 && end === str.length ? str : str.slice(start, end);
1894
+ let end = str2.length;
1895
+ if (str2.startsWith("/")) start = 1;
1896
+ if (str2.endsWith("/")) end = str2.length - 1;
1897
+ return start === 0 && end === str2.length ? str2 : str2.slice(start, end);
1883
1898
  }
1884
1899
  var Supplier = {
1885
1900
  get: async (supplier) => {
@@ -2394,48 +2409,675 @@ function normalizeClientOptionsWithAuth(options) {
2394
2409
  normalized.authProvider = options.auth;
2395
2410
  return normalized;
2396
2411
  }
2397
- Object.assign(normalized, options.auth);
2398
- }
2399
- const normalizedWithNoOpAuthProvider = withNoOpAuthProvider(normalized);
2400
- normalized.authProvider ?? (normalized.authProvider = new BearerAuthProvider(normalizedWithNoOpAuthProvider));
2401
- return normalized;
2402
- }
2403
- function withNoOpAuthProvider(options) {
2404
- return {
2405
- ...options,
2406
- authProvider: new NoOpAuthProvider()
2407
- };
2408
- }
2409
- function handleNonStatusCodeError(error, rawResponse, method, path2) {
2410
- switch (error.reason) {
2411
- case "non-json":
2412
- throw new VectrosError({
2413
- statusCode: error.statusCode,
2414
- body: error.rawBody,
2415
- rawResponse
2416
- });
2417
- case "body-is-null":
2418
- throw new VectrosError({
2419
- statusCode: error.statusCode,
2420
- rawResponse
2421
- });
2422
- case "timeout":
2423
- throw new VectrosTimeoutError(`Timeout exceeded when calling ${method} ${path2}.`, {
2424
- cause: error.cause
2425
- });
2426
- case "unknown":
2427
- throw new VectrosError({
2428
- message: error.errorMessage,
2429
- rawResponse,
2430
- cause: error.cause
2431
- });
2432
- default:
2433
- throw new VectrosError({
2434
- message: "Unknown error",
2435
- rawResponse
2436
- });
2412
+ Object.assign(normalized, options.auth);
2413
+ }
2414
+ const normalizedWithNoOpAuthProvider = withNoOpAuthProvider(normalized);
2415
+ normalized.authProvider ?? (normalized.authProvider = new BearerAuthProvider(normalizedWithNoOpAuthProvider));
2416
+ return normalized;
2417
+ }
2418
+ function withNoOpAuthProvider(options) {
2419
+ return {
2420
+ ...options,
2421
+ authProvider: new NoOpAuthProvider()
2422
+ };
2423
+ }
2424
+ function handleNonStatusCodeError(error, rawResponse, method, path2) {
2425
+ switch (error.reason) {
2426
+ case "non-json":
2427
+ throw new VectrosError({
2428
+ statusCode: error.statusCode,
2429
+ body: error.rawBody,
2430
+ rawResponse
2431
+ });
2432
+ case "body-is-null":
2433
+ throw new VectrosError({
2434
+ statusCode: error.statusCode,
2435
+ rawResponse
2436
+ });
2437
+ case "timeout":
2438
+ throw new VectrosTimeoutError(`Timeout exceeded when calling ${method} ${path2}.`, {
2439
+ cause: error.cause
2440
+ });
2441
+ case "unknown":
2442
+ throw new VectrosError({
2443
+ message: error.errorMessage,
2444
+ rawResponse,
2445
+ cause: error.cause
2446
+ });
2447
+ default:
2448
+ throw new VectrosError({
2449
+ message: "Unknown error",
2450
+ rawResponse
2451
+ });
2452
+ }
2453
+ }
2454
+ var AgentsClient = class {
2455
+ constructor(options) {
2456
+ this._options = normalizeClientOptionsWithAuth(options);
2457
+ }
2458
+ /**
2459
+ * Returns a page of the agents in the app context, newest first, each at its latest version. A caller holding `runs:c` but not `agents:r` gets only each agent's `id`, `name`, `description`, `latestVersion` and `status`. Retired and purged agents are left out unless `includeRetired=true`. Requires `agents:r` or `runs:c`.
2460
+ *
2461
+ * @param {Vectros.ListAgentsRequest} request
2462
+ * @param {AgentsClient.RequestOptions} requestOptions - Request-specific configuration.
2463
+ *
2464
+ * @throws {@link Vectros.ForbiddenError}
2465
+ *
2466
+ * @example
2467
+ * await client.agents.listAgents()
2468
+ */
2469
+ listAgents(request = {}, requestOptions) {
2470
+ return HttpResponsePromise.fromPromise(this.__listAgents(request, requestOptions));
2471
+ }
2472
+ async __listAgents(request = {}, requestOptions) {
2473
+ const { contextId, includeRetired, startFrom, limit } = request;
2474
+ const _queryParams = {
2475
+ contextId,
2476
+ includeRetired,
2477
+ startFrom,
2478
+ limit
2479
+ };
2480
+ const _authRequest = await this._options.authProvider.getAuthRequest();
2481
+ const _headers = mergeHeaders(
2482
+ _authRequest.headers,
2483
+ this._options?.headers,
2484
+ requestOptions?.headers
2485
+ );
2486
+ const _response = await fetcher({
2487
+ url: url_exports.join(
2488
+ await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
2489
+ "v1/agents"
2490
+ ),
2491
+ method: "GET",
2492
+ headers: _headers,
2493
+ queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
2494
+ timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
2495
+ maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
2496
+ abortSignal: requestOptions?.abortSignal,
2497
+ fetchFn: this._options?.fetch,
2498
+ logging: this._options.logging
2499
+ });
2500
+ if (_response.ok) {
2501
+ return { data: _response.body, rawResponse: _response.rawResponse };
2502
+ }
2503
+ if (_response.error.reason === "status-code") {
2504
+ switch (_response.error.statusCode) {
2505
+ case 403:
2506
+ throw new ForbiddenError(_response.error.body, _response.rawResponse);
2507
+ default:
2508
+ throw new VectrosError({
2509
+ statusCode: _response.error.statusCode,
2510
+ body: _response.error.body,
2511
+ rawResponse: _response.rawResponse
2512
+ });
2513
+ }
2514
+ }
2515
+ return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/agents");
2516
+ }
2517
+ /**
2518
+ * Stores a new agent at version 1, or returns the existing agent of this name unchanged. With `?upsert=true` an existing agent whose definition differs gets a new version instead. Requires the `agents:c` scope (also `agents:u` with `?upsert=true`).
2519
+ *
2520
+ * @param {Vectros.CreateAgentRequest} request
2521
+ * @param {AgentsClient.RequestOptions} requestOptions - Request-specific configuration.
2522
+ *
2523
+ * @throws {@link Vectros.BadRequestError}
2524
+ * @throws {@link Vectros.ForbiddenError}
2525
+ * @throws {@link Vectros.ConflictError}
2526
+ * @throws {@link Vectros.TooManyRequestsError}
2527
+ *
2528
+ * @example
2529
+ * await client.agents.createAgent({
2530
+ * body: {
2531
+ * model: "claude-sonnet-5-5"
2532
+ * }
2533
+ * })
2534
+ */
2535
+ createAgent(request, requestOptions) {
2536
+ return HttpResponsePromise.fromPromise(this.__createAgent(request, requestOptions));
2537
+ }
2538
+ async __createAgent(request, requestOptions) {
2539
+ const { upsert, contextId, body: _body } = request;
2540
+ const _queryParams = {
2541
+ upsert,
2542
+ contextId
2543
+ };
2544
+ const _authRequest = await this._options.authProvider.getAuthRequest();
2545
+ const _headers = mergeHeaders(
2546
+ _authRequest.headers,
2547
+ this._options?.headers,
2548
+ requestOptions?.headers
2549
+ );
2550
+ const _response = await fetcher({
2551
+ url: url_exports.join(
2552
+ await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
2553
+ "v1/agents"
2554
+ ),
2555
+ method: "POST",
2556
+ headers: _headers,
2557
+ contentType: "application/json",
2558
+ queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
2559
+ requestType: "json",
2560
+ body: _body,
2561
+ timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
2562
+ maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
2563
+ abortSignal: requestOptions?.abortSignal,
2564
+ fetchFn: this._options?.fetch,
2565
+ logging: this._options.logging
2566
+ });
2567
+ if (_response.ok) {
2568
+ return { data: _response.body, rawResponse: _response.rawResponse };
2569
+ }
2570
+ if (_response.error.reason === "status-code") {
2571
+ switch (_response.error.statusCode) {
2572
+ case 400:
2573
+ throw new BadRequestError(_response.error.body, _response.rawResponse);
2574
+ case 403:
2575
+ throw new ForbiddenError(_response.error.body, _response.rawResponse);
2576
+ case 409:
2577
+ throw new ConflictError(_response.error.body, _response.rawResponse);
2578
+ case 429:
2579
+ throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
2580
+ default:
2581
+ throw new VectrosError({
2582
+ statusCode: _response.error.statusCode,
2583
+ body: _response.error.body,
2584
+ rawResponse: _response.rawResponse
2585
+ });
2586
+ }
2587
+ }
2588
+ return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/agents");
2589
+ }
2590
+ /**
2591
+ * Returns the agent at its latest version, or at `version`. Requires the `agents:r` scope.
2592
+ *
2593
+ * @param {Vectros.GetAgentRequest} request
2594
+ * @param {AgentsClient.RequestOptions} requestOptions - Request-specific configuration.
2595
+ *
2596
+ * @throws {@link Vectros.ForbiddenError}
2597
+ * @throws {@link Vectros.NotFoundError}
2598
+ *
2599
+ * @example
2600
+ * await client.agents.getAgent({
2601
+ * id: "id"
2602
+ * })
2603
+ */
2604
+ getAgent(request, requestOptions) {
2605
+ return HttpResponsePromise.fromPromise(this.__getAgent(request, requestOptions));
2606
+ }
2607
+ async __getAgent(request, requestOptions) {
2608
+ const { id, contextId, version } = request;
2609
+ const _queryParams = {
2610
+ contextId,
2611
+ version
2612
+ };
2613
+ const _authRequest = await this._options.authProvider.getAuthRequest();
2614
+ const _headers = mergeHeaders(
2615
+ _authRequest.headers,
2616
+ this._options?.headers,
2617
+ requestOptions?.headers
2618
+ );
2619
+ const _response = await fetcher({
2620
+ url: url_exports.join(
2621
+ await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
2622
+ `v1/agents/${url_exports.encodePathParam(id)}`
2623
+ ),
2624
+ method: "GET",
2625
+ headers: _headers,
2626
+ queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
2627
+ timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
2628
+ maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
2629
+ abortSignal: requestOptions?.abortSignal,
2630
+ fetchFn: this._options?.fetch,
2631
+ logging: this._options.logging
2632
+ });
2633
+ if (_response.ok) {
2634
+ return { data: _response.body, rawResponse: _response.rawResponse };
2635
+ }
2636
+ if (_response.error.reason === "status-code") {
2637
+ switch (_response.error.statusCode) {
2638
+ case 403:
2639
+ throw new ForbiddenError(_response.error.body, _response.rawResponse);
2640
+ case 404:
2641
+ throw new NotFoundError(_response.error.body, _response.rawResponse);
2642
+ default:
2643
+ throw new VectrosError({
2644
+ statusCode: _response.error.statusCode,
2645
+ body: _response.error.body,
2646
+ rawResponse: _response.rawResponse
2647
+ });
2648
+ }
2649
+ }
2650
+ return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/agents/{id}");
2651
+ }
2652
+ /**
2653
+ * Stores the body as the agent's next version. Earlier versions never change. Every optional field you leave out takes its default; `model` is required. With `?restore=true` a retired agent becomes active again with this version. Requires the `agents:u` scope.
2654
+ *
2655
+ * @param {Vectros.UpdateAgentRequest} request
2656
+ * @param {AgentsClient.RequestOptions} requestOptions - Request-specific configuration.
2657
+ *
2658
+ * @throws {@link Vectros.BadRequestError}
2659
+ * @throws {@link Vectros.ForbiddenError}
2660
+ * @throws {@link Vectros.NotFoundError}
2661
+ * @throws {@link Vectros.ConflictError}
2662
+ * @throws {@link Vectros.TooManyRequestsError}
2663
+ *
2664
+ * @example
2665
+ * await client.agents.updateAgent({
2666
+ * id: "id",
2667
+ * body: {
2668
+ * model: "claude-sonnet-5-5"
2669
+ * }
2670
+ * })
2671
+ */
2672
+ updateAgent(request, requestOptions) {
2673
+ return HttpResponsePromise.fromPromise(this.__updateAgent(request, requestOptions));
2674
+ }
2675
+ async __updateAgent(request, requestOptions) {
2676
+ const { id, restore, contextId, body: _body } = request;
2677
+ const _queryParams = {
2678
+ restore,
2679
+ contextId
2680
+ };
2681
+ const _authRequest = await this._options.authProvider.getAuthRequest();
2682
+ const _headers = mergeHeaders(
2683
+ _authRequest.headers,
2684
+ this._options?.headers,
2685
+ requestOptions?.headers
2686
+ );
2687
+ const _response = await fetcher({
2688
+ url: url_exports.join(
2689
+ await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
2690
+ `v1/agents/${url_exports.encodePathParam(id)}`
2691
+ ),
2692
+ method: "PUT",
2693
+ headers: _headers,
2694
+ contentType: "application/json",
2695
+ queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
2696
+ requestType: "json",
2697
+ body: _body,
2698
+ timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
2699
+ maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
2700
+ abortSignal: requestOptions?.abortSignal,
2701
+ fetchFn: this._options?.fetch,
2702
+ logging: this._options.logging
2703
+ });
2704
+ if (_response.ok) {
2705
+ return { data: _response.body, rawResponse: _response.rawResponse };
2706
+ }
2707
+ if (_response.error.reason === "status-code") {
2708
+ switch (_response.error.statusCode) {
2709
+ case 400:
2710
+ throw new BadRequestError(_response.error.body, _response.rawResponse);
2711
+ case 403:
2712
+ throw new ForbiddenError(_response.error.body, _response.rawResponse);
2713
+ case 404:
2714
+ throw new NotFoundError(_response.error.body, _response.rawResponse);
2715
+ case 409:
2716
+ throw new ConflictError(_response.error.body, _response.rawResponse);
2717
+ case 429:
2718
+ throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
2719
+ default:
2720
+ throw new VectrosError({
2721
+ statusCode: _response.error.statusCode,
2722
+ body: _response.error.body,
2723
+ rawResponse: _response.rawResponse
2724
+ });
2725
+ }
2726
+ }
2727
+ return handleNonStatusCodeError(_response.error, _response.rawResponse, "PUT", "/v1/agents/{id}");
2728
+ }
2729
+ /**
2730
+ * Retires the agent: its versions stay readable, it leaves the default listing, and it can be restored. With `?purge=true` a retired agent's content (every version's prompt, description, tools, model, limits and budget) is erased, leaving its id, name, version numbers and timestamps; its change history keeps only a one-way hash of the prompt, description and tools. If the agent is restored while a purge is running, the purge stops (409) and versions it already erased stay erased; purge it again after retiring it. With `?purge=true&version=N` one version that is not the latest is erased. The name of a purged agent stays reserved. Requires the `agents:d` scope.
2731
+ *
2732
+ * @param {Vectros.DeleteAgentRequest} request
2733
+ * @param {AgentsClient.RequestOptions} requestOptions - Request-specific configuration.
2734
+ *
2735
+ * @throws {@link Vectros.BadRequestError}
2736
+ * @throws {@link Vectros.ForbiddenError}
2737
+ * @throws {@link Vectros.NotFoundError}
2738
+ * @throws {@link Vectros.ConflictError}
2739
+ * @throws {@link Vectros.TooManyRequestsError}
2740
+ *
2741
+ * @example
2742
+ * await client.agents.deleteAgent({
2743
+ * id: "id"
2744
+ * })
2745
+ */
2746
+ deleteAgent(request, requestOptions) {
2747
+ return HttpResponsePromise.fromPromise(this.__deleteAgent(request, requestOptions));
2748
+ }
2749
+ async __deleteAgent(request, requestOptions) {
2750
+ const { id, purge, version, contextId } = request;
2751
+ const _queryParams = {
2752
+ purge,
2753
+ version,
2754
+ contextId
2755
+ };
2756
+ const _authRequest = await this._options.authProvider.getAuthRequest();
2757
+ const _headers = mergeHeaders(
2758
+ _authRequest.headers,
2759
+ this._options?.headers,
2760
+ requestOptions?.headers
2761
+ );
2762
+ const _response = await fetcher({
2763
+ url: url_exports.join(
2764
+ await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
2765
+ `v1/agents/${url_exports.encodePathParam(id)}`
2766
+ ),
2767
+ method: "DELETE",
2768
+ headers: _headers,
2769
+ queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
2770
+ timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
2771
+ maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
2772
+ abortSignal: requestOptions?.abortSignal,
2773
+ fetchFn: this._options?.fetch,
2774
+ logging: this._options.logging
2775
+ });
2776
+ if (_response.ok) {
2777
+ return { data: _response.body, rawResponse: _response.rawResponse };
2778
+ }
2779
+ if (_response.error.reason === "status-code") {
2780
+ switch (_response.error.statusCode) {
2781
+ case 400:
2782
+ throw new BadRequestError(_response.error.body, _response.rawResponse);
2783
+ case 403:
2784
+ throw new ForbiddenError(_response.error.body, _response.rawResponse);
2785
+ case 404:
2786
+ throw new NotFoundError(_response.error.body, _response.rawResponse);
2787
+ case 409:
2788
+ throw new ConflictError(_response.error.body, _response.rawResponse);
2789
+ case 429:
2790
+ throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
2791
+ default:
2792
+ throw new VectrosError({
2793
+ statusCode: _response.error.statusCode,
2794
+ body: _response.error.body,
2795
+ rawResponse: _response.rawResponse
2796
+ });
2797
+ }
2798
+ }
2799
+ return handleNonStatusCodeError(_response.error, _response.rawResponse, "DELETE", "/v1/agents/{id}");
2800
+ }
2801
+ /**
2802
+ * Returns a page of the agent's versions, newest first: who wrote each and when, and whether it was purged. With `includeContent=true` each entry carries its full definition. Requires the `agents:r` scope.
2803
+ *
2804
+ * @param {Vectros.ListAgentVersionsRequest} request
2805
+ * @param {AgentsClient.RequestOptions} requestOptions - Request-specific configuration.
2806
+ *
2807
+ * @throws {@link Vectros.ForbiddenError}
2808
+ * @throws {@link Vectros.NotFoundError}
2809
+ *
2810
+ * @example
2811
+ * await client.agents.listAgentVersions({
2812
+ * id: "id"
2813
+ * })
2814
+ */
2815
+ listAgentVersions(request, requestOptions) {
2816
+ return HttpResponsePromise.fromPromise(this.__listAgentVersions(request, requestOptions));
2817
+ }
2818
+ async __listAgentVersions(request, requestOptions) {
2819
+ const { id, contextId, includeContent, startFrom, limit } = request;
2820
+ const _queryParams = {
2821
+ contextId,
2822
+ includeContent,
2823
+ startFrom,
2824
+ limit
2825
+ };
2826
+ const _authRequest = await this._options.authProvider.getAuthRequest();
2827
+ const _headers = mergeHeaders(
2828
+ _authRequest.headers,
2829
+ this._options?.headers,
2830
+ requestOptions?.headers
2831
+ );
2832
+ const _response = await fetcher({
2833
+ url: url_exports.join(
2834
+ await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
2835
+ `v1/agents/${url_exports.encodePathParam(id)}/versions`
2836
+ ),
2837
+ method: "GET",
2838
+ headers: _headers,
2839
+ queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
2840
+ timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
2841
+ maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
2842
+ abortSignal: requestOptions?.abortSignal,
2843
+ fetchFn: this._options?.fetch,
2844
+ logging: this._options.logging
2845
+ });
2846
+ if (_response.ok) {
2847
+ return { data: _response.body, rawResponse: _response.rawResponse };
2848
+ }
2849
+ if (_response.error.reason === "status-code") {
2850
+ switch (_response.error.statusCode) {
2851
+ case 403:
2852
+ throw new ForbiddenError(_response.error.body, _response.rawResponse);
2853
+ case 404:
2854
+ throw new NotFoundError(_response.error.body, _response.rawResponse);
2855
+ default:
2856
+ throw new VectrosError({
2857
+ statusCode: _response.error.statusCode,
2858
+ body: _response.error.body,
2859
+ rawResponse: _response.rawResponse
2860
+ });
2861
+ }
2862
+ }
2863
+ return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/agents/{id}/versions");
2864
+ }
2865
+ /**
2866
+ * Stops a run. The answer is `202` with the run still `RUNNING`: read it with `GET /v1/runs/{id}` to see it end. A model call in progress is cut within a few seconds; a tool call in progress is first allowed to finish, for up to about 30 seconds, so its change is recorded and billed, and the run stops as soon as it has. The run then ends `CANCELLED` with `errorCode` `CANCELLED_BY_CALLER`, unless it had already completed, in which case it stays `COMPLETED`. Its reservation is settled once, like any run's: a model call in progress when it stopped is charged up to its maximum. A run that has ended (or that had not started, which this cancel ends) answers `200` with its final state, so a cancel can always be retried. A run can be cancelled by the credential that started it (for a token bound to a user, by that user) and by your root key. Requires the `runs:c` scope; with `runs:r` as well the answer is the whole run, otherwise only its `id`, `status`, `terminal`, `reason` and `errorCode`. Takes no body.
2867
+ *
2868
+ * @param {Vectros.CancelRunRequest} request
2869
+ * @param {AgentsClient.RequestOptions} requestOptions - Request-specific configuration.
2870
+ *
2871
+ * @throws {@link Vectros.BadRequestError}
2872
+ * @throws {@link Vectros.UnauthorizedError}
2873
+ * @throws {@link Vectros.ForbiddenError}
2874
+ * @throws {@link Vectros.NotFoundError}
2875
+ * @throws {@link Vectros.TooManyRequestsError}
2876
+ *
2877
+ * @example
2878
+ * await client.agents.cancelRun({
2879
+ * id: "id"
2880
+ * })
2881
+ */
2882
+ cancelRun(request, requestOptions) {
2883
+ return HttpResponsePromise.fromPromise(this.__cancelRun(request, requestOptions));
2884
+ }
2885
+ async __cancelRun(request, requestOptions) {
2886
+ const { id, contextId } = request;
2887
+ const _queryParams = {
2888
+ contextId
2889
+ };
2890
+ const _authRequest = await this._options.authProvider.getAuthRequest();
2891
+ const _headers = mergeHeaders(
2892
+ _authRequest.headers,
2893
+ this._options?.headers,
2894
+ requestOptions?.headers
2895
+ );
2896
+ const _response = await fetcher({
2897
+ url: url_exports.join(
2898
+ await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
2899
+ `v1/runs/${url_exports.encodePathParam(id)}/cancel`
2900
+ ),
2901
+ method: "POST",
2902
+ headers: _headers,
2903
+ queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
2904
+ timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
2905
+ maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
2906
+ abortSignal: requestOptions?.abortSignal,
2907
+ fetchFn: this._options?.fetch,
2908
+ logging: this._options.logging
2909
+ });
2910
+ if (_response.ok) {
2911
+ return { data: _response.body, rawResponse: _response.rawResponse };
2912
+ }
2913
+ if (_response.error.reason === "status-code") {
2914
+ switch (_response.error.statusCode) {
2915
+ case 400:
2916
+ throw new BadRequestError(_response.error.body, _response.rawResponse);
2917
+ case 401:
2918
+ throw new UnauthorizedError(_response.error.body, _response.rawResponse);
2919
+ case 403:
2920
+ throw new ForbiddenError(_response.error.body, _response.rawResponse);
2921
+ case 404:
2922
+ throw new NotFoundError(_response.error.body, _response.rawResponse);
2923
+ case 429:
2924
+ throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
2925
+ default:
2926
+ throw new VectrosError({
2927
+ statusCode: _response.error.statusCode,
2928
+ body: _response.error.body,
2929
+ rawResponse: _response.rawResponse
2930
+ });
2931
+ }
2932
+ }
2933
+ return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/runs/{id}/cancel");
2934
+ }
2935
+ /**
2936
+ * Returns the status and metadata of one run: the agent version that ran, how it ended, its tool calls (never their arguments or results) and what it was charged. It never returns text: the answer is delivered only in the run's stream. A run is visible to the credential that started it (for a token bound to a user, to that user) and to your root key, and is kept for 30 days after it ends. Requires the `runs:r` scope.
2937
+ *
2938
+ * @param {Vectros.GetRunRequest} request
2939
+ * @param {AgentsClient.RequestOptions} requestOptions - Request-specific configuration.
2940
+ *
2941
+ * @throws {@link Vectros.BadRequestError}
2942
+ * @throws {@link Vectros.UnauthorizedError}
2943
+ * @throws {@link Vectros.ForbiddenError}
2944
+ * @throws {@link Vectros.NotFoundError}
2945
+ *
2946
+ * @example
2947
+ * await client.agents.getRun({
2948
+ * id: "id"
2949
+ * })
2950
+ */
2951
+ getRun(request, requestOptions) {
2952
+ return HttpResponsePromise.fromPromise(this.__getRun(request, requestOptions));
2953
+ }
2954
+ async __getRun(request, requestOptions) {
2955
+ const { id, contextId } = request;
2956
+ const _queryParams = {
2957
+ contextId
2958
+ };
2959
+ const _authRequest = await this._options.authProvider.getAuthRequest();
2960
+ const _headers = mergeHeaders(
2961
+ _authRequest.headers,
2962
+ this._options?.headers,
2963
+ requestOptions?.headers
2964
+ );
2965
+ const _response = await fetcher({
2966
+ url: url_exports.join(
2967
+ await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
2968
+ `v1/runs/${url_exports.encodePathParam(id)}`
2969
+ ),
2970
+ method: "GET",
2971
+ headers: _headers,
2972
+ queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
2973
+ timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
2974
+ maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
2975
+ abortSignal: requestOptions?.abortSignal,
2976
+ fetchFn: this._options?.fetch,
2977
+ logging: this._options.logging
2978
+ });
2979
+ if (_response.ok) {
2980
+ return { data: _response.body, rawResponse: _response.rawResponse };
2981
+ }
2982
+ if (_response.error.reason === "status-code") {
2983
+ switch (_response.error.statusCode) {
2984
+ case 400:
2985
+ throw new BadRequestError(_response.error.body, _response.rawResponse);
2986
+ case 401:
2987
+ throw new UnauthorizedError(_response.error.body, _response.rawResponse);
2988
+ case 403:
2989
+ throw new ForbiddenError(_response.error.body, _response.rawResponse);
2990
+ case 404:
2991
+ throw new NotFoundError(_response.error.body, _response.rawResponse);
2992
+ default:
2993
+ throw new VectrosError({
2994
+ statusCode: _response.error.statusCode,
2995
+ body: _response.error.body,
2996
+ rawResponse: _response.rawResponse
2997
+ });
2998
+ }
2999
+ }
3000
+ return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/runs/{id}");
3001
+ }
3002
+ /**
3003
+ * Starts a run of a stored agent and streams what it does as Server-Sent Events. The response is always `text/event-stream`, whatever `Accept` you send; its `X-Vectros-Run-Id` header names the run. The run's tool calls act as you, with your own permissions, and only through the tools the agent lists. On a prepaid account the run reserves its budget from your inference balance when it starts and returns what its model calls did not use when it ends; a fixed fee per run, tool calls and run time are billed separately, against your plan. Read each event's `type`; ignore types and fields you do not know; stop at the event with `terminal: true`. A stream that ends without one: read the run with `GET /v1/runs/{id}`. Closing the stream stops the run only on a best-effort basis. Requires the `runs:c` scope, and agent runs switched on for your tenant by an account owner.
3004
+ */
3005
+ createRun(request, requestOptions) {
3006
+ return HttpResponsePromise.fromPromise(this.__createRun(request, requestOptions));
3007
+ }
3008
+ async __createRun(request, requestOptions) {
3009
+ const { "Idempotency-Key": idempotencyKey, ..._body } = request;
3010
+ const _authRequest = await this._options.authProvider.getAuthRequest();
3011
+ const _headers = mergeHeaders(
3012
+ _authRequest.headers,
3013
+ this._options?.headers,
3014
+ mergeOnlyDefinedHeaders({ "Idempotency-Key": idempotencyKey }),
3015
+ requestOptions?.headers
3016
+ );
3017
+ const _response = await fetcher({
3018
+ url: url_exports.join(
3019
+ await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment),
3020
+ "v1/runs"
3021
+ ),
3022
+ method: "POST",
3023
+ headers: _headers,
3024
+ contentType: "application/json",
3025
+ queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
3026
+ requestType: "json",
3027
+ body: _body,
3028
+ responseType: "sse",
3029
+ timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
3030
+ maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
3031
+ abortSignal: requestOptions?.abortSignal,
3032
+ fetchFn: this._options?.fetch,
3033
+ logging: this._options.logging
3034
+ });
3035
+ if (_response.ok) {
3036
+ return {
3037
+ data: new Stream({
3038
+ stream: _response.body,
3039
+ parse: (data) => data,
3040
+ signal: requestOptions?.abortSignal,
3041
+ eventShape: {
3042
+ type: "sse"
3043
+ }
3044
+ }),
3045
+ rawResponse: _response.rawResponse
3046
+ };
3047
+ }
3048
+ if (_response.error.reason === "status-code") {
3049
+ switch (_response.error.statusCode) {
3050
+ case 400:
3051
+ throw new BadRequestError(_response.error.body, _response.rawResponse);
3052
+ case 401:
3053
+ throw new UnauthorizedError(_response.error.body, _response.rawResponse);
3054
+ case 402:
3055
+ throw new PaymentRequiredError(_response.error.body, _response.rawResponse);
3056
+ case 403:
3057
+ throw new ForbiddenError(_response.error.body, _response.rawResponse);
3058
+ case 404:
3059
+ throw new NotFoundError(_response.error.body, _response.rawResponse);
3060
+ case 409:
3061
+ throw new ConflictError(_response.error.body, _response.rawResponse);
3062
+ case 413:
3063
+ throw new ContentTooLargeError(_response.error.body, _response.rawResponse);
3064
+ case 422:
3065
+ throw new UnprocessableEntityError(_response.error.body, _response.rawResponse);
3066
+ case 429:
3067
+ throw new TooManyRequestsError(_response.error.body, _response.rawResponse);
3068
+ case 503:
3069
+ throw new ServiceUnavailableError(_response.error.body, _response.rawResponse);
3070
+ default:
3071
+ throw new VectrosError({
3072
+ statusCode: _response.error.statusCode,
3073
+ body: _response.error.body,
3074
+ rawResponse: _response.rawResponse
3075
+ });
3076
+ }
3077
+ }
3078
+ return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/runs");
2437
3079
  }
2438
- }
3080
+ };
2439
3081
  var AuthClient = class {
2440
3082
  constructor(options) {
2441
3083
  this._options = normalizeClientOptionsWithAuth(options);
@@ -2983,9 +3625,7 @@ var AuthClient = class {
2983
3625
  * @example
2984
3626
  * await client.auth.createAccessProfile({
2985
3627
  * contextId: "contextId",
2986
- * body: {
2987
- * principalId: "usr_6ba7b810-9dad-11d1-80b4-00c04fd430c8"
2988
- * }
3628
+ * body: {}
2989
3629
  * })
2990
3630
  */
2991
3631
  createAccessProfile(request, requestOptions) {
@@ -3121,10 +3761,7 @@ var AuthClient = class {
3121
3761
  *
3122
3762
  * @example
3123
3763
  * await client.auth.createAppContext({
3124
- * body: {
3125
- * contextId: "myapp",
3126
- * name: "My Internal App"
3127
- * }
3764
+ * body: {}
3128
3765
  * })
3129
3766
  */
3130
3767
  createAppContext(request, requestOptions) {
@@ -3267,13 +3904,7 @@ var AuthClient = class {
3267
3904
  * @example
3268
3905
  * await client.auth.createRole({
3269
3906
  * contextId: "contextId",
3270
- * body: {
3271
- * roleId: "engineering-member",
3272
- * name: "Engineering Team Member",
3273
- * scopes: [{
3274
- * allowed_actions: ["records:cru", "search:r"]
3275
- * }]
3276
- * }
3907
+ * body: {}
3277
3908
  * })
3278
3909
  */
3279
3910
  createRole(request, requestOptions) {
@@ -3417,9 +4048,7 @@ var AuthClient = class {
3417
4048
  * await client.auth.updateAccessProfile({
3418
4049
  * contextId: "contextId",
3419
4050
  * principalId: "principalId",
3420
- * body: {
3421
- * principalId: "usr_6ba7b810-9dad-11d1-80b4-00c04fd430c8"
3422
- * }
4051
+ * body: {}
3423
4052
  * })
3424
4053
  */
3425
4054
  updateAccessProfile(request, requestOptions) {
@@ -3622,10 +4251,7 @@ var AuthClient = class {
3622
4251
  * @example
3623
4252
  * await client.auth.updateAppContext({
3624
4253
  * contextId: "contextId",
3625
- * body: {
3626
- * contextId: "myapp",
3627
- * name: "My Internal App"
3628
- * }
4254
+ * body: {}
3629
4255
  * })
3630
4256
  */
3631
4257
  updateAppContext(request, requestOptions) {
@@ -3830,13 +4456,7 @@ var AuthClient = class {
3830
4456
  * await client.auth.updateRole({
3831
4457
  * contextId: "contextId",
3832
4458
  * roleId: "roleId",
3833
- * body: {
3834
- * roleId: "engineering-member",
3835
- * name: "Engineering Team Member",
3836
- * scopes: [{
3837
- * allowed_actions: ["records:cru", "search:r"]
3838
- * }]
3839
- * }
4459
+ * body: {}
3840
4460
  * })
3841
4461
  */
3842
4462
  updateRole(request, requestOptions) {
@@ -5288,7 +5908,7 @@ var DocumentsClient = class {
5288
5908
  this._options = normalizeClientOptionsWithAuth(options);
5289
5909
  }
5290
5910
  /**
5291
- * Returns a paginated list of your documents, optionally filtered by folder (`folderId`) and/or owner (`userId` or `scope`). The response is a `{data, nextCursor}` envelope; pass `nextCursor` back as `startFrom` to fetch the next page. Requires the `documents:r` scope.
5911
+ * Returns a paginated list of your documents, optionally filtered by folder (`folderId`), owner (`userId` or `scope`) and/or type (`type`). The response is a `{data, nextCursor}` envelope; pass `nextCursor` back as `startFrom` to fetch the next page. A page can hold fewer documents than `limit`, or none, while `nextCursor` is still set: keep paging until `nextCursor` is null. Requires the `documents:r` scope.
5292
5912
  *
5293
5913
  * @param {Vectros.ListDocumentsRequest} request
5294
5914
  * @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -5298,6 +5918,7 @@ var DocumentsClient = class {
5298
5918
  * userId: "550e8400-e29b-41d4-a716-446655440000",
5299
5919
  * scope: "group:eng-team",
5300
5920
  * folderId: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
5921
+ * type: "investigation_report",
5301
5922
  * startFrom: "b3BhcXVlLWN1cnNvci1mcm9tLXRoZS1wcmV2aW91cy1wYWdl"
5302
5923
  * })
5303
5924
  */
@@ -5305,11 +5926,12 @@ var DocumentsClient = class {
5305
5926
  return HttpResponsePromise.fromPromise(this.__listDocuments(request, requestOptions));
5306
5927
  }
5307
5928
  async __listDocuments(request = {}, requestOptions) {
5308
- const { userId, scope, folderId, startFrom, limit } = request;
5929
+ const { userId, scope, folderId, type: type_, startFrom, limit } = request;
5309
5930
  const _queryParams = {
5310
5931
  userId,
5311
5932
  scope,
5312
5933
  folderId,
5934
+ type: type_,
5313
5935
  startFrom,
5314
5936
  limit
5315
5937
  };
@@ -5359,9 +5981,7 @@ var DocumentsClient = class {
5359
5981
  *
5360
5982
  * @example
5361
5983
  * await client.documents.ingestDocument({
5362
- * body: {
5363
- * title: "Patient Intake Form \u2014 Jane Doe"
5364
- * }
5984
+ * body: {}
5365
5985
  * })
5366
5986
  */
5367
5987
  ingestDocument(request, requestOptions) {
@@ -5491,9 +6111,7 @@ var DocumentsClient = class {
5491
6111
  * @example
5492
6112
  * await client.documents.updateDocument({
5493
6113
  * id: "id",
5494
- * body: {
5495
- * title: "Patient Intake Form \u2014 Jane Doe"
5496
- * }
6114
+ * body: {}
5497
6115
  * })
5498
6116
  */
5499
6117
  updateDocument(request, requestOptions) {
@@ -5891,11 +6509,12 @@ var DocumentsClient = class {
5891
6509
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/documents/{id}/download");
5892
6510
  }
5893
6511
  /**
5894
- * Returns the document's full text body when it is retained: retained for text-ingested documents, and for file-uploaded documents unless they were uploaded with `storeText=false` (which discards the extracted text once indexing completes — the original file remains available via `GET /v1/documents/{id}/download`). Returns 404 when the document does not exist, its text was not retained, or extraction has not yet completed. Requires the `documents:r` scope.
6512
+ * Returns the document's full text body when it is retained: retained for text-ingested documents, and for file-uploaded documents unless they were uploaded with `storeText=false` (which discards the extracted text once indexing completes — the original file remains available via `GET /v1/documents/{id}/download`). Returns 404 when the document does not exist, its text was not retained, extraction has not yet completed, or no text could be extracted from its file (see the document's `extraction`). To read a long text in parts, pass `limit` (and `offset` from the second part on): offsets and lengths count Unicode characters (code points), `totalLength` is the length of the whole text, and `nextOffset` is where the next part starts, absent once the end is reached. Requires the `documents:r` scope.
5895
6513
  *
5896
6514
  * @param {Vectros.GetDocumentTextRequest} request
5897
6515
  * @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
5898
6516
  *
6517
+ * @throws {@link Vectros.BadRequestError}
5899
6518
  * @throws {@link Vectros.NotFoundError}
5900
6519
  *
5901
6520
  * @example
@@ -5907,7 +6526,11 @@ var DocumentsClient = class {
5907
6526
  return HttpResponsePromise.fromPromise(this.__getDocumentText(request, requestOptions));
5908
6527
  }
5909
6528
  async __getDocumentText(request, requestOptions) {
5910
- const { id } = request;
6529
+ const { id, offset, limit } = request;
6530
+ const _queryParams = {
6531
+ offset,
6532
+ limit
6533
+ };
5911
6534
  const _authRequest = await this._options.authProvider.getAuthRequest();
5912
6535
  const _headers = mergeHeaders(
5913
6536
  _authRequest.headers,
@@ -5921,7 +6544,7 @@ var DocumentsClient = class {
5921
6544
  ),
5922
6545
  method: "GET",
5923
6546
  headers: _headers,
5924
- queryString: url_exports.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
6547
+ queryString: url_exports.queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
5925
6548
  timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
5926
6549
  maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
5927
6550
  abortSignal: requestOptions?.abortSignal,
@@ -5933,6 +6556,8 @@ var DocumentsClient = class {
5933
6556
  }
5934
6557
  if (_response.error.reason === "status-code") {
5935
6558
  switch (_response.error.statusCode) {
6559
+ case 400:
6560
+ throw new BadRequestError(_response.error.body, _response.rawResponse);
5936
6561
  case 404:
5937
6562
  throw new NotFoundError(_response.error.body, _response.rawResponse);
5938
6563
  default:
@@ -6152,9 +6777,7 @@ var FoldersClient = class {
6152
6777
  *
6153
6778
  * @example
6154
6779
  * await client.folders.createFolder({
6155
- * body: {
6156
- * name: "Patient Records 2024"
6157
- * }
6780
+ * body: {}
6158
6781
  * })
6159
6782
  */
6160
6783
  createFolder(request, requestOptions) {
@@ -6282,9 +6905,7 @@ var FoldersClient = class {
6282
6905
  * @example
6283
6906
  * await client.folders.updateFolder({
6284
6907
  * id: "id",
6285
- * body: {
6286
- * name: "Patient Records 2024"
6287
- * }
6908
+ * body: {}
6288
6909
  * })
6289
6910
  */
6290
6911
  updateFolder(request, requestOptions) {
@@ -6417,9 +7038,7 @@ var FoldersClient = class {
6417
7038
  * @example
6418
7039
  * await client.folders.patchFolder({
6419
7040
  * id: "id",
6420
- * body: {
6421
- * name: "Patient Records 2024"
6422
- * }
7041
+ * body: {}
6423
7042
  * })
6424
7043
  */
6425
7044
  patchFolder(request, requestOptions) {
@@ -6634,9 +7253,7 @@ var IdentityClient = class {
6634
7253
  * await client.identity.createEntity({
6635
7254
  * namespace: "team",
6636
7255
  * contextId: "myapp",
6637
- * body: {
6638
- * externalId: "team_eng_platform"
6639
- * }
7256
+ * body: {}
6640
7257
  * })
6641
7258
  */
6642
7259
  createEntity(request, requestOptions) {
@@ -6772,9 +7389,7 @@ var IdentityClient = class {
6772
7389
  * namespace: "team",
6773
7390
  * id: "id",
6774
7391
  * contextId: "myapp",
6775
- * body: {
6776
- * externalId: "team_eng_platform"
6777
- * }
7392
+ * body: {}
6778
7393
  * })
6779
7394
  */
6780
7395
  updateEntity(request, requestOptions) {
@@ -7114,10 +7729,7 @@ var IdentityClient = class {
7114
7729
  * @example
7115
7730
  * await client.identity.updateNamespace({
7116
7731
  * namespace: "team",
7117
- * body: {
7118
- * namespace: "team",
7119
- * specificityRank: 1500
7120
- * }
7732
+ * body: {}
7121
7733
  * })
7122
7734
  */
7123
7735
  updateNamespace(request, requestOptions) {
@@ -7304,10 +7916,7 @@ var IdentityClient = class {
7304
7916
  *
7305
7917
  * @example
7306
7918
  * await client.identity.registerNamespace({
7307
- * body: {
7308
- * namespace: "team",
7309
- * specificityRank: 1500
7310
- * }
7919
+ * body: {}
7311
7920
  * })
7312
7921
  */
7313
7922
  registerNamespace(request, requestOptions) {
@@ -7440,9 +8049,7 @@ var IdentityClient = class {
7440
8049
  *
7441
8050
  * @example
7442
8051
  * await client.identity.createUser({
7443
- * body: {
7444
- * externalId: "usr_12345"
7445
- * }
8052
+ * body: {}
7446
8053
  * })
7447
8054
  */
7448
8055
  createUser(request, requestOptions) {
@@ -7561,6 +8168,7 @@ var IdentityClient = class {
7561
8168
  * @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
7562
8169
  *
7563
8170
  * @throws {@link Vectros.BadRequestError}
8171
+ * @throws {@link Vectros.ForbiddenError}
7564
8172
  * @throws {@link Vectros.NotFoundError}
7565
8173
  * @throws {@link Vectros.ConflictError}
7566
8174
  * @throws {@link Vectros.TooManyRequestsError}
@@ -7568,9 +8176,7 @@ var IdentityClient = class {
7568
8176
  * @example
7569
8177
  * await client.identity.updateUser({
7570
8178
  * id: "550e8400-e29b-41d4-a716-446655440000",
7571
- * body: {
7572
- * externalId: "usr_12345"
7573
- * }
8179
+ * body: {}
7574
8180
  * })
7575
8181
  */
7576
8182
  updateUser(request, requestOptions) {
@@ -7608,6 +8214,8 @@ var IdentityClient = class {
7608
8214
  switch (_response.error.statusCode) {
7609
8215
  case 400:
7610
8216
  throw new BadRequestError(_response.error.body, _response.rawResponse);
8217
+ case 403:
8218
+ throw new ForbiddenError(_response.error.body, _response.rawResponse);
7611
8219
  case 404:
7612
8220
  throw new NotFoundError(_response.error.body, _response.rawResponse);
7613
8221
  case 409:
@@ -7630,6 +8238,7 @@ var IdentityClient = class {
7630
8238
  * @param {Vectros.DeleteUserRequest} request
7631
8239
  * @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
7632
8240
  *
8241
+ * @throws {@link Vectros.ForbiddenError}
7633
8242
  * @throws {@link Vectros.NotFoundError}
7634
8243
  * @throws {@link Vectros.ConflictError}
7635
8244
  * @throws {@link Vectros.TooManyRequestsError}
@@ -7669,6 +8278,8 @@ var IdentityClient = class {
7669
8278
  }
7670
8279
  if (_response.error.reason === "status-code") {
7671
8280
  switch (_response.error.statusCode) {
8281
+ case 403:
8282
+ throw new ForbiddenError(_response.error.body, _response.rawResponse);
7672
8283
  case 404:
7673
8284
  throw new NotFoundError(_response.error.body, _response.rawResponse);
7674
8285
  case 409:
@@ -7873,7 +8484,7 @@ var InferenceClient = class {
7873
8484
  this._options = normalizeClientOptionsWithAuth(options);
7874
8485
  }
7875
8486
  /**
7876
- * Returns the whole platform model catalog, whatever your plan: `availableOn` names each model's plan tiers. Each entry also carries the context window and the credit rates per 1K input and output tokens: `regionPricing.base` for global-region requests, `regionPricing.us` for default requests, and `longContext` for prompts over its threshold. A model reached through a `providerAlias` is not listed. Use this to populate model pickers and to validate a request before calling `/v1/chat`, `/v1/rag`, or `/v1/documents/{id}/ask`.
8487
+ * Returns the whole platform model catalog, whatever your plan: `availableOn` names each model's plan tiers. Each entry also carries the context window and the credit rates per 1K input and output tokens: `regionPricing.base` for global-region requests, `regionPricing.us` for default requests, `longContext` for prompts over its threshold, and `cachePricing` for prompt-cache tokens on a model that has cache prices. A model reached through a `providerAlias` is not listed. Use this to populate model pickers and to validate a request before calling `/v1/chat`, `/v1/rag`, or `/v1/documents/{id}/ask`.
7877
8488
  *
7878
8489
  * @param {InferenceClient.RequestOptions} requestOptions - Request-specific configuration.
7879
8490
  *
@@ -7917,7 +8528,7 @@ var InferenceClient = class {
7917
8528
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/models");
7918
8529
  }
7919
8530
  /**
7920
- * Streams a model response as Server-Sent Events (SSE). Send the full conversation history in the `messages` array; a message with role `system` is extracted and used as the system prompt. On a pre-paid account, token cost is debited from your inference balance; usage-billed accounts accrue it for post-billing. A request routed through your own `providerAlias` incurs no Vectros token cost. A small per-call flat fee is charged to your monthly credit allowance, except when the call fails on the server side. Requires the `inference:r` scope.
8531
+ * Streams a model response as Server-Sent Events (SSE). Send the full conversation history in the `messages` array; a message with role `system` is extracted and used as the system prompt. On a pre-paid account, token cost is debited from your inference balance; usage-billed accounts accrue it for post-billing. A request routed through your own `providerAlias` incurs no Vectros token cost. A per-call platform fee is charged to your monthly credit allowance, except when the call fails on the server side: 0.2 credits for a call of up to 60 seconds, then 1 credit per 5 minutes of the call's duration. Requires the `inference:r` scope.
7921
8532
  */
7922
8533
  chatInference(request, requestOptions) {
7923
8534
  return HttpResponsePromise.fromPromise(this.__chatInference(request, requestOptions));
@@ -7989,7 +8600,7 @@ var InferenceClient = class {
7989
8600
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/chat");
7990
8601
  }
7991
8602
  /**
7992
- * Loads a single document's extracted text, supplies it as context, and streams a model answer about it. The document must be fully indexed. If the document exceeds the 32K-token cap, the call returns 413 with no credits charged — use `POST /v1/rag` instead to answer over larger or multi-document collections. Requires the `inference:r` scope.
8603
+ * Loads a single document's extracted text, supplies it as context, and streams a model answer about it. The document must have finished processing and have text. If the document exceeds the 32K-token cap, the call returns 413 with no credits charged — use `POST /v1/rag` instead to answer over larger or multi-document collections. Requires the `inference:r` scope.
7993
8604
  */
7994
8605
  documentAsk(request, requestOptions) {
7995
8606
  return HttpResponsePromise.fromPromise(this.__documentAsk(request, requestOptions));
@@ -9124,8 +9735,7 @@ var SchemasClient = class {
9124
9735
  * }],
9125
9736
  * capabilities: {
9126
9737
  * "auditHistory": true
9127
- * },
9128
- * allowedSurfaces: ["record"]
9738
+ * }
9129
9739
  * }
9130
9740
  * })
9131
9741
  */
@@ -9255,11 +9865,7 @@ var SchemasClient = class {
9255
9865
  * @example
9256
9866
  * await client.schemas.updateSchema({
9257
9867
  * id: "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
9258
- * body: {
9259
- * typeName: "intake_form",
9260
- * displayName: "Client Intake Form",
9261
- * allowedSurfaces: ["record"]
9262
- * }
9868
+ * body: {}
9263
9869
  * })
9264
9870
  */
9265
9871
  updateSchema(request, requestOptions) {
@@ -9799,7 +10405,7 @@ var ScriptsClient = class {
9799
10405
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "PUT", "/v1/scripts/{id}");
9800
10406
  }
9801
10407
  /**
9802
- * Permanently deletes one script version by ID. Deleting one version does not affect any other version of the same name. Requires the `scripts:d` scope. Refused with 409 if a live trigger rule still references this version — either directly (a pinned `scriptRef`), or via `"latest"` when this IS the newest version of its name. Delete or re-point those rules first.
10408
+ * Permanently deletes one script version by ID. Deleting one version does not affect any other version of the same name. Requires the `scripts:d` scope. Refused with 409 if a live trigger rule still references this version — either directly (a pinned `scriptRef`), or via `"latest"` when this IS the newest version of its name. Delete or re-point those rules first. Also refused with a retryable 409, deleting nothing, when it cannot be told yet whether this is the newest version (for example just after several of this name's newest versions were deleted, or while its first version is gone and the listing has not caught up) and a `"latest"` rule depends on the script: try again shortly.
9803
10409
  *
9804
10410
  * @param {Vectros.DeleteScriptRequest} request
9805
10411
  * @param {ScriptsClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -10063,17 +10669,7 @@ var TriggersClient = class {
10063
10669
  *
10064
10670
  * @example
10065
10671
  * await client.triggers.createTrigger({
10066
- * body: {
10067
- * name: "on-intake-create",
10068
- * firingSource: {
10069
- * schemaId: "sch_9f8e7d6c",
10070
- * event: "CREATE"
10071
- * },
10072
- * scriptRef: {
10073
- * name: "notify-assignee",
10074
- * version: "3"
10075
- * }
10076
- * }
10672
+ * body: {}
10077
10673
  * })
10078
10674
  */
10079
10675
  createTrigger(request, requestOptions) {
@@ -10202,17 +10798,7 @@ var TriggersClient = class {
10202
10798
  * @example
10203
10799
  * await client.triggers.updateTrigger({
10204
10800
  * id: "id",
10205
- * body: {
10206
- * name: "on-intake-create",
10207
- * firingSource: {
10208
- * schemaId: "sch_9f8e7d6c",
10209
- * event: "CREATE"
10210
- * },
10211
- * scriptRef: {
10212
- * name: "notify-assignee",
10213
- * version: "3"
10214
- * }
10215
- * }
10801
+ * body: {}
10216
10802
  * })
10217
10803
  */
10218
10804
  updateTrigger(request, requestOptions) {
@@ -10337,6 +10923,9 @@ var VectrosClient = class {
10337
10923
  get auth() {
10338
10924
  return this._auth ?? (this._auth = new AuthClient(this._options));
10339
10925
  }
10926
+ get agents() {
10927
+ return this._agents ?? (this._agents = new AgentsClient(this._options));
10928
+ }
10340
10929
  get documents() {
10341
10930
  return this._documents ?? (this._documents = new DocumentsClient(this._options));
10342
10931
  }
@@ -10402,7 +10991,7 @@ var logging;
10402
10991
 
10403
10992
  // src/server.ts
10404
10993
  var import_types3 = require("@modelcontextprotocol/sdk/types.js");
10405
- var import_zod25 = require("zod");
10994
+ var import_zod28 = require("zod");
10406
10995
 
10407
10996
  // src/auth.ts
10408
10997
  var KEY_RE = /^(sk|ssk|st)_(live|test)_/;
@@ -10446,8 +11035,8 @@ function warnOnSuboptimalKey(key, log) {
10446
11035
 
10447
11036
  // src/build-info.ts
10448
11037
  var BUILD_INFO = {
10449
- mcpServer: true ? "0.18.2" : "dev",
10450
- sdk: true ? "0.48.0" : "dev"
11038
+ mcpServer: true ? "0.19.0" : "dev",
11039
+ sdk: true ? "0.49.0" : "dev"
10451
11040
  };
10452
11041
  function formatBuildInfo() {
10453
11042
  return `vectros-mcp-server ${BUILD_INFO.mcpServer} (sdk ${BUILD_INFO.sdk})`;
@@ -10706,6 +11295,11 @@ ${detail}${trailer}`
10706
11295
  };
10707
11296
  }
10708
11297
 
11298
+ // src/tools/limits.ts
11299
+ var MAX_OWNERSHIP_SCOPES = 2;
11300
+ var MAX_SCOPE_FILTERS = 16;
11301
+ var MAX_CONTENT_TYPES = 2;
11302
+
10709
11303
  // src/tools/hybrid_search.ts
10710
11304
  var MCP_DEFAULT_LIMIT = 3;
10711
11305
  var MCP_MAX_LIMIT = 50;
@@ -10748,11 +11342,11 @@ var inputSchema = {
10748
11342
  folderId: import_zod.z.string().optional().describe("Scope to content in this EXACT folder (Vectros folder id)."),
10749
11343
  rootFolderId: import_zod.z.string().optional().describe("Scope to content under this folder AND all its descendants (subtree-root folder id)."),
10750
11344
  // Content narrowing.
10751
- contentTypes: import_zod.z.array(import_zod.z.enum(["documents", "records"])).optional().describe('Narrow to content types. ["documents"] or ["records"]; omit for unified (both).'),
11345
+ contentTypes: import_zod.z.array(import_zod.z.enum(["documents", "records"])).max(MAX_CONTENT_TYPES, `contentTypes accepts at most ${MAX_CONTENT_TYPES} entries`).optional().describe('Narrow to content types. ["documents"] or ["records"]; omit for unified (both).'),
10752
11346
  typeName: import_zod.z.string().optional().describe(
10753
11347
  'Restrict hits to this schema type (e.g. "patient", "runbook"). Applies to BOTH documents and records \u2014 combine with contentTypes to scope within one content type. Untyped content never matches.'
10754
11348
  ),
10755
- filters: import_zod.z.record(import_zod.z.unknown()).optional().describe(
11349
+ filters: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional().describe(
10756
11350
  'Field-level metadata filters (AND-combined). Value = scalar (equality), array (OR-set), or operator map: $eq/$ne/$gt/$gte/$lt/$lte (scalar) or $in/$nin (array). e.g. {"status":"open"} or {"price":{"$gte":100,"$lte":500}}.'
10757
11351
  ),
10758
11352
  // Ownership.
@@ -10760,7 +11354,7 @@ var inputSchema = {
10760
11354
  scope: import_zod.z.string().optional().describe(
10761
11355
  'Restrict to content carrying this scope value, in `namespace:value` form (e.g. "org:<uuid>", "client:<uuid>", "group:eng-team"). `org` and `client` are reserved namespace names, registered like any other; others are namespaces you registered yourself. Mutually exclusive with `scopeFilters` \u2014 use this for ONE dimension.'
10762
11356
  ),
10763
- scopeFilters: import_zod.z.array(import_zod.z.string()).min(1, "scopeFilters must name at least one dimension when supplied").optional().describe(
11357
+ scopeFilters: import_zod.z.array(import_zod.z.string()).min(1, "scopeFilters must name at least one dimension when supplied").max(MAX_SCOPE_FILTERS, `scopeFilters accepts at most ${MAX_SCOPE_FILTERS} entries`).optional().describe(
10764
11358
  'Restrict to content matching ALL of these scope values \u2014 one per namespace \u2014 for a credential whose access spans more than one ownership dimension. e.g. ["org:<uuid>", "client:<uuid>"] narrows to one specific client WITHIN one specific org, which `scope` alone cannot express. Same `namespace:value` form as `scope`; naming the same namespace twice is rejected. Mutually exclusive with `scope` \u2014 use `scope` for a single dimension.'
10765
11359
  ),
10766
11360
  // Date window.
@@ -11281,7 +11875,7 @@ var inputSchema5 = {
11281
11875
  status: import_zod5.z.string().optional().describe("Record lifecycle status. Defaults to ACTIVE server-side."),
11282
11876
  folderId: import_zod5.z.string().optional().describe("Group this record into a folder."),
11283
11877
  userId: import_zod5.z.string().optional().describe("Owning user id."),
11284
- scopes: import_zod5.z.array(import_zod5.z.string()).optional().describe(
11878
+ scopes: import_zod5.z.array(import_zod5.z.string()).max(MAX_OWNERSHIP_SCOPES, `scopes accepts at most ${MAX_OWNERSHIP_SCOPES} entries`).optional().describe(
11285
11879
  'Scope ownership as `namespace:value` entries, at most 2 (e.g. ["org:<uuid>", "group:eng-team"]). `org` and `client` are reserved namespace names, registered like any other; others are namespaces you registered yourself. This is the record\'s COMPLETE scope declaration, and each entry must fall inside the `data_scope` of a single clause of your credential that also grants this write \u2014 your identity supplies the DEFAULT when you state none, it does not limit which value you may state. An empty array `[]` creates a PRIVATE record owned by the calling user alone. Omit to stamp the credential\'s full identity \u2014 the default.'
11286
11880
  )
11287
11881
  };
@@ -11339,7 +11933,7 @@ var itemSchema = import_zod6.z.strictObject({
11339
11933
  status: import_zod6.z.string().optional().describe("Record lifecycle status. Defaults to ACTIVE server-side."),
11340
11934
  folderId: import_zod6.z.string().optional().describe("Group this record into a folder."),
11341
11935
  userId: import_zod6.z.string().optional().describe("Owning user id."),
11342
- scopes: import_zod6.z.array(import_zod6.z.string()).optional().describe(
11936
+ scopes: import_zod6.z.array(import_zod6.z.string()).max(MAX_OWNERSHIP_SCOPES, `scopes accepts at most ${MAX_OWNERSHIP_SCOPES} entries`).optional().describe(
11343
11937
  "Scope ownership as `namespace:value` entries, at most 2 namespaces. When supplied this is the record's COMPLETE scope declaration, and each entry must fall inside the `data_scope` of a single clause of your credential that also grants this write \u2014 your identity supplies the DEFAULT when you state none, it does not limit which value you may state. `[]` creates a PRIVATE record owned by the calling user alone. Omit to inherit the credential's full identity."
11344
11938
  )
11345
11939
  });
@@ -11496,7 +12090,7 @@ var import_zod10 = require("zod");
11496
12090
  // src/tools/provider-alias.ts
11497
12091
  var import_zod9 = require("zod");
11498
12092
  var providerAliasInput = import_zod9.z.string().min(1, "providerAlias must be non-empty when supplied").optional().describe(
11499
- "Route THIS call through your own model provider instead of the platform-hosted default, by the alias of a provider config your account has activated. It works only after your account has set up that provider and signed the platform's risk-acceptance waiver; without both, the platform refuses the call with a 403, which is returned to you as written. When the waiver is the cause, the 403 carries an `errorCode` that says which case it is: `WAIVER_NOT_SIGNED` (the waiver has not been signed), `WAIVER_TEXT_CHANGED` (it was signed, but its text changed afterwards, so the earlier signature no longer counts), or `WAIVER_REVOKED` (an owner revoked it). An account owner resolves each in the developer portal (Model Providers); retrying the call does not help. If your account has accepted the Business Associate Agreement with Vectros in the developer portal, an account owner must also have attested that provider config in the developer portal (Model Providers); until then the platform refuses the call with a 403 that says it needs a BAA-holder attestation. A call served by your own provider leaves the Vectros perimeter. Omit it (the default) to use the platform-hosted path. When set, `model` names the model on your provider's own id space, and falls back to that provider config's default model when omitted."
12093
+ "Route THIS call through your own model provider instead of the platform-hosted default, by the alias of a provider config your account has activated. It works only after your account has set up that provider and signed the platform's risk-acceptance waiver; without both, the platform refuses the call with a 403, which is returned to you as written. When the waiver is the cause, the 403 carries an `errorCode` that says which case it is: `WAIVER_NOT_SIGNED` (the waiver has not been signed), `WAIVER_TEXT_CHANGED` (Vectros now requires a newer version of the waiver than the one in force for your account), or `WAIVER_REVOKED` (an owner revoked it). An account owner resolves each in the developer portal (Model Providers); retrying the call does not help. If your account has accepted the Business Associate Agreement with Vectros in the developer portal, an account owner must also have attested that provider config in the developer portal (Model Providers); until then the platform refuses the call with a 403 that says it needs a BAA-holder attestation. A call served by your own provider leaves the Vectros perimeter. Omit it (the default) to use the platform-hosted path. When set, `model` names the model on your provider's own id space, and falls back to that provider config's default model when omitted."
11500
12094
  );
11501
12095
 
11502
12096
  // src/tools/rag_ask.ts
@@ -11523,14 +12117,14 @@ var inputSchema9 = {
11523
12117
  scope: import_zod10.z.string().optional().describe(
11524
12118
  'Restrict retrieval to content carrying this scope value, in `namespace:value` form (e.g. "org:<uuid>", "client:<uuid>", "group:eng-team"). `org` and `client` are reserved namespace names, registered like any other; others are namespaces you registered yourself. Mutually exclusive with `scopeFilters` \u2014 use this for ONE dimension.'
11525
12119
  ),
11526
- scopeFilters: import_zod10.z.array(import_zod10.z.string()).min(1, "scopeFilters must name at least one dimension when supplied").optional().describe(
12120
+ scopeFilters: import_zod10.z.array(import_zod10.z.string()).min(1, "scopeFilters must name at least one dimension when supplied").max(MAX_SCOPE_FILTERS, `scopeFilters accepts at most ${MAX_SCOPE_FILTERS} entries`).optional().describe(
11527
12121
  'Restrict retrieval to content matching ALL of these scope values \u2014 one per namespace \u2014 for a credential whose access spans more than one ownership dimension. e.g. ["org:<uuid>", "client:<uuid>"] grounds the answer on one specific client WITHIN one specific org, which `scope` alone cannot express. Naming the same namespace twice is rejected. Mutually exclusive with `scope`.'
11528
12122
  ),
11529
12123
  folderId: import_zod10.z.string().optional().describe("Restrict retrieval to this exact folder."),
11530
12124
  rootFolderId: import_zod10.z.string().optional().describe("Restrict retrieval to this folder and all its descendants."),
11531
12125
  typeName: import_zod10.z.string().optional().describe("Restrict record retrieval to this schema type."),
11532
- contentTypes: import_zod10.z.array(import_zod10.z.enum(["documents", "records"])).optional().describe('Narrow retrieval to content types. ["documents"] or ["records"]; omit for both.'),
11533
- filters: import_zod10.z.record(import_zod10.z.unknown()).optional().describe(
12126
+ contentTypes: import_zod10.z.array(import_zod10.z.enum(["documents", "records"])).max(MAX_CONTENT_TYPES, `contentTypes accepts at most ${MAX_CONTENT_TYPES} entries`).optional().describe('Narrow retrieval to content types. ["documents"] or ["records"]; omit for both.'),
12127
+ filters: import_zod10.z.record(import_zod10.z.string(), import_zod10.z.unknown()).optional().describe(
11534
12128
  'Field-level metadata filters (AND-combined). Value = scalar (equality), array (OR-set), or operator map ($eq/$ne/$gt/$gte/$lt/$lte, $in/$nin). e.g. {"status":"open"}.'
11535
12129
  ),
11536
12130
  createdAfter: import_zod10.z.string().optional().describe(
@@ -11805,7 +12399,7 @@ function isNotAvailable(err) {
11805
12399
  var documentGet = ({ client, log }) => ({
11806
12400
  name: "document_get",
11807
12401
  title: "Get document metadata (and optionally text)",
11808
- description: "Fetch metadata for a single document \u2014 select it by its Vectros `documentId` OR by your own `externalId` + `type` (resolved for you). Pass `includeText: true` to also fetch the text body (capped at ~8K tokens; `truncated: true` flag if cut). Text is available for every text-ingested document and for file-ingested documents unless they were uploaded with `storeText: false` (extracted text discarded after indexing) \u2014 then `textAvailable: false` is set; the original file is still retrievable via `includeDownloadUrl`. Pass `includeDownloadUrl: true` to also get a short-lived presigned `downloadUrl` for the original file (file-backed documents only). Returns the full document metadata, including its lifecycle `status` (ACTIVE, or ARCHIVED when soft-retracted from search \u2014 restorable via document_update) and its processing `indexStatus`. When `indexStatus` is FAILED the response also carries `indexFailure` with a machine-readable `code` telling you whether the content is still findable \u2014 e.g. TEXT_INDEX_FAILED / VECTOR_LIMIT_EXCEEDED (one leg still serves it) vs INDEXING_FAILED (not findable by search at all). Branch on `code`, not on the message.",
12402
+ description: "Fetch metadata for a single document \u2014 select it by its Vectros `documentId` OR by your own `externalId` + `type` (resolved for you). Pass `includeText: true` to also fetch the text body (capped at ~8K tokens; `truncated: true` flag if cut). Text is available for every text-ingested document and for file-ingested documents unless they were uploaded with `storeText: false` (extracted text discarded after indexing) or no text could be extracted from the file (`extraction.outcome` other than OK/TRUNCATED, e.g. an image or a scanned page) \u2014 then `textAvailable: false` is set; the original file is still retrievable via `includeDownloadUrl`. Pass `includeDownloadUrl: true` to also get a short-lived presigned `downloadUrl` for the original file (file-backed documents only). Returns the full document metadata, including its lifecycle `status` (ACTIVE, or ARCHIVED when soft-retracted from search \u2014 restorable via document_update) and its processing `indexStatus`. When `indexStatus` is FAILED the response also carries `indexFailure` with a machine-readable `code` telling you whether the content is still findable \u2014 e.g. TEXT_INDEX_FAILED / VECTOR_LIMIT_EXCEEDED (one leg still serves it) vs INDEXING_FAILED (not findable by search at all). Branch on `code`, not on the message.",
11809
12403
  inputSchema: inputSchema12,
11810
12404
  // A pure read — never creates, modifies, or deletes anything server-side.
11811
12405
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true },
@@ -11831,7 +12425,7 @@ var documentGet = ({ client, log }) => ({
11831
12425
  if (isNotAvailable(textErr)) {
11832
12426
  log.debug(
11833
12427
  { tool: "document_get", id },
11834
- "document_get text unavailable (not retained \u2014 storeText:false upload)"
12428
+ "document_get text unavailable (not retained, or no text could be extracted from the file)"
11835
12429
  );
11836
12430
  extra = { ...extra, textAvailable: false };
11837
12431
  } else {
@@ -11884,10 +12478,12 @@ var inputSchema13 = {
11884
12478
  to: import_zod14.z.string().optional().describe("Lookup mode (range): inclusive upper bound; requires `from`."),
11885
12479
  prefix: import_zod14.z.string().optional().describe("Lookup mode (prefix): match values starting with this. Range-enabled string fields only."),
11886
12480
  order: import_zod14.z.enum(["asc", "desc"]).optional().describe(
11887
- "Lookup mode: sort direction by the looked-up field. `asc` (default) or `desc` \u2014 use `desc` with a range/prefix lookup to get the most-recent / highest values first (e.g. latest-N). Ignored in list mode."
12481
+ "Lookup mode: sort direction by the looked-up field. `asc` (default) or `desc` \u2014 use `desc` with a range/prefix lookup to get the most-recent / highest values first (e.g. latest-N). Refused without `field`."
11888
12482
  ),
11889
- type: import_zod14.z.string().optional().describe("Lookup mode: the document type (the bound schema's type). Required with `field`."),
11890
- // List-mode args:
12483
+ type: import_zod14.z.string().min(1, "type must be non-empty: omit it to list every type").optional().describe(
12484
+ "The document type (the bound schema's type). Required with `field` (lookup mode); in list mode it narrows the list to documents of this type. The list filter applies page by page: a page can hold fewer documents than `limit`, or none, while `nextCursor` is set, so keep paging until `nextCursor` is null before concluding there are none. For a large collection, hybrid_search with `typeName` finds documents of one type directly."
12485
+ ),
12486
+ // List-mode args (`type` above applies to both modes):
11891
12487
  folderId: import_zod14.z.string().optional().describe("List mode: only documents in this folder (Vectros folder id)."),
11892
12488
  userId: import_zod14.z.string().optional().describe("List mode: scope to documents owned by this user."),
11893
12489
  scope: import_zod14.z.string().optional().describe(
@@ -11901,7 +12497,7 @@ var inputSchema13 = {
11901
12497
  var documentQuery = ({ client, log }) => ({
11902
12498
  name: "document_query",
11903
12499
  title: "Document query (list or lookup)",
11904
- description: "Query document metadata. Two modes:\n \u2022 Lookup on a lookup-indexed field: pass `type` and `field` plus exactly one of `value` (exact), `from`+`to` (range), or `prefix`. Works on sensitive fields (equality only there); range/prefix need a range-enabled field.\n \u2022 List: omit `field`; optionally filter by `folderId`/`userId`/`scope` (`namespace:value`).\nReturns a `{ data, nextCursor }` page: `data` holds up to `limit` documents (default 3, max 100 \u2014 raise it in one call when you can accept the payload), and a non-null `nextCursor` means more remain \u2014 pass it back as `startFrom` to page. Mode is auto-detected. Use document_get for the full text/download URL of one document.",
12500
+ description: "Query document metadata. Two modes:\n \u2022 Lookup on a lookup-indexed field: pass `type` and `field` plus exactly one of `value` (exact), `from`+`to` (range), or `prefix`. Works on sensitive fields (equality only there); range/prefix need a range-enabled field.\n \u2022 List: omit `field`; optionally filter by `type`/`folderId`/`userId`/`scope` (`namespace:value`). The `type` filter is applied page by page, so a page can be short or empty while `nextCursor` is set: keep paging before concluding there are none.\nReturns a `{ data, nextCursor }` page: `data` holds up to `limit` documents (default 3, max 100 \u2014 raise it in one call when you can accept the payload), and a non-null `nextCursor` means more remain \u2014 pass it back as `startFrom` to page. Mode is auto-detected. Use document_get for the full text/download URL of one document.",
11905
12501
  inputSchema: inputSchema13,
11906
12502
  // A pure read — never creates, modifies, or deletes anything server-side.
11907
12503
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true },
@@ -11960,7 +12556,19 @@ var documentQuery = ({ client, log }) => ({
11960
12556
  "document_query lookup ok"
11961
12557
  );
11962
12558
  } else {
12559
+ const strayLookupArgs = ["value", "from", "to", "prefix", "order"].filter(
12560
+ (k) => args[k] !== void 0
12561
+ );
12562
+ if (strayLookupArgs.length > 0) {
12563
+ return toolError(
12564
+ "document_query",
12565
+ new Error(
12566
+ `Lookup arguments need 'field' (and 'type'): ${strayLookupArgs.map((k) => `'${k}'`).join(", ")}. Without 'field' the call lists documents: filter the list with 'type', 'folderId', 'userId' or 'scope'.`
12567
+ )
12568
+ );
12569
+ }
11963
12570
  page = await client.documents.listDocuments({
12571
+ type,
11964
12572
  folderId: args.folderId,
11965
12573
  userId: args.userId,
11966
12574
  scope: args.scope,
@@ -11968,7 +12576,7 @@ var documentQuery = ({ client, log }) => ({
11968
12576
  limit
11969
12577
  });
11970
12578
  log.debug(
11971
- { tool: "document_query", mode: "list", limit, returned: pageItems(page).length },
12579
+ { tool: "document_query", mode: "list", type, limit, returned: pageItems(page).length },
11972
12580
  "document_query list ok"
11973
12581
  );
11974
12582
  }
@@ -12003,7 +12611,7 @@ var inputSchema14 = {
12003
12611
  "Lifecycle status. `ARCHIVED` soft-retracts the document \u2014 it is pulled from search and recall but kept and recoverable; set it back to `ACTIVE` to re-index and restore it. The way to retire superseded content when the credential has no delete authority. Omit to leave unchanged."
12004
12612
  ),
12005
12613
  userId: import_zod15.z.string().optional().describe("Reassign the owning user (Vectros UUID)."),
12006
- scopes: import_zod15.z.array(import_zod15.z.string()).optional().describe(
12614
+ scopes: import_zod15.z.array(import_zod15.z.string()).max(MAX_OWNERSHIP_SCOPES, `scopes accepts at most ${MAX_OWNERSHIP_SCOPES} entries`).optional().describe(
12007
12615
  'Reassign scope ownership as `namespace:value` entries, at most 2 (e.g. ["org:<uuid>", "group:eng-team"]) \u2014 the COMPLETE new parent set. `org`/`client` are reserved namespace names, registered like any other. Omit to leave ownership unchanged; `[]` clears it (private to the owning user).'
12008
12616
  ),
12009
12617
  expectedVersion: import_zod15.z.number().int().optional().describe(
@@ -12147,7 +12755,7 @@ var inputSchema17 = {
12147
12755
  "Optional stable slug (sibling-unique; idempotency key). Lowercase letters/digits/hyphens. SUPPLY THIS to make a retry safe \u2014 if omitted, a derived slug is only ever a freshly-proved-free one, so a redelivered call creates a new sibling folder every time rather than matching the first."
12148
12756
  ),
12149
12757
  userId: import_zod18.z.string().optional().describe("Owning user (Vectros UUID)."),
12150
- scopes: import_zod18.z.array(import_zod18.z.string()).optional().describe(
12758
+ scopes: import_zod18.z.array(import_zod18.z.string()).max(MAX_OWNERSHIP_SCOPES, `scopes accepts at most ${MAX_OWNERSHIP_SCOPES} entries`).optional().describe(
12151
12759
  'Scope ownership as `namespace:value` entries, at most 2 (e.g. ["org:<uuid>", "group:eng-team"]). `org` and `client` are reserved namespace names, registered like any other; others are namespaces you registered yourself. This is the folder\'s COMPLETE scope declaration and values must come from the credential\'s own identity. An empty array `[]` creates a PRIVATE folder owned by the calling user alone. Omit to stamp the credential\'s full identity \u2014 the default.'
12152
12760
  )
12153
12761
  };
@@ -12193,7 +12801,7 @@ var inputSchema18 = {
12193
12801
  name: import_zod19.z.string().optional().describe("New folder name. Omit to keep the current name."),
12194
12802
  description: import_zod19.z.string().optional().describe("New description. Omit to leave unchanged."),
12195
12803
  userId: import_zod19.z.string().optional().describe("Reassign the owning user (Vectros UUID)."),
12196
- scopes: import_zod19.z.array(import_zod19.z.string()).optional().describe(
12804
+ scopes: import_zod19.z.array(import_zod19.z.string()).max(MAX_OWNERSHIP_SCOPES, `scopes accepts at most ${MAX_OWNERSHIP_SCOPES} entries`).optional().describe(
12197
12805
  'Reassign scope ownership as `namespace:value` entries, at most 2 (e.g. ["org:<uuid>", "group:eng-team"]) \u2014 the COMPLETE new parent set. `org`/`client` are reserved namespace names, registered like any other. Omit to leave ownership unchanged; `[]` clears it (private to the owning user).'
12198
12806
  ),
12199
12807
  expectedVersion: import_zod19.z.number().int().optional().describe(
@@ -12242,7 +12850,7 @@ var inputSchema19 = {
12242
12850
  var folderDelete = ({ client, log }) => ({
12243
12851
  name: "folder_delete",
12244
12852
  title: "Delete a folder",
12245
- description: 'Permanently delete a folder by id. The folder must be EMPTY first \u2014 it must contain no documents, no records, and no sub-folders \u2014 and a non-empty folder is refused, which is the most common way this call fails. Use record_query with this folderId, and document_query, to see what is in it. Clearing it differs by content type: a document can be moved out (document_update with a different folderId) or deleted. A RECORD can also be re-filed into another folder \u2014 the API supports it \u2014 but THIS SERVER does not expose that yet: record_update has no folderId argument, so from here your only option is record_delete (needs records:d). Do NOT read that as "the record cannot be moved" and delete the record on that basis: if the record should be kept, tell the user to move it with the Vectros API/SDK directly rather than deleting it here. A sub-folder cannot be re-parented at all, so nested folders have to be emptied and deleted innermost-first. Note the emptiness check counts everything in the folder, INCLUDING items your credential cannot read \u2014 so a refusal you cannot account for from what you can list is expected behaviour, not a bug, and retrying will not clear it. Requires the key to allow folders:d \u2014 a key without it gets a permission error. Protected folders (e.g. a context root) cannot be deleted at all, however empty.',
12853
+ description: 'Permanently delete a folder by id. The folder must be EMPTY first \u2014 it must contain no documents, no records, and no sub-folders \u2014 and a non-empty folder is refused, which is the most common way this call fails. Use record_query with this folderId, and document_query, to see what is in it. Clearing it differs by content type: a document can be moved out (document_update with a different folderId) or deleted. A RECORD can also be re-filed into another folder \u2014 the API supports it \u2014 but THIS SERVER does not expose that: record_update has no folderId argument, so from here your only option is record_delete (needs records:d). Do NOT read that as "the record cannot be moved" and delete the record on that basis: if the record should be kept, tell the user to move it with the Vectros API/SDK directly rather than deleting it here. A sub-folder cannot be re-parented at all, so nested folders have to be emptied and deleted innermost-first. Note the emptiness check counts everything in the folder, INCLUDING items your credential cannot read \u2014 so a refusal you cannot account for from what you can list is expected behaviour, not a bug, and retrying will not clear it. Requires the key to allow folders:d \u2014 a key without it gets a permission error. Protected folders (e.g. a context root) cannot be deleted at all, however empty.',
12246
12854
  inputSchema: inputSchema19,
12247
12855
  // Deletes. Idempotent in the standard REST sense: the end state ("this id no longer
12248
12856
  // resolves") is the same whether this is the first delete or a repeat of one.
@@ -12395,14 +13003,14 @@ var inputSchema21 = {
12395
13003
  // Common (both modes):
12396
13004
  folderId: import_zod21.z.string().optional().describe("Optional folder to ingest into. Default: tenant root."),
12397
13005
  userId: import_zod21.z.string().optional().describe("Owning user ID. Optional."),
12398
- scopes: import_zod21.z.array(import_zod21.z.string()).optional().describe(
13006
+ scopes: import_zod21.z.array(import_zod21.z.string()).max(MAX_OWNERSHIP_SCOPES, `scopes accepts at most ${MAX_OWNERSHIP_SCOPES} entries`).optional().describe(
12399
13007
  "TEXT MODE ONLY. Scope ownership as `namespace:value` entries, at most 2 (e.g. [\"org:<uuid>\", \"group:eng-team\"]). `org` and `client` are reserved namespace names, registered like any other; others are namespaces you registered yourself. This is the document's COMPLETE scope declaration and values must come from the credential's own identity. An empty array `[]` creates a PRIVATE document owned by the calling user alone. Omit to stamp the credential's full identity \u2014 the default. Rejected with `filePath` (file uploads do not accept a scope declaration): a file-uploaded document is stamped with the credential's full identity."
12400
13008
  )
12401
13009
  };
12402
13010
  var documentIngest = ({ client, log, transport, ingestRoot }) => ({
12403
13011
  name: "document_ingest",
12404
13012
  title: "Ingest a new document (text body or file upload)",
12405
- description: "Create a new document in your Vectros tenant. Two modes:\n \u2022 Text mode: pass `text` (string body). Single-call. Use for crawled content, notes, generated text.\n \u2022 File mode: pass `filePath` (local path on the MCP server's host machine). STDIO-TRANSPORT ONLY \u2014 rejected on HTTP transport. MCP server reads the bytes, requests a presigned upload URL, and PUTs them. Returns when the upload is accepted (indexStatus: PENDING_INDEX); poll `document_get` until indexStatus is INDEXED. EXCEPTION \u2014 re-ingesting file mode against an externalId that already has a document (response `created:false`): the file body is replaced by ANY such re-ingest, whether or not `upsert` was set (`upsert` there only additionally applies `payload`/`title` to the matched document). The document keeps serving the OLD file's bytes until the new one is adopted, and indexStatus already reads INDEXED left over from that old file, so polling it returns immediately without waiting for the new content. Poll `document_get` and watch `fileItemId` instead \u2014 once it differs from the value it held before this call, the new file has been adopted. Re-request any download URL after that: one minted before adoption can stop working even within its stated `downloadExpires`.\nEither `text` or `filePath` must be present; both is an error. Idempotent by `externalId` (re-ingest returns the existing document, not a duplicate \u2014 requires documents:r in addition to documents:c, since being handed the existing document is a read of it; in FILE MODE a re-ingest against an existing externalId needs documents:u). TEXT MODE: without `upsert`, the existing document's content is genuinely unchanged. FILE MODE: as noted above, a re-ingest against an existing externalId always replaces the file body regardless of `upsert` \u2014 only the `payload`/`title` metadata overwrite is gated by it. To UPDATE an existing document instead \u2014 re-index an edited body \u2014 pass `upsert:true` with the same `externalId` (and the same `schemaId`); this is the re-sync primitive for keeping a knowledge base current. Pass `schemaId` + `payload` for a typed, lookup-queryable document (records parity). An `externalId` with no `schemaId` is refused (400) unless you also pass `confirmUntyped:true` to confirm that an untyped document is intended. indexMode defaults to HYBRID for untyped documents (omit to inherit a bound schema's default). storeText is a FILE-MODE knob (default true): false discards the uploaded file's extracted text after indexing (search + file download keep working; text retrieval and document_ask do not). Text-mode bodies are always retained, so storeText is not accepted with `text`.",
13013
+ description: "Create a new document in your Vectros tenant. Two modes:\n \u2022 Text mode: pass `text` (string body). Single-call. Use for crawled content, notes, generated text.\n \u2022 File mode: pass `filePath` (local path on the MCP server's host machine). STDIO-TRANSPORT ONLY \u2014 rejected on HTTP transport. MCP server reads the bytes, requests a presigned upload URL, and PUTs them. Returns when the upload is accepted (indexStatus: PENDING_INDEX); poll `document_get` until indexStatus is terminal: INDEXED, SKIPPED (no indexable text: `extraction.outcome` says why, e.g. NO_TEXT for an image or a scanned page), STORED (indexMode NONE) or FAILED. EXCEPTION \u2014 re-ingesting file mode against an externalId that already has a document (response `created:false`): the file body is replaced by ANY such re-ingest, whether or not `upsert` was set (`upsert` there only additionally applies `payload`/`title` to the matched document). The document keeps serving the OLD file's bytes until the new one is adopted, and indexStatus already reads INDEXED left over from that old file, so polling it returns immediately without waiting for the new content. Poll `document_get` and watch `fileItemId` instead \u2014 once it differs from the value it held before this call, the new file has been adopted. Re-request any download URL after that: one minted before adoption can stop working even within its stated `downloadExpires`.\nEither `text` or `filePath` must be present; both is an error. Idempotent by `externalId` (re-ingest returns the existing document, not a duplicate \u2014 requires documents:r in addition to documents:c, since being handed the existing document is a read of it; in FILE MODE a re-ingest against an existing externalId needs documents:u). TEXT MODE: without `upsert`, the existing document's content is genuinely unchanged. FILE MODE: as noted above, a re-ingest against an existing externalId always replaces the file body regardless of `upsert` \u2014 only the `payload`/`title` metadata overwrite is gated by it. To UPDATE an existing document instead \u2014 re-index an edited body \u2014 pass `upsert:true` with the same `externalId` (and the same `schemaId`); this is the re-sync primitive for keeping a knowledge base current. Pass `schemaId` + `payload` for a typed, lookup-queryable document (records parity). An `externalId` with no `schemaId` is refused (400) unless you also pass `confirmUntyped:true` to confirm that an untyped document is intended. indexMode defaults to HYBRID for untyped documents (omit to inherit a bound schema's default). storeText is a FILE-MODE knob (default true): false discards the uploaded file's extracted text after indexing (search + file download keep working; text retrieval and document_ask do not). Text-mode bodies are always retained, so storeText is not accepted with `text`.",
12406
13014
  inputSchema: inputSchema21,
12407
13015
  // Creates by default, idempotent ONLY when the caller supplies `externalId` (optional,
12408
13016
  // per the doc comment above) — re-ingest then returns the existing document rather than
@@ -12544,7 +13152,7 @@ var documentIngest = ({ client, log, transport, ingestRoot }) => ({
12544
13152
  "document_ingest file ok"
12545
13153
  );
12546
13154
  const uploadCreated = upload?.created;
12547
- const note = uploadCreated === false ? "File replaced: this re-ingest matched an existing externalId, which always replaces that document's file body (upsert or not \u2014 upsert only additionally applies payload/title to it). The next document_get call may already show indexStatus: INDEXED \u2014 that is left over from the PREVIOUS file, not confirmation the new one is ready, and the document keeps serving the old file's bytes until adoption completes. Poll document_get(id) and watch fileItemId instead: once it differs from the value it held before this call, the new file has been adopted. Any download URL already held for this document was minted for the old file and can stop working before its stated downloadExpires once adoption happens \u2014 request a fresh one after fileItemId changes." : "File uploaded; indexing is asynchronous. Poll document_get(id) until indexStatus is INDEXED.";
13155
+ const note = uploadCreated === false ? "File replaced: this re-ingest matched an existing externalId, which always replaces that document's file body (upsert or not \u2014 upsert only additionally applies payload/title to it). The next document_get call may already show indexStatus: INDEXED \u2014 that is left over from the PREVIOUS file, not confirmation the new one is ready, and the document keeps serving the old file's bytes until adoption completes. Poll document_get(id) and watch fileItemId instead: once it differs from the value it held before this call, the new file has been adopted. Any download URL already held for this document was minted for the old file and can stop working before its stated downloadExpires once adoption happens \u2014 request a fresh one after fileItemId changes." : "File uploaded; indexing is asynchronous. Poll document_get(id) until indexStatus is INDEXED, SKIPPED (no indexable text; see extraction.outcome), STORED or FAILED.";
12548
13156
  return {
12549
13157
  content: [
12550
13158
  {
@@ -12717,6 +13325,365 @@ var versionHistory = ({ client, log }) => ({
12717
13325
  });
12718
13326
  var version_history_default = versionHistory;
12719
13327
 
13328
+ // src/tools/agent_list.ts
13329
+ var import_zod24 = require("zod");
13330
+ var MCP_DEFAULT_LIMIT6 = 10;
13331
+ var MCP_MAX_LIMIT6 = 100;
13332
+ function toAgentSummary(agent) {
13333
+ return {
13334
+ id: agent.id,
13335
+ name: agent.name,
13336
+ description: agent.description,
13337
+ latestVersion: agent.latestVersion,
13338
+ status: agent.status
13339
+ };
13340
+ }
13341
+ var inputSchema24 = {
13342
+ includeRetired: import_zod24.z.boolean().optional().describe("Also list retired and purged agents (neither can be run). Default false."),
13343
+ startFrom: import_zod24.z.string().optional().describe("Pagination cursor: pass the `nextCursor` from the previous page to fetch the next."),
13344
+ limit: import_zod24.z.number().int().min(1).max(MCP_MAX_LIMIT6).optional().describe(`Max agents per page. Default ${MCP_DEFAULT_LIMIT6}, max ${MCP_MAX_LIMIT6}.`)
13345
+ };
13346
+ var agentList = ({ client, log }) => ({
13347
+ name: "agent_list",
13348
+ title: "List agents",
13349
+ description: "List the stored agents you can run with agent_run, newest first. Each is returned as its `id`, `name`, `description`, `latestVersion` and `status`; only an `ACTIVE` agent can be run. Retired and purged agents are left out unless `includeRetired` is true. Returns a `{ data, nextCursor }` page: a non-null `nextCursor` means more remain, pass it back as `startFrom`. Needs the `runs:c` or `agents:r` scope; running a listed agent needs `runs:c`, so a credential with only `agents:r` can list agents but not run them.",
13350
+ inputSchema: inputSchema24,
13351
+ // A pure read: it lists definitions and changes nothing.
13352
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true },
13353
+ handler: async (args) => {
13354
+ const limit = args.limit ?? MCP_DEFAULT_LIMIT6;
13355
+ try {
13356
+ const page = await client.agents.listAgents({
13357
+ includeRetired: args.includeRetired,
13358
+ startFrom: args.startFrom,
13359
+ limit
13360
+ });
13361
+ const data = (page.data ?? []).map(toAgentSummary);
13362
+ const nextCursor = page.nextCursor ?? null;
13363
+ log.debug({ tool: "agent_list", limit, returned: data.length }, "agent_list ok");
13364
+ return { content: [{ type: "text", text: JSON.stringify({ data, nextCursor }, null, 2) }] };
13365
+ } catch (err) {
13366
+ log.warn({ tool: "agent_list", err: String(err) }, "agent_list failed");
13367
+ return toolError("agent_list", err);
13368
+ }
13369
+ }
13370
+ });
13371
+ var agent_list_default = agentList;
13372
+
13373
+ // src/tools/agent_run.ts
13374
+ var import_node_crypto = require("crypto");
13375
+ var import_zod25 = require("zod");
13376
+
13377
+ // src/run-stream.ts
13378
+ var TEXT_PROGRESS_CHARS = 256;
13379
+ var HEARTBEAT_MS = 15e3;
13380
+ var TERMINAL_STATUS = {
13381
+ "run.completed": "COMPLETED",
13382
+ "run.failed": "FAILED",
13383
+ "run.cancelled": "CANCELLED"
13384
+ };
13385
+ function str(v) {
13386
+ return typeof v === "string" && v.length > 0 ? v : void 0;
13387
+ }
13388
+ function num(v) {
13389
+ return typeof v === "number" && Number.isFinite(v) ? v : void 0;
13390
+ }
13391
+ async function consumeRunStream(stream, initialRunId, onProgress, heartbeatMs = HEARTBEAT_MS) {
13392
+ const result = {
13393
+ runId: initialRunId,
13394
+ terminal: false,
13395
+ status: "UNKNOWN",
13396
+ text: "",
13397
+ toolCalls: []
13398
+ };
13399
+ const blocks = [];
13400
+ let pending = "";
13401
+ let unsentChars = 0;
13402
+ const emit = async (message) => {
13403
+ if (!onProgress) return;
13404
+ try {
13405
+ await onProgress(message);
13406
+ } catch {
13407
+ }
13408
+ };
13409
+ let heartbeat;
13410
+ let lastEventAt = Date.now();
13411
+ if (onProgress) {
13412
+ heartbeat = setInterval(() => {
13413
+ if (Date.now() - lastEventAt >= heartbeatMs) {
13414
+ lastEventAt = Date.now();
13415
+ void emit("run still working");
13416
+ }
13417
+ }, Math.max(1, Math.floor(heartbeatMs / 3)));
13418
+ heartbeat.unref?.();
13419
+ }
13420
+ try {
13421
+ for await (const raw of stream) {
13422
+ lastEventAt = Date.now();
13423
+ if (!raw || typeof raw !== "object") continue;
13424
+ const ev = raw;
13425
+ result.runId ??= str(ev.runId);
13426
+ const type = typeof ev.type === "string" ? ev.type : "";
13427
+ switch (type) {
13428
+ case "run.started":
13429
+ result.agentId = str(ev.agentId) ?? result.agentId;
13430
+ result.agentVersion = num(ev.agentVersion) ?? result.agentVersion;
13431
+ await emit("run started");
13432
+ break;
13433
+ case "message.delta": {
13434
+ const piece = typeof ev.text === "string" ? ev.text : "";
13435
+ pending += piece;
13436
+ unsentChars += piece.length;
13437
+ if (unsentChars >= TEXT_PROGRESS_CHARS) {
13438
+ unsentChars = 0;
13439
+ await emit(`answer: ${blocks.join("\n\n").length + pending.length} characters so far`);
13440
+ }
13441
+ break;
13442
+ }
13443
+ case "message.completed": {
13444
+ const full = str(ev.text) ?? pending;
13445
+ if (full.length > 0) blocks.push(full);
13446
+ pending = "";
13447
+ unsentChars = 0;
13448
+ await emit("model call completed");
13449
+ break;
13450
+ }
13451
+ case "tool.completed": {
13452
+ const call = {
13453
+ tool: str(ev.tool),
13454
+ outcome: str(ev.outcome),
13455
+ code: str(ev.code)
13456
+ };
13457
+ result.toolCalls.push(call);
13458
+ await emit(`tool ${call.tool ?? "call"}: ${call.outcome ?? "ended"}`);
13459
+ break;
13460
+ }
13461
+ default:
13462
+ break;
13463
+ }
13464
+ if (ev.terminal === true || Object.hasOwn(TERMINAL_STATUS, type)) {
13465
+ result.terminal = true;
13466
+ result.status = str(ev.status) ?? TERMINAL_STATUS[type] ?? "ENDED";
13467
+ result.reason = str(ev.reason);
13468
+ result.errorCode = str(ev.errorCode);
13469
+ if (typeof ev.settled === "boolean" || ev.inferenceBalanceCentsChargedMilli !== void 0 || ev.inferenceBalanceCentsRefundedMilli !== void 0) {
13470
+ result.charged = {
13471
+ settled: typeof ev.settled === "boolean" ? ev.settled : void 0,
13472
+ inferenceBalanceCentsChargedMilli: num(ev.inferenceBalanceCentsChargedMilli),
13473
+ inferenceBalanceCentsRefundedMilli: num(ev.inferenceBalanceCentsRefundedMilli)
13474
+ };
13475
+ }
13476
+ break;
13477
+ }
13478
+ }
13479
+ } catch (err) {
13480
+ result.streamError = err instanceof Error ? err.message : String(err);
13481
+ } finally {
13482
+ if (heartbeat) clearInterval(heartbeat);
13483
+ }
13484
+ if (pending.length > 0) blocks.push(pending);
13485
+ result.text = blocks.join("\n\n");
13486
+ return result;
13487
+ }
13488
+
13489
+ // src/tools/agent_run.ts
13490
+ var RUN_ID_HEADER = "x-vectros-run-id";
13491
+ var MAX_INPUT_CHARS = 1e5;
13492
+ var MAX_INPUT_BYTES = 24e4;
13493
+ function encodedInputBytes(v) {
13494
+ return Buffer.byteLength(JSON.stringify(v), "utf8");
13495
+ }
13496
+ var TERMINAL_EVENT_TYPES = /* @__PURE__ */ new Set(["run.completed", "run.failed", "run.cancelled"]);
13497
+ var ENDED_STATUSES = /* @__PURE__ */ new Set(["COMPLETED", "FAILED", "CANCELLED", "EXPIRED"]);
13498
+ var inputSchema25 = {
13499
+ agentId: import_zod25.z.string().min(1, "agentId must be non-empty").describe("The agent to run: an `id` from agent_list."),
13500
+ input: import_zod25.z.string().min(1, "input must be non-empty").max(MAX_INPUT_CHARS, `input accepts at most ${MAX_INPUT_CHARS} characters`).refine(
13501
+ (v) => encodedInputBytes(v) <= MAX_INPUT_BYTES,
13502
+ `input accepts at most ${MAX_INPUT_BYTES} bytes as sent (a JSON string in UTF-8)`
13503
+ ).describe(
13504
+ `What the agent is asked, 1 to ${MAX_INPUT_CHARS} characters and at most ${MAX_INPUT_BYTES} bytes as sent (a JSON string in UTF-8; most control characters other than newline and tab count six bytes).`
13505
+ ),
13506
+ agentVersion: import_zod25.z.number().int().min(1).optional().describe("The agent version to run. Default: its latest version."),
13507
+ maxInferenceCents: import_zod25.z.number().int().min(1).optional().describe(
13508
+ "The most this run's model calls may cost, in US cents. It can only lower the agent's own budget (a higher value is refused); a value below the platform minimum is refused with errorCode `BUDGET_TOO_LOW`, whose message names the minimum. Default: the agent's budget. A run that reaches it ends `FAILED` with errorCode `BUDGET_EXCEEDED`."
13509
+ ),
13510
+ readOnly: import_zod25.z.boolean().optional().describe("When true, every tool call that would change data is refused in this run. Default false."),
13511
+ idempotencyKey: import_zod25.z.string().regex(/^[A-Za-z0-9._:-]{1,128}$/, "idempotencyKey is 1 to 128 letters, digits, `.`, `_`, `:` or `-`").optional().describe(
13512
+ "Makes a retried call safe: the same key with the same arguments never starts a second run; the retry returns that run's id and status (`alreadyStarted: true`) instead. Its answer text is not returned again; read how it ended with run_get. Default: a new key per call."
13513
+ )
13514
+ };
13515
+ var agentRun = ({ client, log }) => ({
13516
+ name: "agent_run",
13517
+ title: "Run an agent",
13518
+ description: "Run a stored agent (from agent_list) on one `input` and return its answer. The agent's tool calls act as you, with your own permissions, and only through the tools the agent lists; set `readOnly` to refuse every tool call that would change data. Cap the run's model cost with `maxInferenceCents` (it can only lower the agent's own budget). The run is billed: model calls against your inference balance, and a fee per run, tool calls and run time against your plan. An agent can search the web or fetch a page when its definition lists that web tool (web fetch also needs your tenant's owner to switch it on, and a run of an agent that lists `web_search` is refused while the platform has web search disabled). Returns `{ runId, agentId, agentVersion, status, terminal, reason, errorCode, text, toolCalls, charged }`; `charged` carries the run's charge and refund in milli-cents (1 cent = 1000). Progress notifications keep the call alive while the run works for a client that resets its timeout on progress; cancelling the call cancels the run once the run is named (almost at once). If `terminal` is false the result arrived before the run ended: read it with run_get, which needs `runs:r` as well. Calling again without `idempotencyKey` starts a new, billed run. Needs the `runs:c` scope.",
13519
+ inputSchema: inputSchema25,
13520
+ // Not a read: a run is billed, and its tool calls may create, change or delete data with the
13521
+ // caller's permissions, so a host should confirm it. Not idempotent: each call is a new paid run
13522
+ // unless the same idempotencyKey is passed again.
13523
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
13524
+ handler: async (args, extra) => {
13525
+ const agentId = args.agentId;
13526
+ const maxInferenceCents = args.maxInferenceCents;
13527
+ const idempotencyKey = args.idempotencyKey ?? (0, import_node_crypto.randomUUID)();
13528
+ const request = {
13529
+ "Idempotency-Key": idempotencyKey,
13530
+ agentId,
13531
+ agentVersion: args.agentVersion,
13532
+ input: { text: args.input },
13533
+ budget: maxInferenceCents !== void 0 ? { maxInferenceCents } : void 0,
13534
+ readOnly: args.readOnly
13535
+ };
13536
+ const progressToken = extra._meta?.progressToken;
13537
+ let progressCount = 0;
13538
+ const onProgress = progressToken !== void 0 && extra.sendNotification ? async (message) => {
13539
+ progressCount += 1;
13540
+ await extra.sendNotification({
13541
+ method: "notifications/progress",
13542
+ params: { progressToken, progress: progressCount, message }
13543
+ });
13544
+ } : void 0;
13545
+ const streamAbort = new AbortController();
13546
+ const callSignal = extra.signal;
13547
+ let knownRunId;
13548
+ let headersReceived = false;
13549
+ let cancelRequested = false;
13550
+ let cancelSent = false;
13551
+ let runEnded = false;
13552
+ const sendCancel = () => {
13553
+ if (!cancelRequested || cancelSent || !knownRunId || runEnded) return;
13554
+ cancelSent = true;
13555
+ const id = knownRunId;
13556
+ client.agents.cancelRun({ id }).then(
13557
+ () => log.info({ tool: "agent_run", runId: id }, "agent_run cancelled by the client"),
13558
+ (err) => log.warn({ tool: "agent_run", runId: id, err: String(err) }, "agent_run cancel failed")
13559
+ );
13560
+ };
13561
+ const cancelIfNamed = () => {
13562
+ if (!cancelRequested || !headersReceived || !knownRunId) return;
13563
+ sendCancel();
13564
+ streamAbort.abort();
13565
+ };
13566
+ const onCancel = () => {
13567
+ cancelRequested = true;
13568
+ cancelIfNamed();
13569
+ };
13570
+ if (callSignal?.aborted) {
13571
+ return toolError("agent_run", new Error("The call was cancelled before the run started."));
13572
+ }
13573
+ callSignal?.addEventListener("abort", onCancel, { once: true });
13574
+ try {
13575
+ const { data: stream, rawResponse } = await client.agents.createRun(request, { abortSignal: streamAbort.signal }).withRawResponse();
13576
+ headersReceived = true;
13577
+ knownRunId = rawResponse.headers.get(RUN_ID_HEADER) ?? void 0;
13578
+ cancelIfNamed();
13579
+ const naming = async function* () {
13580
+ for await (const ev of stream) {
13581
+ if (!knownRunId && ev && typeof ev === "object") {
13582
+ const id = ev.runId;
13583
+ if (typeof id === "string" && id.length > 0) {
13584
+ knownRunId = id;
13585
+ cancelIfNamed();
13586
+ }
13587
+ }
13588
+ if (ev && typeof ev === "object") {
13589
+ const e = ev;
13590
+ if (e.terminal === true || typeof e.type === "string" && TERMINAL_EVENT_TYPES.has(e.type)) runEnded = true;
13591
+ }
13592
+ yield ev;
13593
+ }
13594
+ };
13595
+ const run = await consumeRunStream(naming(), knownRunId, onProgress);
13596
+ knownRunId ??= run.runId;
13597
+ if (run.terminal) runEnded = true;
13598
+ sendCancel();
13599
+ log.debug(
13600
+ {
13601
+ tool: "agent_run",
13602
+ runId: run.runId,
13603
+ status: run.status,
13604
+ terminal: run.terminal,
13605
+ toolCalls: run.toolCalls.length,
13606
+ textLength: run.text.length
13607
+ },
13608
+ "agent_run ok"
13609
+ );
13610
+ const body = {
13611
+ runId: run.runId,
13612
+ agentId: run.agentId ?? agentId,
13613
+ agentVersion: run.agentVersion,
13614
+ status: run.status,
13615
+ terminal: run.terminal,
13616
+ reason: run.reason,
13617
+ errorCode: run.errorCode,
13618
+ text: run.text,
13619
+ toolCalls: run.toolCalls,
13620
+ charged: run.charged
13621
+ };
13622
+ if (!run.terminal) {
13623
+ body.note = cancelRequested ? "The call was cancelled and the run was asked to stop. Read it with run_get (needs the `runs:r` scope) to see how it ended." : "The stream ended before the run did" + (run.streamError ? ` (${run.streamError})` : "") + ". The run may still be working: read it with run_get until `terminal` is true (run_get needs the `runs:r` scope).";
13624
+ }
13625
+ return { content: [{ type: "text", text: JSON.stringify(body, null, 2) }] };
13626
+ } catch (err) {
13627
+ const e = err;
13628
+ if (e?.body?.errorCode === "IDEMPOTENCY_IN_PROGRESS") {
13629
+ const runId = (typeof e.body.runId === "string" ? e.body.runId : void 0) ?? e.rawResponse?.headers?.get?.(RUN_ID_HEADER) ?? void 0;
13630
+ if (runId) {
13631
+ const status = typeof e.body.status === "string" ? e.body.status : void 0;
13632
+ log.info({ tool: "agent_run", runId }, "agent_run: the idempotency key already started a run");
13633
+ const body = {
13634
+ runId,
13635
+ agentId,
13636
+ status,
13637
+ // The 409 names the run's status at the time; an ended status is final.
13638
+ terminal: status !== void 0 && ENDED_STATUSES.has(status),
13639
+ alreadyStarted: true,
13640
+ note: "This idempotency key already started this run, so no new run was started. Its answer text is not returned again and cannot be read back: run_get (needs the `runs:r` scope) shows how the run ended and what it was charged, never its text. To start another run, pass a new idempotencyKey."
13641
+ };
13642
+ return { content: [{ type: "text", text: JSON.stringify(body, null, 2) }] };
13643
+ }
13644
+ }
13645
+ log.warn({ tool: "agent_run", agentId, err: String(err) }, "agent_run failed");
13646
+ const result = toolError("agent_run", err);
13647
+ const statusCode = err?.statusCode;
13648
+ if (typeof statusCode !== "number" || statusCode === 408 || statusCode >= 500) {
13649
+ result.content[0].text += `
13650
+ idempotencyKey: ${idempotencyKey}
13651
+ A run may have started before this error. Call agent_run again with the same arguments and this idempotencyKey: if a run started, the call names it; if not, it starts one.` + (cancelRequested ? " (The call was cancelled; a run that started could not be cancelled.)" : "");
13652
+ }
13653
+ return result;
13654
+ } finally {
13655
+ callSignal?.removeEventListener("abort", onCancel);
13656
+ }
13657
+ }
13658
+ });
13659
+ var agent_run_default = agentRun;
13660
+
13661
+ // src/tools/run_get.ts
13662
+ var import_zod26 = require("zod");
13663
+ var inputSchema26 = {
13664
+ runId: import_zod26.z.string().min(1, "runId must be non-empty").describe("The run id agent_run returned (`runId`).")
13665
+ };
13666
+ var runGet = ({ client, log }) => ({
13667
+ name: "run_get",
13668
+ title: "Get an agent run",
13669
+ description: "Read one agent run by id: `status` (`RUNNING`, `COMPLETED`, `FAILED`, `CANCELLED` or `EXPIRED`), `terminal` (whether it has ended; poll until true), `reason`, `errorCode`, `steps`, its `toolCalls` (each tool and how it ended, never its arguments or result) and `usage` (what it was charged, in milli-cents). It does not return the answer text: agent_run returns that. Use it when agent_run returned `terminal: false`. Needs the `runs:r` scope, which starting a run (`runs:c`) does not include: a credential with only `runs:c` gets `403` here, and learns how its runs end only from agent_run's own result.",
13670
+ inputSchema: inputSchema26,
13671
+ // A pure read: polling a run does not change it.
13672
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true },
13673
+ handler: async (args) => {
13674
+ const runId = args.runId;
13675
+ try {
13676
+ const run = await client.agents.getRun({ id: runId });
13677
+ log.debug({ tool: "run_get", runId, status: run.status, terminal: run.terminal }, "run_get ok");
13678
+ return { content: [{ type: "text", text: JSON.stringify(run, null, 2) }] };
13679
+ } catch (err) {
13680
+ log.warn({ tool: "run_get", runId, err: String(err) }, "run_get failed");
13681
+ return toolError("run_get", err);
13682
+ }
13683
+ }
13684
+ });
13685
+ var run_get_default = runGet;
13686
+
12720
13687
  // src/tools/types.ts
12721
13688
  var TOOL_NAMES = [
12722
13689
  "hybrid_search",
@@ -12741,7 +13708,10 @@ var TOOL_NAMES = [
12741
13708
  "current_identity",
12742
13709
  "document_ingest",
12743
13710
  "lookup_principal",
12744
- "version_history"
13711
+ "version_history",
13712
+ "agent_list",
13713
+ "agent_run",
13714
+ "run_get"
12745
13715
  ];
12746
13716
 
12747
13717
  // src/tools/index.ts
@@ -12768,7 +13738,10 @@ var ALL_TOOL_FACTORIES = {
12768
13738
  current_identity: current_identity_default,
12769
13739
  document_ingest: document_ingest_default,
12770
13740
  lookup_principal: lookup_principal_default,
12771
- version_history: version_history_default
13741
+ version_history: version_history_default,
13742
+ agent_list: agent_list_default,
13743
+ agent_run: agent_run_default,
13744
+ run_get: run_get_default
12772
13745
  };
12773
13746
 
12774
13747
  // src/resources/schemas.ts
@@ -12811,11 +13784,12 @@ var ALL_RESOURCE_FACTORIES = {
12811
13784
  };
12812
13785
 
12813
13786
  // src/zod-to-json-schema.ts
12814
- var import_zod24 = require("zod");
13787
+ var import_zod27 = require("zod");
12815
13788
  function zodShapeToJsonSchema(shape) {
12816
13789
  const properties = {};
12817
13790
  const required = [];
12818
- for (const [name, schema] of Object.entries(shape)) {
13791
+ for (const [name, entry] of Object.entries(shape)) {
13792
+ const schema = entry;
12819
13793
  properties[name] = zodTypeToJsonSchema(schema);
12820
13794
  if (!schema.isOptional()) required.push(name);
12821
13795
  }
@@ -12824,43 +13798,45 @@ function zodShapeToJsonSchema(shape) {
12824
13798
  return out;
12825
13799
  }
12826
13800
  function zodTypeToJsonSchema(schema) {
12827
- const description = schema.description;
13801
+ const descriptionOf = (s) => s.description;
13802
+ let description = descriptionOf(schema);
12828
13803
  let current = schema;
12829
- while (current instanceof import_zod24.z.ZodOptional || current instanceof import_zod24.z.ZodDefault || current instanceof import_zod24.z.ZodNullable) {
13804
+ while (current instanceof import_zod27.z.ZodOptional || current instanceof import_zod27.z.ZodDefault || current instanceof import_zod27.z.ZodNullable) {
12830
13805
  current = current._def.innerType;
13806
+ description ??= descriptionOf(current);
12831
13807
  }
12832
13808
  const base = description ? { description } : {};
12833
- if (current instanceof import_zod24.z.ZodString) {
13809
+ if (current instanceof import_zod27.z.ZodString) {
12834
13810
  return { ...base, type: "string" };
12835
13811
  }
12836
- if (current instanceof import_zod24.z.ZodNumber) {
13812
+ if (current instanceof import_zod27.z.ZodNumber) {
12837
13813
  return { ...base, type: "number" };
12838
13814
  }
12839
- if (current instanceof import_zod24.z.ZodBoolean) {
13815
+ if (current instanceof import_zod27.z.ZodBoolean) {
12840
13816
  return { ...base, type: "boolean" };
12841
13817
  }
12842
- if (current instanceof import_zod24.z.ZodEnum) {
13818
+ if (current instanceof import_zod27.z.ZodEnum) {
12843
13819
  return {
12844
13820
  ...base,
12845
13821
  type: "string",
12846
13822
  enum: current.options
12847
13823
  };
12848
13824
  }
12849
- if (current instanceof import_zod24.z.ZodArray) {
13825
+ if (current instanceof import_zod27.z.ZodArray) {
12850
13826
  return {
12851
13827
  ...base,
12852
13828
  type: "array",
12853
13829
  items: zodTypeToJsonSchema(current.element)
12854
13830
  };
12855
13831
  }
12856
- if (current instanceof import_zod24.z.ZodObject) {
13832
+ if (current instanceof import_zod27.z.ZodObject) {
12857
13833
  return {
12858
13834
  ...base,
12859
13835
  ...zodShapeToJsonSchema(current.shape)
12860
13836
  };
12861
13837
  }
12862
- if (current instanceof import_zod24.z.ZodRecord) {
12863
- const valueType = current._def.valueType;
13838
+ if (current instanceof import_zod27.z.ZodRecord) {
13839
+ const valueType = current.valueType;
12864
13840
  return {
12865
13841
  ...base,
12866
13842
  type: "object",
@@ -12988,7 +13964,7 @@ var VectrosMCPServer = class {
12988
13964
  if (!tool) {
12989
13965
  result = toolError(req.params.name ?? "unknown", new Error("No such tool."));
12990
13966
  } else {
12991
- const parsed = import_zod25.z.object(tool.inputSchema).strict().safeParse(req.params.arguments ?? {});
13967
+ const parsed = import_zod28.z.object(tool.inputSchema).strict().safeParse(req.params.arguments ?? {});
12992
13968
  if (!parsed.success) {
12993
13969
  result = toolError(tool.name, new Error(formatArgError(tool, parsed.error)));
12994
13970
  } else {
@@ -13051,7 +14027,7 @@ var VectrosMCPServer = class {
13051
14027
  *
13052
14028
  * If `validateOnStart` (default true) is enabled, performs a
13053
14029
  * GET /v1/ping check BEFORE wiring the transport. On failure,
13054
- * throws — the partner's MCP client sees a startup error instead
14030
+ * throws — your MCP client sees a startup error instead
13055
14031
  * of a confusing "tools work but the first call 401s" experience.
13056
14032
  */
13057
14033
  async connect(transport) {