@seclai/sdk 1.0.7 → 1.1.1

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/index.cjs CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -25,7 +35,8 @@ __export(index_exports, {
25
35
  SeclaiAPIStatusError: () => SeclaiAPIStatusError,
26
36
  SeclaiAPIValidationError: () => SeclaiAPIValidationError,
27
37
  SeclaiConfigurationError: () => SeclaiConfigurationError,
28
- SeclaiError: () => SeclaiError
38
+ SeclaiError: () => SeclaiError,
39
+ SeclaiStreamingError: () => SeclaiStreamingError
29
40
  });
30
41
  module.exports = __toCommonJS(index_exports);
31
42
 
@@ -69,10 +80,293 @@ var SeclaiAPIValidationError = class extends SeclaiAPIStatusError {
69
80
  this.validationError = opts.validationError;
70
81
  }
71
82
  };
83
+ var SeclaiStreamingError = class extends SeclaiError {
84
+ /** The run ID associated with the failed stream, when available. */
85
+ runId;
86
+ constructor(message, runId) {
87
+ super(message);
88
+ this.name = "SeclaiStreamingError";
89
+ this.runId = runId;
90
+ }
91
+ };
92
+
93
+ // src/auth.ts
94
+ var DEFAULT_CONFIG_DIR = ".seclai";
95
+ var SSO_CACHE_DIR = "sso/cache";
96
+ var CONFIG_FILE = "config";
97
+ var EXPIRY_BUFFER_MS = 3e4;
98
+ var DEFAULT_API_KEY_HEADER = "x-api-key";
99
+ function getEnv(name) {
100
+ const p = globalThis?.process;
101
+ return p?.env?.[name];
102
+ }
103
+ function getHomeDir() {
104
+ const p = globalThis?.process;
105
+ return p?.env?.HOME ?? p?.env?.USERPROFILE;
106
+ }
107
+ async function sha1Hex(input) {
108
+ try {
109
+ const { createHash } = await import("crypto");
110
+ return createHash("sha1").update(input).digest("hex");
111
+ } catch {
112
+ const encoded = new TextEncoder().encode(input);
113
+ const buffer = await crypto.subtle.digest("SHA-1", encoded);
114
+ return Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
115
+ }
116
+ }
117
+ async function cacheFileName(domain, clientId) {
118
+ return sha1Hex(`${domain}|${clientId}`);
119
+ }
120
+ function parseIni(content) {
121
+ const sections = {};
122
+ let currentSection = null;
123
+ for (const rawLine of content.split(/\r?\n/)) {
124
+ const line = rawLine.trim();
125
+ if (!line || line.startsWith("#") || line.startsWith(";")) continue;
126
+ const sectionMatch = line.match(/^\[(.+)\]$/);
127
+ if (sectionMatch) {
128
+ const raw = sectionMatch[1].trim();
129
+ currentSection = raw.startsWith("profile ") ? raw.slice("profile ".length).trim() : raw;
130
+ sections[currentSection] ??= {};
131
+ continue;
132
+ }
133
+ if (currentSection !== null) {
134
+ const eqIdx = line.indexOf("=");
135
+ if (eqIdx > 0) {
136
+ const key = line.slice(0, eqIdx).trim();
137
+ const value = line.slice(eqIdx + 1).trim();
138
+ sections[currentSection][key] = value;
139
+ }
140
+ }
141
+ }
142
+ return sections;
143
+ }
144
+ var _fs = null;
145
+ var _path = null;
146
+ async function getFs() {
147
+ if (!_fs) {
148
+ _fs = await import("fs");
149
+ }
150
+ return _fs;
151
+ }
152
+ async function getPath() {
153
+ if (!_path) {
154
+ _path = await import("path");
155
+ }
156
+ return _path;
157
+ }
158
+ async function resolveConfigDir(override) {
159
+ if (override) return override;
160
+ const envDir = getEnv("SECLAI_CONFIG_DIR");
161
+ if (envDir) return envDir;
162
+ const home = getHomeDir();
163
+ if (!home) {
164
+ throw new Error("Cannot determine home directory. Set SECLAI_CONFIG_DIR.");
165
+ }
166
+ const pathMod = await getPath();
167
+ return pathMod.join(home, DEFAULT_CONFIG_DIR);
168
+ }
169
+ async function loadSsoProfile(configDir, profileName) {
170
+ const fs = await getFs();
171
+ const pathMod = await getPath();
172
+ const configPath = pathMod.join(configDir, CONFIG_FILE);
173
+ if (!fs.existsSync(configPath)) return null;
174
+ const content = fs.readFileSync(configPath, "utf-8");
175
+ const sections = parseIni(content);
176
+ const defaultSection = sections["default"] ?? {};
177
+ const profileSection = profileName === "default" ? defaultSection : sections[profileName];
178
+ if (!profileSection) return null;
179
+ const merged = profileName === "default" ? profileSection : { ...defaultSection, ...profileSection };
180
+ const ssoAccountId = merged["sso_account_id"];
181
+ const ssoRegion = merged["sso_region"];
182
+ const ssoClientId = merged["sso_client_id"];
183
+ const ssoDomain = merged["sso_domain"];
184
+ if (!ssoAccountId || !ssoRegion || !ssoClientId || !ssoDomain) return null;
185
+ return { ssoAccountId, ssoRegion, ssoClientId, ssoDomain };
186
+ }
187
+ async function resolveCachePath(configDir, profile) {
188
+ const pathMod = await getPath();
189
+ const hash = await cacheFileName(profile.ssoDomain, profile.ssoClientId);
190
+ return pathMod.join(configDir, SSO_CACHE_DIR, `${hash}.json`);
191
+ }
192
+ async function readSsoCache(configDir, profile) {
193
+ const fs = await getFs();
194
+ const cachePath = await resolveCachePath(configDir, profile);
195
+ if (!fs.existsSync(cachePath)) return null;
196
+ try {
197
+ const raw = fs.readFileSync(cachePath, "utf-8");
198
+ return JSON.parse(raw);
199
+ } catch {
200
+ return null;
201
+ }
202
+ }
203
+ async function writeSsoCache(configDir, profile, entry) {
204
+ const fs = await getFs();
205
+ const pathMod = await getPath();
206
+ const cacheDir = pathMod.join(configDir, SSO_CACHE_DIR);
207
+ fs.mkdirSync(cacheDir, { recursive: true, mode: 448 });
208
+ const cachePath = await resolveCachePath(configDir, profile);
209
+ const tmpPath = `${cachePath}.tmp`;
210
+ fs.writeFileSync(tmpPath, JSON.stringify(entry, null, 2), { mode: 384 });
211
+ if (fs.existsSync(cachePath)) {
212
+ try {
213
+ fs.unlinkSync(cachePath);
214
+ } catch {
215
+ }
216
+ }
217
+ fs.renameSync(tmpPath, cachePath);
218
+ }
219
+ function isTokenValid(entry) {
220
+ const expiresAt = new Date(entry.expiresAt).getTime();
221
+ return Date.now() + EXPIRY_BUFFER_MS < expiresAt;
222
+ }
223
+ async function refreshToken(profile, refreshTokenValue, fetcher) {
224
+ const tokenUrl = `https://${profile.ssoDomain}/oauth2/token`;
225
+ const body = new URLSearchParams({
226
+ grant_type: "refresh_token",
227
+ client_id: profile.ssoClientId,
228
+ refresh_token: refreshTokenValue
229
+ });
230
+ const response = await fetcher(tokenUrl, {
231
+ method: "POST",
232
+ headers: { "content-type": "application/x-www-form-urlencoded" },
233
+ body: body.toString()
234
+ });
235
+ if (!response.ok) {
236
+ const text = await response.text().catch(() => "");
237
+ throw new Error(`Token refresh failed (HTTP ${response.status}): ${text}`);
238
+ }
239
+ const data = await response.json();
240
+ const expiresAt = new Date(Date.now() + data.expires_in * 1e3).toISOString();
241
+ return {
242
+ accessToken: data.access_token,
243
+ refreshToken: data.refresh_token ?? refreshTokenValue,
244
+ idToken: data.id_token ?? void 0,
245
+ expiresAt,
246
+ clientId: profile.ssoClientId,
247
+ region: profile.ssoRegion,
248
+ cognitoDomain: profile.ssoDomain
249
+ };
250
+ }
251
+ async function resolveCredentialChain(opts) {
252
+ const apiKeyHeader = opts.apiKeyHeader ?? DEFAULT_API_KEY_HEADER;
253
+ if (opts.apiKey) {
254
+ return {
255
+ mode: "apiKey",
256
+ apiKey: opts.apiKey,
257
+ apiKeyHeader,
258
+ accountId: opts.accountId,
259
+ autoRefresh: false
260
+ };
261
+ }
262
+ if (opts.accessToken) {
263
+ return {
264
+ mode: "bearerStatic",
265
+ accessToken: opts.accessToken,
266
+ apiKeyHeader,
267
+ accountId: opts.accountId,
268
+ autoRefresh: false
269
+ };
270
+ }
271
+ if (opts.accessTokenProvider) {
272
+ return {
273
+ mode: "bearerProvider",
274
+ accessTokenProvider: opts.accessTokenProvider,
275
+ apiKeyHeader,
276
+ accountId: opts.accountId,
277
+ autoRefresh: false
278
+ };
279
+ }
280
+ const envApiKey = getEnv("SECLAI_API_KEY");
281
+ if (envApiKey) {
282
+ return {
283
+ mode: "apiKey",
284
+ apiKey: envApiKey,
285
+ apiKeyHeader,
286
+ accountId: opts.accountId,
287
+ autoRefresh: false
288
+ };
289
+ }
290
+ try {
291
+ const configDir = await resolveConfigDir(opts.configDir);
292
+ const profileName = opts.profile ?? getEnv("SECLAI_PROFILE") ?? "default";
293
+ const ssoProfile = await loadSsoProfile(configDir, profileName);
294
+ if (ssoProfile) {
295
+ return {
296
+ mode: "sso",
297
+ apiKeyHeader,
298
+ accountId: opts.accountId ?? ssoProfile.ssoAccountId,
299
+ ssoProfile,
300
+ configDir,
301
+ autoRefresh: opts.autoRefresh !== false,
302
+ fetcher: opts.fetch
303
+ };
304
+ }
305
+ } catch {
306
+ }
307
+ throw new Error(
308
+ "Missing credentials. Provide apiKey, accessToken, set SECLAI_API_KEY, or run `seclai auth login`."
309
+ );
310
+ }
311
+ async function resolveAuthHeaders(state) {
312
+ const headers = {};
313
+ switch (state.mode) {
314
+ case "apiKey":
315
+ headers[state.apiKeyHeader] = state.apiKey;
316
+ break;
317
+ case "bearerStatic":
318
+ headers["authorization"] = `Bearer ${state.accessToken}`;
319
+ break;
320
+ case "bearerProvider": {
321
+ const token = await Promise.resolve(state.accessTokenProvider());
322
+ headers["authorization"] = `Bearer ${token}`;
323
+ break;
324
+ }
325
+ case "sso": {
326
+ const token = await resolveSsoToken(state);
327
+ headers["authorization"] = `Bearer ${token}`;
328
+ break;
329
+ }
330
+ }
331
+ if (state.accountId) {
332
+ headers["x-account-id"] = state.accountId;
333
+ }
334
+ return headers;
335
+ }
336
+ async function resolveSsoToken(state) {
337
+ const profile = state.ssoProfile;
338
+ const configDir = state.configDir;
339
+ const cached = await readSsoCache(configDir, profile);
340
+ if (cached && isTokenValid(cached)) {
341
+ return cached.accessToken;
342
+ }
343
+ if (cached?.refreshToken && state.autoRefresh) {
344
+ if (state._refreshPromise) {
345
+ return state._refreshPromise;
346
+ }
347
+ const fetcher = state.fetcher ?? globalThis.fetch;
348
+ if (!fetcher) {
349
+ throw new Error("No fetch implementation available for token refresh.");
350
+ }
351
+ state._refreshPromise = (async () => {
352
+ try {
353
+ const refreshed = await refreshToken(profile, cached.refreshToken, fetcher);
354
+ await writeSsoCache(configDir, profile, refreshed);
355
+ return refreshed.accessToken;
356
+ } finally {
357
+ state._refreshPromise = void 0;
358
+ }
359
+ })();
360
+ return state._refreshPromise;
361
+ }
362
+ throw new Error(
363
+ `SSO token expired. Run \`seclai auth login\` to re-authenticate.`
364
+ );
365
+ }
72
366
 
73
367
  // src/client.ts
74
368
  var SECLAI_API_URL = "https://api.seclai.com";
75
- function getEnv(name) {
369
+ function getEnv2(name) {
76
370
  const p = globalThis?.process;
77
371
  return p?.env?.[name];
78
372
  }
@@ -153,24 +447,75 @@ function anySignal(signals) {
153
447
  }
154
448
  return controller.signal;
155
449
  }
450
+ function toBlob(file, mimeType) {
451
+ if (file instanceof Blob) return file;
452
+ const opts = mimeType ? { type: mimeType } : void 0;
453
+ if (file instanceof ArrayBuffer) return new Blob([new Uint8Array(file)], opts);
454
+ return new Blob([file], opts);
455
+ }
456
+ var MIME_TYPES = {
457
+ txt: "text/plain",
458
+ html: "text/html",
459
+ htm: "text/html",
460
+ md: "text/markdown",
461
+ csv: "text/csv",
462
+ xml: "text/xml",
463
+ json: "application/json",
464
+ pdf: "application/pdf",
465
+ doc: "application/msword",
466
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
467
+ ppt: "application/vnd.ms-powerpoint",
468
+ pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
469
+ xls: "application/vnd.ms-excel",
470
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
471
+ msg: "application/vnd.ms-outlook",
472
+ zip: "application/zip",
473
+ epub: "application/epub+zip",
474
+ png: "image/png",
475
+ jpg: "image/jpeg",
476
+ jpeg: "image/jpeg",
477
+ gif: "image/gif",
478
+ bmp: "image/bmp",
479
+ tiff: "image/tiff",
480
+ webp: "image/webp",
481
+ mp3: "audio/mpeg",
482
+ wav: "audio/wav",
483
+ m4a: "audio/mp4",
484
+ flac: "audio/flac",
485
+ ogg: "audio/ogg",
486
+ mp4: "video/mp4",
487
+ mov: "video/quicktime",
488
+ avi: "video/x-msvideo"
489
+ };
490
+ function inferMimeType(fileName) {
491
+ if (!fileName) return void 0;
492
+ const ext = fileName.split(".").pop()?.toLowerCase();
493
+ return ext ? MIME_TYPES[ext] : void 0;
494
+ }
156
495
  var Seclai = class {
157
- apiKey;
158
496
  baseUrl;
159
- apiKeyHeader;
160
497
  defaultHeaders;
161
498
  fetcher;
499
+ _authState = null;
500
+ _authInitPromise = null;
501
+ _authInitError = null;
162
502
  /**
163
503
  * Create a new Seclai client.
164
504
  *
505
+ * Credentials are resolved via a chain (first match wins):
506
+ * 1. Explicit `apiKey` option
507
+ * 2. Explicit `accessToken` option (static string or provider function)
508
+ * 3. `SECLAI_API_KEY` environment variable
509
+ * 4. SSO profile from `~/.seclai/config` + cached tokens in `~/.seclai/sso/cache/`
510
+ *
165
511
  * @param opts - Client configuration.
166
- * @throws {@link SeclaiConfigurationError} If no API key is provided (and `SECLAI_API_KEY` is not set).
167
512
  * @throws {@link SeclaiConfigurationError} If no `fetch` implementation is available.
513
+ * @throws {@link SeclaiConfigurationError} If both `apiKey` and `accessToken` are provided.
168
514
  */
169
515
  constructor(opts = {}) {
170
- const apiKey = opts.apiKey ?? getEnv("SECLAI_API_KEY");
171
- if (!apiKey) {
516
+ if (opts.apiKey && opts.accessToken) {
172
517
  throw new SeclaiConfigurationError(
173
- "Missing API key. Provide apiKey or set SECLAI_API_KEY."
518
+ "Provide either apiKey or accessToken, not both."
174
519
  );
175
520
  }
176
521
  const fetcher = opts.fetch ?? globalThis.fetch;
@@ -179,30 +524,72 @@ var Seclai = class {
179
524
  "No fetch implementation available. Provide opts.fetch or run in an environment with global fetch."
180
525
  );
181
526
  }
182
- this.apiKey = apiKey;
183
- this.baseUrl = opts.baseUrl ?? getEnv("SECLAI_API_URL") ?? SECLAI_API_URL;
184
- this.apiKeyHeader = opts.apiKeyHeader ?? "x-api-key";
527
+ this.baseUrl = opts.baseUrl ?? getEnv2("SECLAI_API_URL") ?? SECLAI_API_URL;
185
528
  this.defaultHeaders = { ...opts.defaultHeaders ?? {} };
186
529
  this.fetcher = fetcher;
530
+ const accessTokenProvider = typeof opts.accessToken === "function" ? opts.accessToken : void 0;
531
+ const accessTokenStatic = typeof opts.accessToken === "string" ? opts.accessToken : void 0;
532
+ this._authInitPromise = resolveCredentialChain({
533
+ apiKey: opts.apiKey,
534
+ accessToken: accessTokenStatic,
535
+ accessTokenProvider,
536
+ profile: opts.profile,
537
+ configDir: opts.configDir,
538
+ autoRefresh: opts.autoRefresh,
539
+ accountId: opts.accountId,
540
+ apiKeyHeader: opts.apiKeyHeader,
541
+ fetch: fetcher
542
+ }).then((state) => {
543
+ this._authState = state;
544
+ }).catch((err) => {
545
+ this._authInitError = new SeclaiConfigurationError(
546
+ err instanceof Error ? err.message : String(err)
547
+ );
548
+ });
549
+ }
550
+ /** Ensure the credential chain has been resolved. */
551
+ async ensureAuth() {
552
+ if (this._authInitPromise) {
553
+ await this._authInitPromise;
554
+ this._authInitPromise = null;
555
+ }
556
+ if (this._authInitError) {
557
+ throw this._authInitError;
558
+ }
559
+ if (!this._authState) {
560
+ throw new SeclaiConfigurationError(
561
+ "Missing credentials. Provide apiKey, accessToken, set SECLAI_API_KEY, or run `seclai auth login`."
562
+ );
563
+ }
564
+ return this._authState;
187
565
  }
566
+ /** Resolve auth headers for the current request. */
567
+ async authHeaders() {
568
+ const state = await this.ensureAuth();
569
+ return resolveAuthHeaders(state);
570
+ }
571
+ // ═══════════════════════════════════════════════════════════════════════════
572
+ // Low-level request
573
+ // ═══════════════════════════════════════════════════════════════════════════
188
574
  /**
189
575
  * Make a raw HTTP request to the Seclai API.
190
576
  *
191
577
  * This is a low-level escape hatch. For most operations, prefer the typed convenience methods.
192
578
  *
193
579
  * @param method - HTTP method (e.g. `"GET"`, `"POST"`).
194
- * @param path - Request path relative to `baseUrl` (e.g. `"/sources/"`).
195
- * @param opts - Query params, JSON body, and per-request headers.
580
+ * @param path - Request path relative to `baseUrl` (e.g. `"/sources/"`).
581
+ * @param opts - Query params, JSON body, per-request headers, and optional AbortSignal.
196
582
  * @returns Parsed JSON for JSON responses, raw text for non-JSON responses, or `null` for empty bodies.
197
583
  * @throws {@link SeclaiAPIValidationError} For validation errors (typically HTTP 422).
198
584
  * @throws {@link SeclaiAPIStatusError} For other non-success HTTP status codes.
199
585
  */
200
586
  async request(method, path, opts) {
201
587
  const url = buildURL(this.baseUrl, path, opts?.query);
588
+ const authHeaders = await this.authHeaders();
202
589
  const headers = {
203
590
  ...this.defaultHeaders,
204
591
  ...opts?.headers ?? {},
205
- [this.apiKeyHeader]: this.apiKey
592
+ ...authHeaders
206
593
  };
207
594
  let body;
208
595
  if (opts?.json !== void 0) {
@@ -213,6 +600,9 @@ var Seclai = class {
213
600
  if (body !== void 0) {
214
601
  init.body = body;
215
602
  }
603
+ if (opts?.signal) {
604
+ init.signal = opts.signal;
605
+ }
216
606
  const response = await this.fetcher(url, init);
217
607
  if (response.status === 204) return null;
218
608
  const contentType = response.headers.get("content-type") ?? "";
@@ -245,29 +635,253 @@ var Seclai = class {
245
635
  return await response.text();
246
636
  }
247
637
  /**
248
- * Run an agent.
638
+ * Make a raw HTTP request and return the raw `Response` object (for binary downloads, etc.).
639
+ *
640
+ * @param method - HTTP method.
641
+ * @param path - Request path relative to `baseUrl`.
642
+ * @param opts - Query params, JSON body, per-request headers, and optional AbortSignal.
643
+ * @returns The raw `Response` object.
644
+ * @throws {SeclaiAPIValidationError} On HTTP 422 responses.
645
+ * @throws {SeclaiAPIStatusError} On other non-2xx responses.
646
+ */
647
+ async requestRaw(method, path, opts) {
648
+ const url = buildURL(this.baseUrl, path, opts?.query);
649
+ const authHeaders = await this.authHeaders();
650
+ const headers = {
651
+ ...this.defaultHeaders,
652
+ ...opts?.headers ?? {},
653
+ ...authHeaders
654
+ };
655
+ let body;
656
+ if (opts?.json !== void 0) {
657
+ headers["content-type"] = headers["content-type"] ?? "application/json";
658
+ body = JSON.stringify(opts.json);
659
+ }
660
+ const init = { method, headers };
661
+ if (body !== void 0) init.body = body;
662
+ if (opts?.signal) init.signal = opts.signal;
663
+ const response = await this.fetcher(url, init);
664
+ if (!response.ok) {
665
+ const responseText = await safeText(response);
666
+ if (response.status === 422) {
667
+ const validation = await safeJson(response);
668
+ throw new SeclaiAPIValidationError({
669
+ message: "Validation error",
670
+ statusCode: response.status,
671
+ method,
672
+ url: url.toString(),
673
+ responseText,
674
+ validationError: validation
675
+ });
676
+ }
677
+ throw new SeclaiAPIStatusError({
678
+ message: `Request failed with status ${response.status}`,
679
+ statusCode: response.status,
680
+ method,
681
+ url: url.toString(),
682
+ responseText
683
+ });
684
+ }
685
+ return response;
686
+ }
687
+ /** Shared multipart upload helper. */
688
+ async uploadFile(path, opts) {
689
+ const url = buildURL(this.baseUrl, path);
690
+ const authHeaders = await this.authHeaders();
691
+ const headers = {
692
+ ...this.defaultHeaders,
693
+ ...authHeaders
694
+ };
695
+ delete headers["content-type"];
696
+ delete headers["Content-Type"];
697
+ const form = new FormData();
698
+ const mimeType = opts.mimeType ?? inferMimeType(opts.fileName);
699
+ const blob = toBlob(opts.file, mimeType);
700
+ form.set("file", blob, opts.fileName ?? "upload");
701
+ if (opts.title !== void 0) form.set("title", opts.title);
702
+ if (opts.metadata !== void 0) form.set("metadata", JSON.stringify(opts.metadata));
703
+ const init = { method: "POST", headers, body: form };
704
+ if (opts.signal) init.signal = opts.signal;
705
+ const response = await this.fetcher(url, init);
706
+ if (!response.ok) {
707
+ const responseText = await safeText(response);
708
+ if (response.status === 422) {
709
+ const validation = await safeJson(response);
710
+ throw new SeclaiAPIValidationError({
711
+ message: "Validation error",
712
+ statusCode: response.status,
713
+ method: "POST",
714
+ url: url.toString(),
715
+ responseText,
716
+ validationError: validation
717
+ });
718
+ }
719
+ throw new SeclaiAPIStatusError({
720
+ message: `Request failed with status ${response.status}`,
721
+ statusCode: response.status,
722
+ method: "POST",
723
+ url: url.toString(),
724
+ responseText
725
+ });
726
+ }
727
+ return await response.json();
728
+ }
729
+ // ═══════════════════════════════════════════════════════════════════════════
730
+ // Agents — CRUD
731
+ // ═══════════════════════════════════════════════════════════════════════════
732
+ /**
733
+ * List agents.
734
+ *
735
+ * @param opts - Pagination options.
736
+ * @returns Paginated list of agents.
737
+ */
738
+ async listAgents(opts = {}) {
739
+ return await this.request("GET", "/agents", {
740
+ query: { page: opts.page, limit: opts.limit }
741
+ });
742
+ }
743
+ /**
744
+ * Create a new agent.
745
+ *
746
+ * @param body - Agent creation payload (name, trigger type, template, etc.).
747
+ * @returns Summary of the created agent.
748
+ */
749
+ async createAgent(body) {
750
+ return await this.request("POST", "/agents", { json: body });
751
+ }
752
+ /**
753
+ * Get agent details including its definition.
754
+ *
755
+ * @param agentId - Agent identifier.
756
+ * @returns Full agent metadata.
757
+ */
758
+ async getAgent(agentId) {
759
+ return await this.request("GET", `/agents/${agentId}`);
760
+ }
761
+ /**
762
+ * Update an agent.
763
+ *
764
+ * @param agentId - Agent identifier.
765
+ * @param body - Fields to update.
766
+ * @returns Updated agent summary.
767
+ */
768
+ async updateAgent(agentId, body) {
769
+ return await this.request("PUT", `/agents/${agentId}`, { json: body });
770
+ }
771
+ /**
772
+ * Delete an agent.
773
+ *
774
+ * @param agentId - Agent identifier.
775
+ */
776
+ async deleteAgent(agentId) {
777
+ await this.request("DELETE", `/agents/${agentId}`);
778
+ }
779
+ // ═══════════════════════════════════════════════════════════════════════════
780
+ // Agent Definitions
781
+ // ═══════════════════════════════════════════════════════════════════════════
782
+ /**
783
+ * Get an agent's full definition (steps, model config, etc.).
784
+ *
785
+ * @param agentId - Agent identifier.
786
+ * @returns The agent definition.
787
+ */
788
+ async getAgentDefinition(agentId) {
789
+ return await this.request("GET", `/agents/${agentId}/definition`);
790
+ }
791
+ /**
792
+ * Update an agent's definition.
793
+ *
794
+ * @param agentId - Agent identifier.
795
+ * @param body - Updated definition payload.
796
+ * @returns Updated agent definition.
797
+ */
798
+ async updateAgentDefinition(agentId, body) {
799
+ return await this.request("PUT", `/agents/${agentId}/definition`, { json: body });
800
+ }
801
+ // ═══════════════════════════════════════════════════════════════════════════
802
+ // Agent Runs
803
+ // ═══════════════════════════════════════════════════════════════════════════
804
+ /**
805
+ * Start an agent run.
249
806
  *
250
807
  * @param agentId - Agent identifier.
251
- * @param body - Agent run request payload.
808
+ * @param body - Run request payload (`input`, `metadata`, `priority`, etc.).
252
809
  * @returns The created agent run.
253
810
  */
254
811
  async runAgent(agentId, body) {
255
- const data = await this.request("POST", `/agents/${agentId}/runs`, { json: body });
256
- return data;
812
+ return await this.request("POST", `/agents/${agentId}/runs`, { json: body });
813
+ }
814
+ /**
815
+ * List runs for a specific agent.
816
+ *
817
+ * @param agentId - Agent identifier.
818
+ * @param opts - Pagination and filter options.
819
+ * @returns Paginated list of runs.
820
+ */
821
+ async listAgentRuns(agentId, opts = {}) {
822
+ return await this.request("GET", `/agents/${agentId}/runs`, {
823
+ query: { page: opts.page, limit: opts.limit, status: opts.status }
824
+ });
257
825
  }
258
826
  /**
259
- * Run an agent in streaming mode (SSE) and block until the final `done` event.
827
+ * Search agent runs (traces) across all agents.
828
+ *
829
+ * @param body - Search query and filters.
830
+ * @returns Search results with matching runs.
831
+ */
832
+ async searchAgentRuns(body) {
833
+ return await this.request("POST", "/agents/runs/search", { json: body });
834
+ }
835
+ /**
836
+ * Get details of a specific agent run.
837
+ *
838
+ * @param runId - Run identifier.
839
+ * @param opts - Optional flags.
840
+ * @returns Agent run details.
841
+ */
842
+ async getAgentRun(runId, opts) {
843
+ return await this.request("GET", `/agents/runs/${runId}`, opts?.includeStepOutputs ? {
844
+ query: { include_step_outputs: true }
845
+ } : void 0);
846
+ }
847
+ /**
848
+ * Delete an agent run.
849
+ *
850
+ * @param runId - Run identifier.
851
+ */
852
+ async deleteAgentRun(runId) {
853
+ await this.request("DELETE", `/agents/runs/${runId}`);
854
+ }
855
+ /**
856
+ * Cancel a running agent run.
857
+ *
858
+ * @param runId - Run identifier.
859
+ * @returns Updated run (with cancelled status).
860
+ */
861
+ async cancelAgentRun(runId) {
862
+ return await this.request("POST", `/agents/runs/${runId}/cancel`);
863
+ }
864
+ // ═══════════════════════════════════════════════════════════════════════════
865
+ // Agent Runs — Streaming
866
+ // ═══════════════════════════════════════════════════════════════════════════
867
+ /**
868
+ * Run an agent in streaming mode (SSE) and wait for the final result.
869
+ *
870
+ * Consumes the entire SSE stream and returns only the terminal `done` payload.
871
+ * For real-time event access, use {@link runStreamingAgent} instead.
260
872
  *
261
873
  * @param agentId - Agent identifier.
262
- * @param body - Streaming agent run request payload.
263
- * @param opts - Optional timeout + abort signal.
874
+ * @param body - Streaming run request payload.
875
+ * @param opts - Timeout and abort signal options.
264
876
  * @returns Final agent run payload from the `done` event.
877
+ * @throws {@link SeclaiStreamingError} If the stream ends before a `done` event.
265
878
  */
266
879
  async runStreamingAgentAndWait(agentId, body, opts) {
267
880
  const url = buildURL(this.baseUrl, `/agents/${agentId}/runs/stream`);
881
+ const authHdrs = await this.authHeaders();
268
882
  const headers = {
269
883
  ...this.defaultHeaders,
270
- [this.apiKeyHeader]: this.apiKey,
884
+ ...authHdrs,
271
885
  accept: "text/event-stream",
272
886
  "content-type": "application/json"
273
887
  };
@@ -279,12 +893,9 @@ var Seclai = class {
279
893
  timeoutController.abort();
280
894
  }, timeoutMs);
281
895
  const signal = anySignal([opts?.signal, timeoutController.signal]);
896
+ let lastSeen;
282
897
  try {
283
- const init = {
284
- method: "POST",
285
- headers,
286
- body: JSON.stringify(body)
287
- };
898
+ const init = { method: "POST", headers, body: JSON.stringify(body) };
288
899
  if (signal) init.signal = signal;
289
900
  const response = await this.fetcher(url, init);
290
901
  const contentType = response.headers.get("content-type") ?? "";
@@ -321,16 +932,13 @@ var Seclai = class {
321
932
  const reader = response.body.getReader();
322
933
  const decoder = new TextDecoder();
323
934
  let final;
324
- let lastSeen;
325
935
  const parser = createSseParser((msg) => {
326
936
  if (!msg.data) return;
327
937
  if (msg.event === "init" || msg.event === "done") {
328
938
  try {
329
939
  const parsed = JSON.parse(msg.data);
330
940
  lastSeen = parsed;
331
- if (msg.event === "done") {
332
- final = parsed;
333
- }
941
+ if (msg.event === "done") final = parsed;
334
942
  } catch {
335
943
  }
336
944
  }
@@ -345,10 +953,13 @@ var Seclai = class {
345
953
  if (lastSeen && lastSeen.status && lastSeen.status !== "pending") {
346
954
  return lastSeen;
347
955
  }
348
- throw new SeclaiError("Stream ended before receiving a 'done' event.");
956
+ throw new SeclaiStreamingError("Stream ended before receiving a 'done' event.", lastSeen?.run_id);
349
957
  } catch (err) {
350
958
  if (timedOut) {
351
- throw new SeclaiError(`Timed out after ${timeoutMs}ms waiting for streaming agent run to complete.`);
959
+ throw new SeclaiStreamingError(
960
+ `Timed out after ${timeoutMs}ms waiting for streaming agent run to complete.`,
961
+ lastSeen?.run_id
962
+ );
352
963
  }
353
964
  throw err;
354
965
  } finally {
@@ -356,245 +967,1308 @@ var Seclai = class {
356
967
  }
357
968
  }
358
969
  /**
359
- * List agent runs for an agent.
360
- *
361
- * @param agentId - Agent identifier.
362
- * @param opts - Pagination options.
363
- * @returns A paginated list of runs.
364
- */
365
- async listAgentRuns(agentId, opts = {}) {
366
- const data = await this.request("GET", `/agents/${agentId}/runs`, {
367
- query: { page: opts.page ?? 1, limit: opts.limit ?? 50 }
368
- });
369
- return data;
370
- }
371
- async getAgentRun(arg1, arg2, arg3 = {}) {
372
- const hasOldSignature = typeof arg2 === "string";
373
- const runId = hasOldSignature ? arg2 : arg1;
374
- const opts = hasOldSignature ? arg3 : arg2 ?? {};
375
- const data = await this.request(
376
- "GET",
377
- `/agents/runs/${runId}`,
378
- opts.includeStepOutputs ? { query: { include_step_outputs: true } } : void 0
379
- );
380
- return data;
381
- }
382
- async deleteAgentRun(arg1, arg2) {
383
- const runId = arg2 ?? arg1;
384
- const data = await this.request("DELETE", `/agents/runs/${runId}`);
385
- return data;
386
- }
387
- /**
388
- * Get content detail.
389
- *
390
- * Fetches a slice of a content version (use `start`/`end` to page through large content).
391
- *
392
- * @param sourceConnectionContentVersion - Content version identifier.
393
- * @param opts - Range options.
394
- * @returns Content details for the requested range.
395
- */
396
- async getContentDetail(sourceConnectionContentVersion, opts = {}) {
397
- const data = await this.request(
398
- "GET",
399
- `/contents/${sourceConnectionContentVersion}`,
400
- { query: { start: opts.start ?? 0, end: opts.end ?? 5e3 } }
401
- );
402
- return data;
403
- }
404
- /**
405
- * Delete a specific content version.
970
+ * Run an agent in streaming mode and yield each SSE event as it arrives.
406
971
  *
407
- * @param sourceConnectionContentVersion - Content version identifier.
408
- */
409
- async deleteContent(sourceConnectionContentVersion) {
410
- await this.request("DELETE", `/contents/${sourceConnectionContentVersion}`);
411
- }
412
- /**
413
- * List embeddings for a content version.
972
+ * This is an `AsyncGenerator` suitable for real-time UIs that want to render
973
+ * step progress as it happens.
414
974
  *
415
- * @param sourceConnectionContentVersion - Content version identifier.
416
- * @param opts - Pagination options.
417
- * @returns A paginated list of embeddings.
418
- */
419
- async listContentEmbeddings(sourceConnectionContentVersion, opts = {}) {
420
- const data = await this.request(
421
- "GET",
422
- `/contents/${sourceConnectionContentVersion}/embeddings`,
423
- { query: { page: opts.page ?? 1, limit: opts.limit ?? 20 } }
424
- );
425
- return data;
426
- }
427
- /**
428
- * List sources.
975
+ * @param agentId - Agent identifier.
976
+ * @param body - Streaming run request payload.
977
+ * @param opts - Timeout and abort signal options.
978
+ * @yields {@link AgentRunEvent} for each SSE message.
429
979
  *
430
- * @param opts - Pagination and filter options.
431
- * @returns A paginated list of sources.
980
+ * @example
981
+ * ```ts
982
+ * for await (const event of client.runStreamingAgent("agent-id", { input: "Hello!" })) {
983
+ * if (event.event === "done") {
984
+ * console.log("Final:", event.data);
985
+ * }
986
+ * }
987
+ * ```
432
988
  */
433
- async listSources(opts = {}) {
434
- const data = await this.request("GET", "/sources/", {
435
- query: {
436
- page: opts.page ?? 1,
437
- limit: opts.limit ?? 20,
438
- sort: opts.sort ?? "created_at",
439
- order: opts.order ?? "desc",
440
- account_id: opts.accountId ?? void 0
441
- }
442
- });
443
- return data;
444
- }
445
- /**
446
- * Upload a file to a specific source connection.
447
- *
448
- * Maximum file size: 200 MiB.
449
- *
450
- * Supported MIME types:
451
- * - `application/epub+zip`
452
- * - `application/json`
453
- * - `application/msword`
454
- * - `application/pdf`
455
- * - `application/vnd.ms-excel`
456
- * - `application/vnd.ms-outlook`
457
- * - `application/vnd.ms-powerpoint`
458
- * - `application/vnd.openxmlformats-officedocument.presentationml.presentation`
459
- * - `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`
460
- * - `application/vnd.openxmlformats-officedocument.wordprocessingml.document`
461
- * - `application/xml`
462
- * - `application/zip`
463
- * - `audio/flac`, `audio/mp4`, `audio/mpeg`, `audio/ogg`, `audio/wav`
464
- * - `image/bmp`, `image/gif`, `image/jpeg`, `image/png`, `image/tiff`, `image/webp`
465
- * - `text/csv`, `text/html`, `text/markdown`, `text/x-markdown`, `text/plain`, `text/xml`
466
- * - `video/mp4`, `video/quicktime`, `video/x-msvideo`
467
- *
468
- * Notes:
469
- * - If `mimeType` is omitted, the upload is typically sent as `application/octet-stream`.
470
- * In that case, the server attempts to infer the type from the uploaded filename/extension,
471
- * so prefer providing `fileName` with a meaningful extension (e.g. `"recording.mp3"`).
472
- *
473
- * @param sourceConnectionId - Source connection identifier.
474
- * @param opts - File payload and optional metadata.
475
- * @param opts.file - File payload as a `Blob`, `Uint8Array`, or `ArrayBuffer`.
476
- * @param opts.title - Optional title for the uploaded file.
477
- * @param opts.metadata - Optional metadata object. This is sent as a JSON string form field named `metadata`.
478
- * Example: `{ category: "docs", author: "Ada" }`.
479
- * @param opts.fileName - Optional filename to send with the upload.
480
- * @param opts.mimeType - Optional MIME type to attach to the upload.
481
- * @returns Upload response details.
482
- */
483
- async uploadFileToSource(sourceConnectionId, opts) {
484
- const url = buildURL(this.baseUrl, `/sources/${sourceConnectionId}/upload`);
989
+ async *runStreamingAgent(agentId, body, opts) {
990
+ const url = buildURL(this.baseUrl, `/agents/${agentId}/runs/stream`);
991
+ const authHdrs = await this.authHeaders();
485
992
  const headers = {
486
993
  ...this.defaultHeaders,
487
- [this.apiKeyHeader]: this.apiKey
994
+ ...authHdrs,
995
+ accept: "text/event-stream",
996
+ "content-type": "application/json"
488
997
  };
489
- const form = new FormData();
490
- let blob;
491
- if (opts.file instanceof Blob) {
492
- blob = opts.file;
493
- } else if (opts.file instanceof ArrayBuffer) {
494
- const blobOpts = opts.mimeType ? { type: opts.mimeType } : void 0;
495
- blob = new Blob([new Uint8Array(opts.file)], blobOpts);
496
- } else {
497
- const blobOpts = opts.mimeType ? { type: opts.mimeType } : void 0;
498
- blob = new Blob([opts.file], blobOpts);
499
- }
500
- const fileName = opts.fileName ?? "upload";
501
- form.set("file", blob, fileName);
502
- if (opts.title !== void 0) {
503
- form.set("title", opts.title);
504
- }
505
- if (opts.metadata !== void 0) {
506
- form.set("metadata", JSON.stringify(opts.metadata));
507
- }
508
- const response = await this.fetcher(url, {
509
- method: "POST",
510
- headers,
511
- body: form
512
- });
513
- if (!response.ok) {
514
- const responseText = await safeText(response);
515
- if (response.status === 422) {
516
- const validation = await safeJson(response);
517
- throw new SeclaiAPIValidationError({
518
- message: "Validation error",
998
+ const timeoutMs = opts?.timeoutMs ?? 6e4;
999
+ const timeoutController = new AbortController();
1000
+ let timedOut = false;
1001
+ const timeoutId = setTimeout(() => {
1002
+ timedOut = true;
1003
+ timeoutController.abort();
1004
+ }, timeoutMs);
1005
+ const signal = anySignal([opts?.signal, timeoutController.signal]);
1006
+ try {
1007
+ const init = { method: "POST", headers, body: JSON.stringify(body) };
1008
+ if (signal) init.signal = signal;
1009
+ const response = await this.fetcher(url, init);
1010
+ const contentType = response.headers.get("content-type") ?? "";
1011
+ const isJson = contentType.includes("application/json");
1012
+ if (!response.ok) {
1013
+ const responseText = await safeText(response);
1014
+ if (response.status === 422) {
1015
+ const validation = await safeJson(response);
1016
+ throw new SeclaiAPIValidationError({
1017
+ message: "Validation error",
1018
+ statusCode: response.status,
1019
+ method: "POST",
1020
+ url: url.toString(),
1021
+ responseText,
1022
+ validationError: validation
1023
+ });
1024
+ }
1025
+ throw new SeclaiAPIStatusError({
1026
+ message: `Request failed with status ${response.status}`,
519
1027
  statusCode: response.status,
520
1028
  method: "POST",
521
1029
  url: url.toString(),
522
- responseText,
523
- validationError: validation
1030
+ responseText
524
1031
  });
525
1032
  }
526
- throw new SeclaiAPIStatusError({
527
- message: `Request failed with status ${response.status}`,
528
- statusCode: response.status,
529
- method: "POST",
530
- url: url.toString(),
531
- responseText
1033
+ if (isJson) {
1034
+ const data = await response.json();
1035
+ yield { event: "done", data };
1036
+ return;
1037
+ }
1038
+ if (!response.body) {
1039
+ throw new SeclaiConfigurationError(
1040
+ "Streaming response body is not available in this environment."
1041
+ );
1042
+ }
1043
+ const reader = response.body.getReader();
1044
+ const decoder = new TextDecoder();
1045
+ const events = [];
1046
+ const parser = createSseParser((msg) => {
1047
+ if (!msg.data) return;
1048
+ let data;
1049
+ try {
1050
+ data = JSON.parse(msg.data);
1051
+ } catch {
1052
+ data = msg.data;
1053
+ }
1054
+ events.push({ event: msg.event ?? "message", data });
532
1055
  });
1056
+ while (true) {
1057
+ const { value, done } = await reader.read();
1058
+ if (value) parser.feed(decoder.decode(value, { stream: true }));
1059
+ while (events.length > 0) {
1060
+ yield events.shift();
1061
+ }
1062
+ if (done) break;
1063
+ }
1064
+ parser.end();
1065
+ while (events.length > 0) {
1066
+ yield events.shift();
1067
+ }
1068
+ } catch (err) {
1069
+ if (timedOut) {
1070
+ throw new SeclaiStreamingError(
1071
+ `Timed out after ${timeoutMs}ms waiting for streaming agent run to complete.`
1072
+ );
1073
+ }
1074
+ throw err;
1075
+ } finally {
1076
+ clearTimeout(timeoutId);
533
1077
  }
534
- return await response.json();
535
1078
  }
1079
+ // ═══════════════════════════════════════════════════════════════════════════
1080
+ // Agent Runs — Polling
1081
+ // ═══════════════════════════════════════════════════════════════════════════
536
1082
  /**
537
- * Upload a new file and replace the content backing an existing content version.
1083
+ * Run an agent and poll until it reaches a terminal status.
538
1084
  *
539
- * This endpoint is useful when you need to correct or update an uploaded document while keeping
540
- * references stable (the content version ID stays the same).
1085
+ * This is useful in environments where SSE streaming is unavailable.
541
1086
  *
542
- * Notes:
543
- * - `metadata` is sent as a JSON string form field named `metadata`.
544
- * - `title` is a convenience field and may be merged into `metadata.title` by the server.
1087
+ * @param agentId - Agent identifier.
1088
+ * @param body - Run request payload.
1089
+ * @param opts - Polling configuration and abort signal.
1090
+ * @returns The terminal agent run.
1091
+ * @throws {@link SeclaiStreamingError} On timeout.
545
1092
  */
546
- async uploadFileToContent(sourceConnectionContentVersion, opts) {
547
- const url = buildURL(this.baseUrl, `/contents/${sourceConnectionContentVersion}/upload`);
548
- const headers = {
549
- ...this.defaultHeaders,
550
- [this.apiKeyHeader]: this.apiKey
551
- };
552
- const form = new FormData();
553
- let blob;
554
- if (opts.file instanceof Blob) {
555
- blob = opts.file;
556
- } else if (opts.file instanceof ArrayBuffer) {
557
- const blobOpts = opts.mimeType ? { type: opts.mimeType } : void 0;
558
- blob = new Blob([new Uint8Array(opts.file)], blobOpts);
559
- } else {
560
- const blobOpts = opts.mimeType ? { type: opts.mimeType } : void 0;
561
- blob = new Blob([opts.file], blobOpts);
562
- }
563
- const fileName = opts.fileName ?? "upload";
564
- form.set("file", blob, fileName);
565
- if (opts.title !== void 0) {
566
- form.set("title", opts.title);
567
- }
568
- if (opts.metadata !== void 0) {
569
- form.set("metadata", JSON.stringify(opts.metadata));
570
- }
571
- const response = await this.fetcher(url, {
572
- method: "POST",
573
- headers,
574
- body: form
575
- });
576
- if (!response.ok) {
577
- const responseText = await safeText(response);
578
- if (response.status === 422) {
579
- const validation = await safeJson(response);
580
- throw new SeclaiAPIValidationError({
581
- message: "Validation error",
582
- statusCode: response.status,
583
- method: "POST",
584
- url: url.toString(),
585
- responseText,
586
- validationError: validation
587
- });
1093
+ async runAgentAndPoll(agentId, body, opts) {
1094
+ const pollInterval = opts?.pollIntervalMs ?? 2e3;
1095
+ const timeout = opts?.timeoutMs ?? 3e5;
1096
+ const startTime = Date.now();
1097
+ const run = await this.runAgent(agentId, body);
1098
+ const runId = run.id ?? run.run_id;
1099
+ if (!runId) throw new SeclaiError("Agent run response did not contain an id.");
1100
+ while (true) {
1101
+ if (opts?.signal?.aborted) throw new SeclaiError("Polling aborted.");
1102
+ if (Date.now() - startTime > timeout) {
1103
+ throw new SeclaiStreamingError(`Polling timed out after ${timeout}ms.`, runId);
1104
+ }
1105
+ await new Promise((r) => setTimeout(r, pollInterval));
1106
+ const current = await this.getAgentRun(
1107
+ runId,
1108
+ opts?.includeStepOutputs ? { includeStepOutputs: true } : void 0
1109
+ );
1110
+ const status = current.status;
1111
+ if (status === "completed" || status === "failed" || status === "cancelled") {
1112
+ return current;
588
1113
  }
589
- throw new SeclaiAPIStatusError({
590
- message: `Request failed with status ${response.status}`,
591
- statusCode: response.status,
592
- method: "POST",
593
- url: url.toString(),
594
- responseText
595
- });
596
1114
  }
597
- return await response.json();
1115
+ }
1116
+ // ═══════════════════════════════════════════════════════════════════════════
1117
+ // Agent Run Evaluation Results
1118
+ // ═══════════════════════════════════════════════════════════════════════════
1119
+ /**
1120
+ * List evaluation results for a specific agent run.
1121
+ *
1122
+ * @param agentId - Agent identifier.
1123
+ * @param runId - Run identifier.
1124
+ * @param opts - Pagination options.
1125
+ * @returns Paginated list of evaluation results.
1126
+ */
1127
+ async listRunEvaluationResults(agentId, runId, opts = {}) {
1128
+ return await this.request("GET", `/agents/${agentId}/runs/${runId}/evaluation-results`, {
1129
+ query: { page: opts.page, limit: opts.limit }
1130
+ });
1131
+ }
1132
+ // ═══════════════════════════════════════════════════════════════════════════
1133
+ // Agent Input Uploads
1134
+ // ═══════════════════════════════════════════════════════════════════════════
1135
+ /**
1136
+ * Upload a file to use as input for a `dynamic_input` agent run.
1137
+ *
1138
+ * After uploading, poll {@link getAgentInputUploadStatus} until `status` is `ready`,
1139
+ * then pass `input_upload_id` to {@link runAgent}.
1140
+ *
1141
+ * @param agentId - Agent identifier.
1142
+ * @param opts - File payload and optional metadata.
1143
+ * @returns Upload response with the upload ID and status.
1144
+ */
1145
+ async uploadAgentInput(agentId, opts) {
1146
+ return await this.uploadFile(`/agents/${agentId}/upload-input`, opts);
1147
+ }
1148
+ /**
1149
+ * Get the status of an agent input upload.
1150
+ *
1151
+ * @param agentId - Agent identifier.
1152
+ * @param uploadId - Upload identifier.
1153
+ * @returns Upload status and metadata.
1154
+ */
1155
+ async getAgentInputUploadStatus(agentId, uploadId) {
1156
+ return await this.request("GET", `/agents/${agentId}/input-uploads/${uploadId}`);
1157
+ }
1158
+ // ═══════════════════════════════════════════════════════════════════════════
1159
+ // Agent AI Assistant (Steps Generation)
1160
+ // ═══════════════════════════════════════════════════════════════════════════
1161
+ /**
1162
+ * Generate agent workflow steps from natural language using AI.
1163
+ *
1164
+ * @param agentId - Agent identifier.
1165
+ * @param body - Generation request with user instructions.
1166
+ * @returns AI-generated step configuration.
1167
+ */
1168
+ async generateAgentSteps(agentId, body) {
1169
+ return await this.request("POST", `/agents/${agentId}/ai-assistant/generate-steps`, { json: body });
1170
+ }
1171
+ /**
1172
+ * Generate a single step configuration using AI.
1173
+ *
1174
+ * @param agentId - Agent identifier.
1175
+ * @param body - Step config generation request.
1176
+ * @returns AI-generated step config.
1177
+ */
1178
+ async generateStepConfig(agentId, body) {
1179
+ return await this.request("POST", `/agents/${agentId}/ai-assistant/step-config`, { json: body });
1180
+ }
1181
+ /**
1182
+ * Get AI conversation history for an agent.
1183
+ *
1184
+ * @param agentId - Agent identifier.
1185
+ * @returns Conversation history.
1186
+ */
1187
+ async getAgentAiConversationHistory(agentId) {
1188
+ return await this.request("GET", `/agents/${agentId}/ai-assistant/conversations`);
1189
+ }
1190
+ /**
1191
+ * Mark an AI suggestion as accepted or rejected.
1192
+ *
1193
+ * @param agentId - Agent identifier.
1194
+ * @param conversationId - Conversation turn identifier.
1195
+ * @param body - Mark request payload.
1196
+ */
1197
+ async markAgentAiSuggestion(agentId, conversationId, body) {
1198
+ await this.request("PATCH", `/agents/${agentId}/ai-assistant/${conversationId}`, { json: body });
1199
+ }
1200
+ // ═══════════════════════════════════════════════════════════════════════════
1201
+ // Agent Evaluation Criteria
1202
+ // ═══════════════════════════════════════════════════════════════════════════
1203
+ /**
1204
+ * List evaluation criteria for an agent.
1205
+ *
1206
+ * @param agentId - Agent identifier.
1207
+ * @param opts - Pagination options.
1208
+ */
1209
+ async listEvaluationCriteria(agentId, opts = {}) {
1210
+ return await this.request("GET", `/agents/${agentId}/evaluation-criteria`, {
1211
+ query: { page: opts.page, limit: opts.limit }
1212
+ });
1213
+ }
1214
+ /**
1215
+ * Create evaluation criteria for an agent.
1216
+ *
1217
+ * @param agentId - Agent identifier.
1218
+ * @param body - Criteria definition.
1219
+ * @returns Created evaluation criteria.
1220
+ */
1221
+ async createEvaluationCriteria(agentId, body) {
1222
+ return await this.request("POST", `/agents/${agentId}/evaluation-criteria`, { json: body });
1223
+ }
1224
+ /**
1225
+ * Get a single evaluation criteria by ID.
1226
+ *
1227
+ * @param criteriaId - Criteria identifier.
1228
+ * @returns Evaluation criteria details.
1229
+ */
1230
+ async getEvaluationCriteria(criteriaId) {
1231
+ return await this.request("GET", `/agents/evaluation-criteria/${criteriaId}`);
1232
+ }
1233
+ /**
1234
+ * Update an evaluation criteria.
1235
+ *
1236
+ * @param criteriaId - Criteria identifier.
1237
+ * @param body - Fields to update.
1238
+ * @returns Updated evaluation criteria.
1239
+ */
1240
+ async updateEvaluationCriteria(criteriaId, body) {
1241
+ return await this.request("PATCH", `/agents/evaluation-criteria/${criteriaId}`, { json: body });
1242
+ }
1243
+ /**
1244
+ * Delete an evaluation criteria and all associated results.
1245
+ *
1246
+ * @param criteriaId - Criteria identifier.
1247
+ */
1248
+ async deleteEvaluationCriteria(criteriaId) {
1249
+ await this.request("DELETE", `/agents/evaluation-criteria/${criteriaId}`);
1250
+ }
1251
+ /**
1252
+ * Get the evaluation summary for a specific criteria.
1253
+ *
1254
+ * @param criteriaId - Criteria identifier.
1255
+ * @returns Evaluation result summary.
1256
+ */
1257
+ async getEvaluationCriteriaSummary(criteriaId) {
1258
+ return await this.request("GET", `/agents/evaluation-criteria/${criteriaId}/summary`);
1259
+ }
1260
+ /**
1261
+ * List evaluation results for a specific criteria.
1262
+ *
1263
+ * @param criteriaId - Criteria identifier.
1264
+ * @param opts - Pagination options.
1265
+ */
1266
+ async listEvaluationResults(criteriaId, opts = {}) {
1267
+ return await this.request("GET", `/agents/evaluation-criteria/${criteriaId}/results`, {
1268
+ query: { page: opts.page, limit: opts.limit }
1269
+ });
1270
+ }
1271
+ /**
1272
+ * Create a manual evaluation result for a criteria.
1273
+ *
1274
+ * @param criteriaId - Criteria identifier.
1275
+ * @param body - Evaluation result payload.
1276
+ * @returns Created evaluation result.
1277
+ */
1278
+ async createEvaluationResult(criteriaId, body) {
1279
+ return await this.request("POST", `/agents/evaluation-criteria/${criteriaId}/results`, { json: body });
1280
+ }
1281
+ /**
1282
+ * List runs compatible with a specific evaluation criteria.
1283
+ *
1284
+ * @param criteriaId - Criteria identifier.
1285
+ * @param opts - Pagination options.
1286
+ */
1287
+ async listCompatibleRuns(criteriaId, opts = {}) {
1288
+ return await this.request("GET", `/agents/evaluation-criteria/${criteriaId}/compatible-runs`, {
1289
+ query: { page: opts.page, limit: opts.limit }
1290
+ });
1291
+ }
1292
+ /**
1293
+ * Test a draft evaluation criteria without persisting it.
1294
+ *
1295
+ * @param agentId - Agent identifier.
1296
+ * @param body - Draft evaluation to test.
1297
+ * @returns Test evaluation response.
1298
+ */
1299
+ async testDraftEvaluation(agentId, body) {
1300
+ return await this.request("POST", `/agents/${agentId}/evaluation-criteria/test-draft`, { json: body });
1301
+ }
1302
+ /**
1303
+ * List all evaluation results for an agent.
1304
+ *
1305
+ * @param agentId - Agent identifier.
1306
+ * @param opts - Pagination options.
1307
+ */
1308
+ async listAgentEvaluationResults(agentId, opts = {}) {
1309
+ return await this.request("GET", `/agents/${agentId}/evaluation-results`, {
1310
+ query: { page: opts.page, limit: opts.limit }
1311
+ });
1312
+ }
1313
+ /**
1314
+ * List evaluation run summaries for an agent.
1315
+ *
1316
+ * @param agentId - Agent identifier.
1317
+ * @param opts - Pagination options.
1318
+ */
1319
+ async listEvaluationRuns(agentId, opts = {}) {
1320
+ return await this.request("GET", `/agents/${agentId}/evaluation-runs`, {
1321
+ query: { page: opts.page, limit: opts.limit }
1322
+ });
1323
+ }
1324
+ /**
1325
+ * Get a summary of non-manual evaluations across an agent's runs.
1326
+ *
1327
+ * @param agentId - Agent identifier.
1328
+ */
1329
+ async getNonManualEvaluationSummary(agentId) {
1330
+ return await this.request("GET", "/agents/evaluation-results/non-manual-summary", {
1331
+ query: { agent_id: agentId }
1332
+ });
1333
+ }
1334
+ // ═══════════════════════════════════════════════════════════════════════════
1335
+ // Knowledge Bases
1336
+ // ═══════════════════════════════════════════════════════════════════════════
1337
+ /**
1338
+ * List knowledge bases.
1339
+ *
1340
+ * @param opts - Pagination and sorting options.
1341
+ * @returns Paginated list of knowledge bases.
1342
+ */
1343
+ async listKnowledgeBases(opts = {}) {
1344
+ return await this.request("GET", "/knowledge_bases", {
1345
+ query: { page: opts.page, limit: opts.limit, sort: opts.sort, order: opts.order }
1346
+ });
1347
+ }
1348
+ /**
1349
+ * Create a new knowledge base.
1350
+ *
1351
+ * @param body - Knowledge base configuration.
1352
+ * @returns The created knowledge base.
1353
+ */
1354
+ async createKnowledgeBase(body) {
1355
+ return await this.request("POST", "/knowledge_bases", { json: body });
1356
+ }
1357
+ /**
1358
+ * Get a knowledge base by ID.
1359
+ *
1360
+ * @param knowledgeBaseId - Knowledge base identifier.
1361
+ * @returns Knowledge base details.
1362
+ */
1363
+ async getKnowledgeBase(knowledgeBaseId) {
1364
+ return await this.request("GET", `/knowledge_bases/${knowledgeBaseId}`);
1365
+ }
1366
+ /**
1367
+ * Update a knowledge base.
1368
+ *
1369
+ * @param knowledgeBaseId - Knowledge base identifier.
1370
+ * @param body - Fields to update.
1371
+ * @returns Updated knowledge base.
1372
+ */
1373
+ async updateKnowledgeBase(knowledgeBaseId, body) {
1374
+ return await this.request("PUT", `/knowledge_bases/${knowledgeBaseId}`, { json: body });
1375
+ }
1376
+ /**
1377
+ * Delete a knowledge base.
1378
+ *
1379
+ * @param knowledgeBaseId - Knowledge base identifier.
1380
+ */
1381
+ async deleteKnowledgeBase(knowledgeBaseId) {
1382
+ await this.request("DELETE", `/knowledge_bases/${knowledgeBaseId}`);
1383
+ }
1384
+ // ═══════════════════════════════════════════════════════════════════════════
1385
+ // Memory Banks
1386
+ // ═══════════════════════════════════════════════════════════════════════════
1387
+ /**
1388
+ * List memory banks.
1389
+ *
1390
+ * @param opts - Pagination and sorting options.
1391
+ * @returns Paginated list of memory banks.
1392
+ */
1393
+ async listMemoryBanks(opts = {}) {
1394
+ return await this.request("GET", "/memory_banks", {
1395
+ query: { page: opts.page, limit: opts.limit, sort: opts.sort, order: opts.order }
1396
+ });
1397
+ }
1398
+ /**
1399
+ * Create a new memory bank.
1400
+ *
1401
+ * Memory banks give agents persistent memory across conversations.
1402
+ * Types: `conversation` (chat-style history) or `general` (flat factual entries).
1403
+ *
1404
+ * @param body - Memory bank configuration.
1405
+ * @returns The created memory bank.
1406
+ */
1407
+ async createMemoryBank(body) {
1408
+ return await this.request("POST", "/memory_banks", { json: body });
1409
+ }
1410
+ /**
1411
+ * Get a memory bank by ID.
1412
+ *
1413
+ * @param memoryBankId - Memory bank identifier.
1414
+ * @returns Memory bank details.
1415
+ */
1416
+ async getMemoryBank(memoryBankId) {
1417
+ return await this.request("GET", `/memory_banks/${memoryBankId}`);
1418
+ }
1419
+ /**
1420
+ * Update a memory bank.
1421
+ *
1422
+ * @param memoryBankId - Memory bank identifier.
1423
+ * @param body - Fields to update.
1424
+ * @returns Updated memory bank.
1425
+ */
1426
+ async updateMemoryBank(memoryBankId, body) {
1427
+ return await this.request("PUT", `/memory_banks/${memoryBankId}`, { json: body });
1428
+ }
1429
+ /**
1430
+ * Delete a memory bank.
1431
+ *
1432
+ * @param memoryBankId - Memory bank identifier.
1433
+ */
1434
+ async deleteMemoryBank(memoryBankId) {
1435
+ await this.request("DELETE", `/memory_banks/${memoryBankId}`);
1436
+ }
1437
+ /**
1438
+ * Get agents that are using a specific memory bank.
1439
+ *
1440
+ * @param memoryBankId - Memory bank identifier.
1441
+ */
1442
+ async getAgentsUsingMemoryBank(memoryBankId) {
1443
+ return await this.request("GET", `/memory_banks/${memoryBankId}/agents`);
1444
+ }
1445
+ /**
1446
+ * Get stats for a memory bank.
1447
+ *
1448
+ * @param memoryBankId - Memory bank identifier.
1449
+ */
1450
+ async getMemoryBankStats(memoryBankId) {
1451
+ return await this.request("GET", `/memory_banks/${memoryBankId}/stats`);
1452
+ }
1453
+ /**
1454
+ * Compact a memory bank (trigger compaction).
1455
+ *
1456
+ * @param memoryBankId - Memory bank identifier.
1457
+ */
1458
+ async compactMemoryBank(memoryBankId) {
1459
+ await this.request("POST", `/memory_banks/${memoryBankId}/compact`);
1460
+ }
1461
+ /**
1462
+ * Delete a memory bank source.
1463
+ *
1464
+ * @param memoryBankId - Memory bank identifier.
1465
+ */
1466
+ async deleteMemoryBankSource(memoryBankId) {
1467
+ await this.request("DELETE", `/memory_banks/${memoryBankId}/source`);
1468
+ }
1469
+ /**
1470
+ * Test compaction for a specific memory bank.
1471
+ *
1472
+ * @param memoryBankId - Memory bank identifier.
1473
+ * @param body - Test compaction request.
1474
+ */
1475
+ async testMemoryBankCompaction(memoryBankId, body) {
1476
+ return await this.request("POST", `/memory_banks/${memoryBankId}/test-compaction`, { json: body });
1477
+ }
1478
+ /**
1479
+ * Test compaction prompt standalone (not tied to a specific memory bank).
1480
+ *
1481
+ * @param body - Standalone compaction test request.
1482
+ */
1483
+ async testCompactionPromptStandalone(body) {
1484
+ return await this.request("POST", "/memory_banks/test-compaction", { json: body });
1485
+ }
1486
+ /**
1487
+ * List available memory bank templates.
1488
+ */
1489
+ async listMemoryBankTemplates() {
1490
+ return await this.request("GET", "/memory_banks/templates");
1491
+ }
1492
+ // ─── Memory Bank AI Assistant ──────────────────────────────────────────────
1493
+ /**
1494
+ * Generate memory bank configuration using AI.
1495
+ *
1496
+ * @param body - AI assistant request with user instructions.
1497
+ * @returns AI-generated memory bank config.
1498
+ */
1499
+ async generateMemoryBankConfig(body) {
1500
+ return await this.request("POST", "/memory_banks/ai-assistant", { json: body });
1501
+ }
1502
+ /**
1503
+ * Get the last AI conversation for memory banks.
1504
+ */
1505
+ async getMemoryBankAiLastConversation() {
1506
+ return await this.request("GET", "/memory_banks/ai-assistant/last-conversation");
1507
+ }
1508
+ /**
1509
+ * Accept a memory bank AI suggestion.
1510
+ *
1511
+ * @param conversationId - Conversation identifier.
1512
+ * @param body - Accept request payload.
1513
+ */
1514
+ async acceptMemoryBankAiSuggestion(conversationId, body) {
1515
+ return await this.request("PATCH", `/memory_banks/ai-assistant/${conversationId}`, { json: body });
1516
+ }
1517
+ // ═══════════════════════════════════════════════════════════════════════════
1518
+ // Sources
1519
+ // ═══════════════════════════════════════════════════════════════════════════
1520
+ /**
1521
+ * List sources.
1522
+ *
1523
+ * @param opts - Pagination, sorting, and filter options.
1524
+ * @returns Paginated list of sources.
1525
+ */
1526
+ async listSources(opts = {}) {
1527
+ return await this.request("GET", "/sources/", {
1528
+ query: {
1529
+ page: opts.page,
1530
+ limit: opts.limit,
1531
+ sort: opts.sort,
1532
+ order: opts.order,
1533
+ account_id: opts.accountId
1534
+ }
1535
+ });
1536
+ }
1537
+ /**
1538
+ * Create a new content source.
1539
+ *
1540
+ * @param body - Source configuration (type, name, knowledge base link, etc.).
1541
+ * @returns The created source.
1542
+ */
1543
+ async createSource(body) {
1544
+ return await this.request("POST", "/sources", { json: body });
1545
+ }
1546
+ /**
1547
+ * Get a source by ID.
1548
+ *
1549
+ * @param sourceId - Source connection identifier.
1550
+ * @returns Source details.
1551
+ */
1552
+ async getSource(sourceId) {
1553
+ return await this.request("GET", `/sources/${sourceId}`);
1554
+ }
1555
+ /**
1556
+ * Update a source.
1557
+ *
1558
+ * @param sourceId - Source connection identifier.
1559
+ * @param body - Fields to update.
1560
+ * @returns Updated source.
1561
+ */
1562
+ async updateSource(sourceId, body) {
1563
+ return await this.request("PUT", `/sources/${sourceId}`, { json: body });
1564
+ }
1565
+ /**
1566
+ * Delete a source.
1567
+ *
1568
+ * @param sourceId - Source connection identifier.
1569
+ */
1570
+ async deleteSource(sourceId) {
1571
+ await this.request("DELETE", `/sources/${sourceId}`);
1572
+ }
1573
+ /**
1574
+ * Upload a file to a source.
1575
+ *
1576
+ * Maximum file size: 200 MiB. Supports text, PDF, DOCX, audio, video, images, and more.
1577
+ * If `mimeType` is omitted, it will be inferred from the `fileName` extension when possible.
1578
+ *
1579
+ * @param sourceId - Source connection identifier.
1580
+ * @param opts - File payload and optional metadata.
1581
+ * @returns Upload response details.
1582
+ */
1583
+ async uploadFileToSource(sourceId, opts) {
1584
+ return await this.uploadFile(`/sources/${sourceId}/upload`, opts);
1585
+ }
1586
+ /**
1587
+ * Upload inline text to a source.
1588
+ *
1589
+ * @param sourceId - Source connection identifier.
1590
+ * @param body - Inline text upload payload.
1591
+ * @returns Upload response.
1592
+ */
1593
+ async uploadInlineTextToSource(sourceId, body) {
1594
+ return await this.request("POST", `/sources/${sourceId}`, { json: body });
1595
+ }
1596
+ // ─── Source Exports ────────────────────────────────────────────────────────
1597
+ /**
1598
+ * List exports for a source.
1599
+ *
1600
+ * @param sourceId - Source connection identifier.
1601
+ * @param opts - Pagination options.
1602
+ * @returns Paginated list of exports.
1603
+ */
1604
+ async listSourceExports(sourceId, opts = {}) {
1605
+ return await this.request("GET", `/sources/${sourceId}/exports`, {
1606
+ query: { page: opts.page, limit: opts.limit }
1607
+ });
1608
+ }
1609
+ /**
1610
+ * Create a source data export.
1611
+ *
1612
+ * @param sourceId - Source connection identifier.
1613
+ * @param body - Export configuration (format, etc.).
1614
+ * @returns Export response with job status.
1615
+ */
1616
+ async createSourceExport(sourceId, body) {
1617
+ return await this.request("POST", `/sources/${sourceId}/exports`, { json: body });
1618
+ }
1619
+ /**
1620
+ * Get a specific source export.
1621
+ *
1622
+ * @param sourceId - Source connection identifier.
1623
+ * @param exportId - Export identifier.
1624
+ * @returns Export details.
1625
+ */
1626
+ async getSourceExport(sourceId, exportId) {
1627
+ return await this.request("GET", `/sources/${sourceId}/exports/${exportId}`);
1628
+ }
1629
+ /**
1630
+ * Cancel a source export.
1631
+ *
1632
+ * @param sourceId - Source connection identifier.
1633
+ * @param exportId - Export identifier.
1634
+ */
1635
+ async cancelSourceExport(sourceId, exportId) {
1636
+ return await this.request("POST", `/sources/${sourceId}/exports/${exportId}/cancel`);
1637
+ }
1638
+ /**
1639
+ * Download a source export file.
1640
+ *
1641
+ * Returns the raw `Response` so you can stream or save the binary data.
1642
+ *
1643
+ * @param sourceId - Source connection identifier.
1644
+ * @param exportId - Export identifier.
1645
+ * @returns Raw response with the export file.
1646
+ */
1647
+ async downloadSourceExport(sourceId, exportId) {
1648
+ return await this.requestRaw("GET", `/sources/${sourceId}/exports/${exportId}/download`);
1649
+ }
1650
+ /**
1651
+ * Estimate a source export.
1652
+ *
1653
+ * @param sourceId - Source connection identifier.
1654
+ * @param body - Estimate request.
1655
+ * @returns Export estimate.
1656
+ */
1657
+ async estimateSourceExport(sourceId, body) {
1658
+ return await this.request("POST", `/sources/${sourceId}/exports/estimate`, { json: body });
1659
+ }
1660
+ /**
1661
+ * Delete a source export.
1662
+ *
1663
+ * @param sourceId - Source connection identifier.
1664
+ * @param exportId - Export identifier.
1665
+ */
1666
+ async deleteSourceExport(sourceId, exportId) {
1667
+ await this.request("DELETE", `/sources/${sourceId}/exports/${exportId}`);
1668
+ }
1669
+ // ─── Source Embedding Migrations ───────────────────────────────────────────
1670
+ /**
1671
+ * Get the status of a source embedding migration.
1672
+ *
1673
+ * @param sourceId - Source connection identifier.
1674
+ * @returns Migration status.
1675
+ */
1676
+ async getSourceEmbeddingMigration(sourceId) {
1677
+ return await this.request("GET", `/sources/${sourceId}/embedding-migration`);
1678
+ }
1679
+ /**
1680
+ * Start a source embedding migration.
1681
+ *
1682
+ * @param sourceId - Source connection identifier.
1683
+ * @param body - Migration configuration (target embedding model, etc.).
1684
+ * @returns Migration status.
1685
+ */
1686
+ async startSourceEmbeddingMigration(sourceId, body) {
1687
+ return await this.request("POST", `/sources/${sourceId}/embedding-migration`, { json: body });
1688
+ }
1689
+ /**
1690
+ * Cancel a source embedding migration.
1691
+ *
1692
+ * @param sourceId - Source connection identifier.
1693
+ * @returns Updated migration status.
1694
+ */
1695
+ async cancelSourceEmbeddingMigration(sourceId) {
1696
+ return await this.request("POST", `/sources/${sourceId}/embedding-migration/cancel`);
1697
+ }
1698
+ // ═══════════════════════════════════════════════════════════════════════════
1699
+ // Content
1700
+ // ═══════════════════════════════════════════════════════════════════════════
1701
+ /**
1702
+ * Get content detail for a specific content version.
1703
+ *
1704
+ * @param contentVersionId - Content version identifier.
1705
+ * @param opts - Range options for slicing large content.
1706
+ * @returns Content details for the requested range.
1707
+ */
1708
+ async getContentDetail(contentVersionId, opts = {}) {
1709
+ return await this.request("GET", `/contents/${contentVersionId}`, {
1710
+ query: { start: opts.start ?? 0, end: opts.end ?? 5e3 }
1711
+ });
1712
+ }
1713
+ /**
1714
+ * Replace content with inline text.
1715
+ *
1716
+ * @param contentVersionId - Content version identifier.
1717
+ * @param body - Inline text replacement payload.
1718
+ */
1719
+ async replaceContentWithInlineText(contentVersionId, body) {
1720
+ return await this.request("PUT", `/contents/${contentVersionId}`, { json: body });
1721
+ }
1722
+ /**
1723
+ * Delete a specific content version.
1724
+ *
1725
+ * @param contentVersionId - Content version identifier.
1726
+ */
1727
+ async deleteContent(contentVersionId) {
1728
+ await this.request("DELETE", `/contents/${contentVersionId}`);
1729
+ }
1730
+ /**
1731
+ * List embeddings for a content version.
1732
+ *
1733
+ * @param contentVersionId - Content version identifier.
1734
+ * @param opts - Pagination options.
1735
+ * @returns Paginated list of embeddings.
1736
+ */
1737
+ async listContentEmbeddings(contentVersionId, opts = {}) {
1738
+ return await this.request("GET", `/contents/${contentVersionId}/embeddings`, {
1739
+ query: { page: opts.page ?? 1, limit: opts.limit ?? 20 }
1740
+ });
1741
+ }
1742
+ /**
1743
+ * Upload a file to replace content for an existing content version.
1744
+ *
1745
+ * @param contentVersionId - Content version identifier.
1746
+ * @param opts - File payload and optional metadata.
1747
+ * @returns Upload response.
1748
+ */
1749
+ async uploadFileToContent(contentVersionId, opts) {
1750
+ return await this.uploadFile(`/contents/${contentVersionId}/upload`, opts);
1751
+ }
1752
+ // ═══════════════════════════════════════════════════════════════════════════
1753
+ // Solutions
1754
+ // ═══════════════════════════════════════════════════════════════════════════
1755
+ /**
1756
+ * List solutions.
1757
+ *
1758
+ * @param opts - Pagination and sorting options.
1759
+ * @returns Paginated list of solutions.
1760
+ */
1761
+ async listSolutions(opts = {}) {
1762
+ return await this.request("GET", "/solutions", {
1763
+ query: { page: opts.page, limit: opts.limit, sort: opts.sort, order: opts.order }
1764
+ });
1765
+ }
1766
+ /**
1767
+ * Create a new solution.
1768
+ *
1769
+ * @param body - Solution configuration.
1770
+ * @returns The created solution.
1771
+ */
1772
+ async createSolution(body) {
1773
+ return await this.request("POST", "/solutions", { json: body });
1774
+ }
1775
+ /**
1776
+ * Get a solution by ID.
1777
+ *
1778
+ * @param solutionId - Solution identifier.
1779
+ * @returns Solution details.
1780
+ */
1781
+ async getSolution(solutionId) {
1782
+ return await this.request("GET", `/solutions/${solutionId}`);
1783
+ }
1784
+ /**
1785
+ * Update a solution.
1786
+ *
1787
+ * @param solutionId - Solution identifier.
1788
+ * @param body - Fields to update.
1789
+ * @returns Updated solution.
1790
+ */
1791
+ async updateSolution(solutionId, body) {
1792
+ return await this.request("PATCH", `/solutions/${solutionId}`, { json: body });
1793
+ }
1794
+ /**
1795
+ * Delete a solution.
1796
+ *
1797
+ * @param solutionId - Solution identifier.
1798
+ */
1799
+ async deleteSolution(solutionId) {
1800
+ await this.request("DELETE", `/solutions/${solutionId}`);
1801
+ }
1802
+ // ─── Solution Resource Linking ─────────────────────────────────────────────
1803
+ /**
1804
+ * Link agents to a solution.
1805
+ *
1806
+ * @param solutionId - Solution identifier.
1807
+ * @param body - Resource IDs to link.
1808
+ * @returns Updated solution.
1809
+ */
1810
+ async linkAgentsToSolution(solutionId, body) {
1811
+ return await this.request("POST", `/solutions/${solutionId}/agents`, { json: body });
1812
+ }
1813
+ /**
1814
+ * Unlink agents from a solution.
1815
+ *
1816
+ * @param solutionId - Solution identifier.
1817
+ * @param body - Resource IDs to unlink.
1818
+ * @returns Updated solution.
1819
+ */
1820
+ async unlinkAgentsFromSolution(solutionId, body) {
1821
+ return await this.request("DELETE", `/solutions/${solutionId}/agents`, { json: body });
1822
+ }
1823
+ /**
1824
+ * Link knowledge bases to a solution.
1825
+ *
1826
+ * @param solutionId - Solution identifier.
1827
+ * @param body - Resource IDs to link.
1828
+ * @returns Updated solution.
1829
+ */
1830
+ async linkKnowledgeBasesToSolution(solutionId, body) {
1831
+ return await this.request("POST", `/solutions/${solutionId}/knowledge-bases`, { json: body });
1832
+ }
1833
+ /**
1834
+ * Unlink knowledge bases from a solution.
1835
+ *
1836
+ * @param solutionId - Solution identifier.
1837
+ * @param body - Resource IDs to unlink.
1838
+ * @returns Updated solution.
1839
+ */
1840
+ async unlinkKnowledgeBasesFromSolution(solutionId, body) {
1841
+ return await this.request("DELETE", `/solutions/${solutionId}/knowledge-bases`, { json: body });
1842
+ }
1843
+ /**
1844
+ * Link source connections to a solution.
1845
+ *
1846
+ * @param solutionId - Solution identifier.
1847
+ * @param body - Resource IDs to link.
1848
+ * @returns Updated solution.
1849
+ */
1850
+ async linkSourceConnectionsToSolution(solutionId, body) {
1851
+ return await this.request("POST", `/solutions/${solutionId}/source-connections`, { json: body });
1852
+ }
1853
+ /**
1854
+ * Unlink source connections from a solution.
1855
+ *
1856
+ * @param solutionId - Solution identifier.
1857
+ * @param body - Resource IDs to unlink.
1858
+ * @returns Updated solution.
1859
+ */
1860
+ async unlinkSourceConnectionsFromSolution(solutionId, body) {
1861
+ return await this.request("DELETE", `/solutions/${solutionId}/source-connections`, { json: body });
1862
+ }
1863
+ // ─── Solution Conversations ────────────────────────────────────────────────
1864
+ /**
1865
+ * List conversations for a solution.
1866
+ *
1867
+ * @param solutionId - Solution identifier.
1868
+ * @returns List of conversations.
1869
+ */
1870
+ async listSolutionConversations(solutionId) {
1871
+ return await this.request("GET", `/solutions/${solutionId}/conversations`);
1872
+ }
1873
+ /**
1874
+ * Add a conversation turn to a solution.
1875
+ *
1876
+ * @param solutionId - Solution identifier.
1877
+ * @param body - Conversation turn payload.
1878
+ * @returns Updated conversation.
1879
+ */
1880
+ async addSolutionConversationTurn(solutionId, body) {
1881
+ return await this.request("POST", `/solutions/${solutionId}/conversations`, { json: body });
1882
+ }
1883
+ /**
1884
+ * Mark a conversation turn (e.g. accepted/rejected).
1885
+ *
1886
+ * @param solutionId - Solution identifier.
1887
+ * @param conversationId - Conversation identifier.
1888
+ * @param body - Mark payload.
1889
+ */
1890
+ async markSolutionConversationTurn(solutionId, conversationId, body) {
1891
+ await this.request("PATCH", `/solutions/${solutionId}/conversations/${conversationId}`, { json: body });
1892
+ }
1893
+ // ─── Solution AI Assistant ─────────────────────────────────────────────────
1894
+ /**
1895
+ * Generate a solution AI plan.
1896
+ *
1897
+ * @param solutionId - Solution identifier.
1898
+ * @param body - Generation request.
1899
+ * @returns AI-generated plan.
1900
+ */
1901
+ async generateSolutionAiPlan(solutionId, body) {
1902
+ return await this.request("POST", `/solutions/${solutionId}/ai-assistant/generate`, { json: body });
1903
+ }
1904
+ /**
1905
+ * Generate a knowledge base configuration via solution AI.
1906
+ *
1907
+ * @param solutionId - Solution identifier.
1908
+ * @param body - Generation request.
1909
+ * @returns AI-generated knowledge base config.
1910
+ */
1911
+ async generateSolutionAiKnowledgeBase(solutionId, body) {
1912
+ return await this.request("POST", `/solutions/${solutionId}/ai-assistant/knowledge-base`, { json: body });
1913
+ }
1914
+ /**
1915
+ * Generate a source configuration via solution AI.
1916
+ *
1917
+ * @param solutionId - Solution identifier.
1918
+ * @param body - Generation request.
1919
+ * @returns AI-generated source config.
1920
+ */
1921
+ async generateSolutionAiSource(solutionId, body) {
1922
+ return await this.request("POST", `/solutions/${solutionId}/ai-assistant/source`, { json: body });
1923
+ }
1924
+ /**
1925
+ * Accept a solution AI plan.
1926
+ *
1927
+ * @param solutionId - Solution identifier.
1928
+ * @param conversationId - Conversation identifier.
1929
+ * @param body - Accept request.
1930
+ * @returns Acceptance result with executed actions.
1931
+ */
1932
+ async acceptSolutionAiPlan(solutionId, conversationId, body) {
1933
+ return await this.request("POST", `/solutions/${solutionId}/ai-assistant/${conversationId}/accept`, { json: body });
1934
+ }
1935
+ /**
1936
+ * Decline a solution AI plan.
1937
+ *
1938
+ * @param solutionId - Solution identifier.
1939
+ * @param conversationId - Conversation identifier.
1940
+ */
1941
+ async declineSolutionAiPlan(solutionId, conversationId) {
1942
+ await this.request("POST", `/solutions/${solutionId}/ai-assistant/${conversationId}/decline`);
1943
+ }
1944
+ // ═══════════════════════════════════════════════════════════════════════════
1945
+ // Governance — AI Assistant
1946
+ // ═══════════════════════════════════════════════════════════════════════════
1947
+ /**
1948
+ * Generate governance policy suggestions using AI.
1949
+ *
1950
+ * @param body - AI governance request.
1951
+ * @returns AI-generated governance suggestions.
1952
+ */
1953
+ async generateGovernanceAiPlan(body) {
1954
+ return await this.request("POST", "/governance/ai-assistant", { json: body });
1955
+ }
1956
+ /**
1957
+ * List governance AI conversations.
1958
+ */
1959
+ async listGovernanceAiConversations() {
1960
+ return await this.request("GET", "/governance/ai-assistant/conversations");
1961
+ }
1962
+ /**
1963
+ * Accept a governance AI plan.
1964
+ *
1965
+ * @param conversationId - Conversation identifier.
1966
+ * @returns Acceptance result.
1967
+ */
1968
+ async acceptGovernanceAiPlan(conversationId) {
1969
+ return await this.request("POST", `/governance/ai-assistant/${conversationId}/accept`);
1970
+ }
1971
+ /**
1972
+ * Decline a governance AI plan.
1973
+ *
1974
+ * @param conversationId - Conversation identifier.
1975
+ */
1976
+ async declineGovernanceAiPlan(conversationId) {
1977
+ await this.request("POST", `/governance/ai-assistant/${conversationId}/decline`);
1978
+ }
1979
+ // ═══════════════════════════════════════════════════════════════════════════
1980
+ // Alerts
1981
+ // ═══════════════════════════════════════════════════════════════════════════
1982
+ /**
1983
+ * List alerts.
1984
+ *
1985
+ * @param opts - Pagination and filter options.
1986
+ * @returns Paginated list of alerts.
1987
+ */
1988
+ async listAlerts(opts = {}) {
1989
+ return await this.request("GET", "/alerts", {
1990
+ query: { page: opts.page, limit: opts.limit, status: opts.status, severity: opts.severity }
1991
+ });
1992
+ }
1993
+ /**
1994
+ * Get alert details by ID.
1995
+ *
1996
+ * @param alertId - Alert identifier.
1997
+ * @returns Alert details.
1998
+ */
1999
+ async getAlert(alertId) {
2000
+ return await this.request("GET", `/alerts/${alertId}`);
2001
+ }
2002
+ /**
2003
+ * Change the status of an alert.
2004
+ *
2005
+ * @param alertId - Alert identifier.
2006
+ * @param body - Status change request.
2007
+ */
2008
+ async changeAlertStatus(alertId, body) {
2009
+ return await this.request("POST", `/alerts/${alertId}/status`, { json: body });
2010
+ }
2011
+ /**
2012
+ * Add a comment to an alert.
2013
+ *
2014
+ * @param alertId - Alert identifier.
2015
+ * @param body - Comment payload.
2016
+ */
2017
+ async addAlertComment(alertId, body) {
2018
+ return await this.request("POST", `/alerts/${alertId}/comments`, { json: body });
2019
+ }
2020
+ /**
2021
+ * Subscribe to an alert.
2022
+ *
2023
+ * @param alertId - Alert identifier.
2024
+ */
2025
+ async subscribeToAlert(alertId) {
2026
+ return await this.request("POST", `/alerts/${alertId}/subscribe`);
2027
+ }
2028
+ /**
2029
+ * Unsubscribe from an alert.
2030
+ *
2031
+ * @param alertId - Alert identifier.
2032
+ */
2033
+ async unsubscribeFromAlert(alertId) {
2034
+ return await this.request("POST", `/alerts/${alertId}/unsubscribe`);
2035
+ }
2036
+ // ─── Alert Configs ─────────────────────────────────────────────────────────
2037
+ /**
2038
+ * List alert configurations.
2039
+ *
2040
+ * @param opts - Pagination options.
2041
+ * @returns Paginated list of alert configs.
2042
+ */
2043
+ async listAlertConfigs(opts = {}) {
2044
+ return await this.request("GET", "/alerts/configs", {
2045
+ query: { page: opts.page, limit: opts.limit }
2046
+ });
2047
+ }
2048
+ /**
2049
+ * Create an alert configuration.
2050
+ *
2051
+ * @param body - Alert config definition.
2052
+ * @returns Created alert config.
2053
+ */
2054
+ async createAlertConfig(body) {
2055
+ return await this.request("POST", "/alerts/configs", { json: body });
2056
+ }
2057
+ /**
2058
+ * Get an alert configuration by ID.
2059
+ *
2060
+ * @param configId - Alert config identifier.
2061
+ * @returns Alert config details.
2062
+ */
2063
+ async getAlertConfig(configId) {
2064
+ return await this.request("GET", `/alerts/configs/${configId}`);
2065
+ }
2066
+ /**
2067
+ * Update an alert configuration.
2068
+ *
2069
+ * @param configId - Alert config identifier.
2070
+ * @param body - Fields to update.
2071
+ * @returns Updated alert config.
2072
+ */
2073
+ async updateAlertConfig(configId, body) {
2074
+ return await this.request("PATCH", `/alerts/configs/${configId}`, { json: body });
2075
+ }
2076
+ /**
2077
+ * Delete an alert configuration.
2078
+ *
2079
+ * @param configId - Alert config identifier.
2080
+ */
2081
+ async deleteAlertConfig(configId) {
2082
+ await this.request("DELETE", `/alerts/configs/${configId}`);
2083
+ }
2084
+ // ─── Organization Alert Preferences ────────────────────────────────────────
2085
+ /**
2086
+ * List organization alert preferences.
2087
+ */
2088
+ async listOrganizationAlertPreferences() {
2089
+ return await this.request("GET", "/alerts/organization-preferences/list");
2090
+ }
2091
+ /**
2092
+ * Update an organization alert preference.
2093
+ *
2094
+ * @param organizationId - Organization identifier.
2095
+ * @param alertType - Alert type.
2096
+ * @param body - Preference update.
2097
+ */
2098
+ async updateOrganizationAlertPreference(organizationId, alertType, body) {
2099
+ return await this.request("PATCH", `/alerts/organization-preferences/${organizationId}/${alertType}`, { json: body });
2100
+ }
2101
+ // ═══════════════════════════════════════════════════════════════════════════
2102
+ // Models & Model Alerts
2103
+ // ═══════════════════════════════════════════════════════════════════════════
2104
+ /**
2105
+ * List model alerts.
2106
+ *
2107
+ * @param opts - Pagination options.
2108
+ */
2109
+ async listModelAlerts(opts = {}) {
2110
+ return await this.request("GET", "/models/alerts", {
2111
+ query: { page: opts.page, limit: opts.limit }
2112
+ });
2113
+ }
2114
+ /**
2115
+ * Mark all model alerts as read.
2116
+ */
2117
+ async markAllModelAlertsRead() {
2118
+ await this.request("POST", "/models/alerts/mark-all-read");
2119
+ }
2120
+ /**
2121
+ * Get unread model alert count.
2122
+ */
2123
+ async getUnreadModelAlertCount() {
2124
+ return await this.request("GET", "/models/alerts/unread-count");
2125
+ }
2126
+ /**
2127
+ * Mark a specific model alert as read.
2128
+ *
2129
+ * @param alertId - Model alert identifier.
2130
+ */
2131
+ async markModelAlertRead(alertId) {
2132
+ await this.request("PATCH", `/models/alerts/${alertId}/read`);
2133
+ }
2134
+ /**
2135
+ * Get model recommendations.
2136
+ *
2137
+ * @param modelId - Model identifier.
2138
+ */
2139
+ async getModelRecommendations(modelId) {
2140
+ return await this.request("GET", `/models/${modelId}/recommendations`);
2141
+ }
2142
+ // ═══════════════════════════════════════════════════════════════════════════
2143
+ // Search
2144
+ // ═══════════════════════════════════════════════════════════════════════════
2145
+ /**
2146
+ * Search across all resource types in your account.
2147
+ *
2148
+ * Accepts a free-text keyword query or a UUID. Results are ranked:
2149
+ * name-prefix > name-substring > description-substring.
2150
+ *
2151
+ * @param opts - Search options.
2152
+ * @param opts.query - Search query string (required, 1-200 chars).
2153
+ * @param opts.limit - Maximum results (1-50, default 10).
2154
+ * @param opts.entityType - Optional entity type filter (e.g. "agent", "knowledge_base").
2155
+ * @returns Search results.
2156
+ */
2157
+ async search(opts) {
2158
+ return await this.request("GET", "/search", {
2159
+ query: { q: opts.query, limit: opts.limit, entity_type: opts.entityType }
2160
+ });
2161
+ }
2162
+ // ═══════════════════════════════════════════════════════════════════════════
2163
+ // Top-Level AI Assistant
2164
+ // ═══════════════════════════════════════════════════════════════════════════
2165
+ /**
2166
+ * Submit feedback on an AI assistant interaction.
2167
+ *
2168
+ * @param body - Feedback payload (thumbs up/down, optional comment).
2169
+ * @returns Feedback response.
2170
+ */
2171
+ async submitAiFeedback(body) {
2172
+ return await this.request("POST", "/ai-assistant/feedback", { json: body });
2173
+ }
2174
+ /**
2175
+ * Generate a knowledge base configuration via AI assistant.
2176
+ *
2177
+ * @param body - Generation request.
2178
+ */
2179
+ async aiAssistantKnowledgeBase(body) {
2180
+ return await this.request("POST", "/ai-assistant/knowledge-base", { json: body });
2181
+ }
2182
+ /**
2183
+ * Generate a source configuration via AI assistant.
2184
+ *
2185
+ * @param body - Generation request.
2186
+ */
2187
+ async aiAssistantSource(body) {
2188
+ return await this.request("POST", "/ai-assistant/source", { json: body });
2189
+ }
2190
+ /**
2191
+ * Generate a solution via AI assistant.
2192
+ *
2193
+ * @param body - Generation request.
2194
+ */
2195
+ async aiAssistantSolution(body) {
2196
+ return await this.request("POST", "/ai-assistant/solution", { json: body });
2197
+ }
2198
+ /**
2199
+ * Generate a memory bank configuration via AI assistant.
2200
+ *
2201
+ * @param body - Generation request.
2202
+ */
2203
+ async aiAssistantMemoryBank(body) {
2204
+ return await this.request("POST", "/ai-assistant/memory-bank", { json: body });
2205
+ }
2206
+ /**
2207
+ * Get AI assistant memory bank conversation history.
2208
+ */
2209
+ async getAiAssistantMemoryBankHistory() {
2210
+ return await this.request("GET", "/ai-assistant/memory-bank/last-conversation");
2211
+ }
2212
+ /**
2213
+ * Accept an AI assistant suggestion.
2214
+ *
2215
+ * @param conversationId - Conversation identifier.
2216
+ * @param body - Acceptance request payload.
2217
+ */
2218
+ async acceptAiAssistantPlan(conversationId, body) {
2219
+ return await this.request("POST", `/ai-assistant/${conversationId}/accept`, { json: body });
2220
+ }
2221
+ /**
2222
+ * Decline an AI assistant suggestion.
2223
+ *
2224
+ * @param conversationId - Conversation identifier.
2225
+ */
2226
+ async declineAiAssistantPlan(conversationId) {
2227
+ await this.request("POST", `/ai-assistant/${conversationId}/decline`);
2228
+ }
2229
+ /**
2230
+ * Accept/mark an AI memory bank suggestion.
2231
+ *
2232
+ * @param conversationId - Conversation identifier.
2233
+ * @param body - Acceptance payload for the memory bank suggestion.
2234
+ */
2235
+ async acceptAiMemoryBankSuggestion(conversationId, body) {
2236
+ return await this.request("PATCH", `/ai-assistant/memory-bank/${conversationId}`, { json: body });
2237
+ }
2238
+ // ═══════════════════════════════════════════════════════════════════════════
2239
+ // Pagination Helpers
2240
+ // ═══════════════════════════════════════════════════════════════════════════
2241
+ /**
2242
+ * Auto-paginate through a list endpoint.
2243
+ *
2244
+ * Yields individual items from each page, automatically fetching the next page
2245
+ * until all items have been returned.
2246
+ *
2247
+ * @param fetchPage - A function that fetches a single page given `{ page, limit }`.
2248
+ * @param opts - Page size (default: 50).
2249
+ *
2250
+ * @example
2251
+ * ```ts
2252
+ * for await (const agent of client.paginate(
2253
+ * (opts) => client.listAgents(opts),
2254
+ * )) {
2255
+ * console.log(agent);
2256
+ * }
2257
+ * ```
2258
+ */
2259
+ async *paginate(fetchPage, opts) {
2260
+ const limit = opts?.limit ?? 50;
2261
+ let page = 1;
2262
+ while (true) {
2263
+ const result = await fetchPage({ page, limit });
2264
+ for (const item of result.items) {
2265
+ yield item;
2266
+ }
2267
+ if (!result.pagination || result.items.length < limit || page >= result.pagination.total_pages) {
2268
+ break;
2269
+ }
2270
+ page++;
2271
+ }
598
2272
  }
599
2273
  };
600
2274
  // Annotate the CommonJS export names for ESM import in node:
@@ -604,6 +2278,7 @@ var Seclai = class {
604
2278
  SeclaiAPIStatusError,
605
2279
  SeclaiAPIValidationError,
606
2280
  SeclaiConfigurationError,
607
- SeclaiError
2281
+ SeclaiError,
2282
+ SeclaiStreamingError
608
2283
  });
609
2284
  //# sourceMappingURL=index.cjs.map