@seclai/sdk 1.1.0 → 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/README.md +46 -5
- package/dist/index.cjs +350 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +476 -364
- package/dist/index.d.ts +476 -364
- package/dist/index.js +340 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -48,9 +48,283 @@ var SeclaiStreamingError = class extends SeclaiError {
|
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
+
// src/auth.ts
|
|
52
|
+
var DEFAULT_CONFIG_DIR = ".seclai";
|
|
53
|
+
var SSO_CACHE_DIR = "sso/cache";
|
|
54
|
+
var CONFIG_FILE = "config";
|
|
55
|
+
var EXPIRY_BUFFER_MS = 3e4;
|
|
56
|
+
var DEFAULT_API_KEY_HEADER = "x-api-key";
|
|
57
|
+
function getEnv(name) {
|
|
58
|
+
const p = globalThis?.process;
|
|
59
|
+
return p?.env?.[name];
|
|
60
|
+
}
|
|
61
|
+
function getHomeDir() {
|
|
62
|
+
const p = globalThis?.process;
|
|
63
|
+
return p?.env?.HOME ?? p?.env?.USERPROFILE;
|
|
64
|
+
}
|
|
65
|
+
async function sha1Hex(input) {
|
|
66
|
+
try {
|
|
67
|
+
const { createHash } = await import("crypto");
|
|
68
|
+
return createHash("sha1").update(input).digest("hex");
|
|
69
|
+
} catch {
|
|
70
|
+
const encoded = new TextEncoder().encode(input);
|
|
71
|
+
const buffer = await crypto.subtle.digest("SHA-1", encoded);
|
|
72
|
+
return Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function cacheFileName(domain, clientId) {
|
|
76
|
+
return sha1Hex(`${domain}|${clientId}`);
|
|
77
|
+
}
|
|
78
|
+
function parseIni(content) {
|
|
79
|
+
const sections = {};
|
|
80
|
+
let currentSection = null;
|
|
81
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
82
|
+
const line = rawLine.trim();
|
|
83
|
+
if (!line || line.startsWith("#") || line.startsWith(";")) continue;
|
|
84
|
+
const sectionMatch = line.match(/^\[(.+)\]$/);
|
|
85
|
+
if (sectionMatch) {
|
|
86
|
+
const raw = sectionMatch[1].trim();
|
|
87
|
+
currentSection = raw.startsWith("profile ") ? raw.slice("profile ".length).trim() : raw;
|
|
88
|
+
sections[currentSection] ??= {};
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (currentSection !== null) {
|
|
92
|
+
const eqIdx = line.indexOf("=");
|
|
93
|
+
if (eqIdx > 0) {
|
|
94
|
+
const key = line.slice(0, eqIdx).trim();
|
|
95
|
+
const value = line.slice(eqIdx + 1).trim();
|
|
96
|
+
sections[currentSection][key] = value;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return sections;
|
|
101
|
+
}
|
|
102
|
+
var _fs = null;
|
|
103
|
+
var _path = null;
|
|
104
|
+
async function getFs() {
|
|
105
|
+
if (!_fs) {
|
|
106
|
+
_fs = await import("fs");
|
|
107
|
+
}
|
|
108
|
+
return _fs;
|
|
109
|
+
}
|
|
110
|
+
async function getPath() {
|
|
111
|
+
if (!_path) {
|
|
112
|
+
_path = await import("path");
|
|
113
|
+
}
|
|
114
|
+
return _path;
|
|
115
|
+
}
|
|
116
|
+
async function resolveConfigDir(override) {
|
|
117
|
+
if (override) return override;
|
|
118
|
+
const envDir = getEnv("SECLAI_CONFIG_DIR");
|
|
119
|
+
if (envDir) return envDir;
|
|
120
|
+
const home = getHomeDir();
|
|
121
|
+
if (!home) {
|
|
122
|
+
throw new Error("Cannot determine home directory. Set SECLAI_CONFIG_DIR.");
|
|
123
|
+
}
|
|
124
|
+
const pathMod = await getPath();
|
|
125
|
+
return pathMod.join(home, DEFAULT_CONFIG_DIR);
|
|
126
|
+
}
|
|
127
|
+
async function loadSsoProfile(configDir, profileName) {
|
|
128
|
+
const fs = await getFs();
|
|
129
|
+
const pathMod = await getPath();
|
|
130
|
+
const configPath = pathMod.join(configDir, CONFIG_FILE);
|
|
131
|
+
if (!fs.existsSync(configPath)) return null;
|
|
132
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
133
|
+
const sections = parseIni(content);
|
|
134
|
+
const defaultSection = sections["default"] ?? {};
|
|
135
|
+
const profileSection = profileName === "default" ? defaultSection : sections[profileName];
|
|
136
|
+
if (!profileSection) return null;
|
|
137
|
+
const merged = profileName === "default" ? profileSection : { ...defaultSection, ...profileSection };
|
|
138
|
+
const ssoAccountId = merged["sso_account_id"];
|
|
139
|
+
const ssoRegion = merged["sso_region"];
|
|
140
|
+
const ssoClientId = merged["sso_client_id"];
|
|
141
|
+
const ssoDomain = merged["sso_domain"];
|
|
142
|
+
if (!ssoAccountId || !ssoRegion || !ssoClientId || !ssoDomain) return null;
|
|
143
|
+
return { ssoAccountId, ssoRegion, ssoClientId, ssoDomain };
|
|
144
|
+
}
|
|
145
|
+
async function resolveCachePath(configDir, profile) {
|
|
146
|
+
const pathMod = await getPath();
|
|
147
|
+
const hash = await cacheFileName(profile.ssoDomain, profile.ssoClientId);
|
|
148
|
+
return pathMod.join(configDir, SSO_CACHE_DIR, `${hash}.json`);
|
|
149
|
+
}
|
|
150
|
+
async function readSsoCache(configDir, profile) {
|
|
151
|
+
const fs = await getFs();
|
|
152
|
+
const cachePath = await resolveCachePath(configDir, profile);
|
|
153
|
+
if (!fs.existsSync(cachePath)) return null;
|
|
154
|
+
try {
|
|
155
|
+
const raw = fs.readFileSync(cachePath, "utf-8");
|
|
156
|
+
return JSON.parse(raw);
|
|
157
|
+
} catch {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async function writeSsoCache(configDir, profile, entry) {
|
|
162
|
+
const fs = await getFs();
|
|
163
|
+
const pathMod = await getPath();
|
|
164
|
+
const cacheDir = pathMod.join(configDir, SSO_CACHE_DIR);
|
|
165
|
+
fs.mkdirSync(cacheDir, { recursive: true, mode: 448 });
|
|
166
|
+
const cachePath = await resolveCachePath(configDir, profile);
|
|
167
|
+
const tmpPath = `${cachePath}.tmp`;
|
|
168
|
+
fs.writeFileSync(tmpPath, JSON.stringify(entry, null, 2), { mode: 384 });
|
|
169
|
+
if (fs.existsSync(cachePath)) {
|
|
170
|
+
try {
|
|
171
|
+
fs.unlinkSync(cachePath);
|
|
172
|
+
} catch {
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
fs.renameSync(tmpPath, cachePath);
|
|
176
|
+
}
|
|
177
|
+
function isTokenValid(entry) {
|
|
178
|
+
const expiresAt = new Date(entry.expiresAt).getTime();
|
|
179
|
+
return Date.now() + EXPIRY_BUFFER_MS < expiresAt;
|
|
180
|
+
}
|
|
181
|
+
async function refreshToken(profile, refreshTokenValue, fetcher) {
|
|
182
|
+
const tokenUrl = `https://${profile.ssoDomain}/oauth2/token`;
|
|
183
|
+
const body = new URLSearchParams({
|
|
184
|
+
grant_type: "refresh_token",
|
|
185
|
+
client_id: profile.ssoClientId,
|
|
186
|
+
refresh_token: refreshTokenValue
|
|
187
|
+
});
|
|
188
|
+
const response = await fetcher(tokenUrl, {
|
|
189
|
+
method: "POST",
|
|
190
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
191
|
+
body: body.toString()
|
|
192
|
+
});
|
|
193
|
+
if (!response.ok) {
|
|
194
|
+
const text = await response.text().catch(() => "");
|
|
195
|
+
throw new Error(`Token refresh failed (HTTP ${response.status}): ${text}`);
|
|
196
|
+
}
|
|
197
|
+
const data = await response.json();
|
|
198
|
+
const expiresAt = new Date(Date.now() + data.expires_in * 1e3).toISOString();
|
|
199
|
+
return {
|
|
200
|
+
accessToken: data.access_token,
|
|
201
|
+
refreshToken: data.refresh_token ?? refreshTokenValue,
|
|
202
|
+
idToken: data.id_token ?? void 0,
|
|
203
|
+
expiresAt,
|
|
204
|
+
clientId: profile.ssoClientId,
|
|
205
|
+
region: profile.ssoRegion,
|
|
206
|
+
cognitoDomain: profile.ssoDomain
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
async function resolveCredentialChain(opts) {
|
|
210
|
+
const apiKeyHeader = opts.apiKeyHeader ?? DEFAULT_API_KEY_HEADER;
|
|
211
|
+
if (opts.apiKey) {
|
|
212
|
+
return {
|
|
213
|
+
mode: "apiKey",
|
|
214
|
+
apiKey: opts.apiKey,
|
|
215
|
+
apiKeyHeader,
|
|
216
|
+
accountId: opts.accountId,
|
|
217
|
+
autoRefresh: false
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
if (opts.accessToken) {
|
|
221
|
+
return {
|
|
222
|
+
mode: "bearerStatic",
|
|
223
|
+
accessToken: opts.accessToken,
|
|
224
|
+
apiKeyHeader,
|
|
225
|
+
accountId: opts.accountId,
|
|
226
|
+
autoRefresh: false
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
if (opts.accessTokenProvider) {
|
|
230
|
+
return {
|
|
231
|
+
mode: "bearerProvider",
|
|
232
|
+
accessTokenProvider: opts.accessTokenProvider,
|
|
233
|
+
apiKeyHeader,
|
|
234
|
+
accountId: opts.accountId,
|
|
235
|
+
autoRefresh: false
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
const envApiKey = getEnv("SECLAI_API_KEY");
|
|
239
|
+
if (envApiKey) {
|
|
240
|
+
return {
|
|
241
|
+
mode: "apiKey",
|
|
242
|
+
apiKey: envApiKey,
|
|
243
|
+
apiKeyHeader,
|
|
244
|
+
accountId: opts.accountId,
|
|
245
|
+
autoRefresh: false
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
try {
|
|
249
|
+
const configDir = await resolveConfigDir(opts.configDir);
|
|
250
|
+
const profileName = opts.profile ?? getEnv("SECLAI_PROFILE") ?? "default";
|
|
251
|
+
const ssoProfile = await loadSsoProfile(configDir, profileName);
|
|
252
|
+
if (ssoProfile) {
|
|
253
|
+
return {
|
|
254
|
+
mode: "sso",
|
|
255
|
+
apiKeyHeader,
|
|
256
|
+
accountId: opts.accountId ?? ssoProfile.ssoAccountId,
|
|
257
|
+
ssoProfile,
|
|
258
|
+
configDir,
|
|
259
|
+
autoRefresh: opts.autoRefresh !== false,
|
|
260
|
+
fetcher: opts.fetch
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
} catch {
|
|
264
|
+
}
|
|
265
|
+
throw new Error(
|
|
266
|
+
"Missing credentials. Provide apiKey, accessToken, set SECLAI_API_KEY, or run `seclai auth login`."
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
async function resolveAuthHeaders(state) {
|
|
270
|
+
const headers = {};
|
|
271
|
+
switch (state.mode) {
|
|
272
|
+
case "apiKey":
|
|
273
|
+
headers[state.apiKeyHeader] = state.apiKey;
|
|
274
|
+
break;
|
|
275
|
+
case "bearerStatic":
|
|
276
|
+
headers["authorization"] = `Bearer ${state.accessToken}`;
|
|
277
|
+
break;
|
|
278
|
+
case "bearerProvider": {
|
|
279
|
+
const token = await Promise.resolve(state.accessTokenProvider());
|
|
280
|
+
headers["authorization"] = `Bearer ${token}`;
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
case "sso": {
|
|
284
|
+
const token = await resolveSsoToken(state);
|
|
285
|
+
headers["authorization"] = `Bearer ${token}`;
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (state.accountId) {
|
|
290
|
+
headers["x-account-id"] = state.accountId;
|
|
291
|
+
}
|
|
292
|
+
return headers;
|
|
293
|
+
}
|
|
294
|
+
async function resolveSsoToken(state) {
|
|
295
|
+
const profile = state.ssoProfile;
|
|
296
|
+
const configDir = state.configDir;
|
|
297
|
+
const cached = await readSsoCache(configDir, profile);
|
|
298
|
+
if (cached && isTokenValid(cached)) {
|
|
299
|
+
return cached.accessToken;
|
|
300
|
+
}
|
|
301
|
+
if (cached?.refreshToken && state.autoRefresh) {
|
|
302
|
+
if (state._refreshPromise) {
|
|
303
|
+
return state._refreshPromise;
|
|
304
|
+
}
|
|
305
|
+
const fetcher = state.fetcher ?? globalThis.fetch;
|
|
306
|
+
if (!fetcher) {
|
|
307
|
+
throw new Error("No fetch implementation available for token refresh.");
|
|
308
|
+
}
|
|
309
|
+
state._refreshPromise = (async () => {
|
|
310
|
+
try {
|
|
311
|
+
const refreshed = await refreshToken(profile, cached.refreshToken, fetcher);
|
|
312
|
+
await writeSsoCache(configDir, profile, refreshed);
|
|
313
|
+
return refreshed.accessToken;
|
|
314
|
+
} finally {
|
|
315
|
+
state._refreshPromise = void 0;
|
|
316
|
+
}
|
|
317
|
+
})();
|
|
318
|
+
return state._refreshPromise;
|
|
319
|
+
}
|
|
320
|
+
throw new Error(
|
|
321
|
+
`SSO token expired. Run \`seclai auth login\` to re-authenticate.`
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
|
|
51
325
|
// src/client.ts
|
|
52
326
|
var SECLAI_API_URL = "https://api.seclai.com";
|
|
53
|
-
function
|
|
327
|
+
function getEnv2(name) {
|
|
54
328
|
const p = globalThis?.process;
|
|
55
329
|
return p?.env?.[name];
|
|
56
330
|
}
|
|
@@ -177,23 +451,29 @@ function inferMimeType(fileName) {
|
|
|
177
451
|
return ext ? MIME_TYPES[ext] : void 0;
|
|
178
452
|
}
|
|
179
453
|
var Seclai = class {
|
|
180
|
-
apiKey;
|
|
181
454
|
baseUrl;
|
|
182
|
-
apiKeyHeader;
|
|
183
455
|
defaultHeaders;
|
|
184
456
|
fetcher;
|
|
457
|
+
_authState = null;
|
|
458
|
+
_authInitPromise = null;
|
|
459
|
+
_authInitError = null;
|
|
185
460
|
/**
|
|
186
461
|
* Create a new Seclai client.
|
|
187
462
|
*
|
|
463
|
+
* Credentials are resolved via a chain (first match wins):
|
|
464
|
+
* 1. Explicit `apiKey` option
|
|
465
|
+
* 2. Explicit `accessToken` option (static string or provider function)
|
|
466
|
+
* 3. `SECLAI_API_KEY` environment variable
|
|
467
|
+
* 4. SSO profile from `~/.seclai/config` + cached tokens in `~/.seclai/sso/cache/`
|
|
468
|
+
*
|
|
188
469
|
* @param opts - Client configuration.
|
|
189
|
-
* @throws {@link SeclaiConfigurationError} If no API key is provided (and `SECLAI_API_KEY` is not set).
|
|
190
470
|
* @throws {@link SeclaiConfigurationError} If no `fetch` implementation is available.
|
|
471
|
+
* @throws {@link SeclaiConfigurationError} If both `apiKey` and `accessToken` are provided.
|
|
191
472
|
*/
|
|
192
473
|
constructor(opts = {}) {
|
|
193
|
-
|
|
194
|
-
if (!apiKey) {
|
|
474
|
+
if (opts.apiKey && opts.accessToken) {
|
|
195
475
|
throw new SeclaiConfigurationError(
|
|
196
|
-
"
|
|
476
|
+
"Provide either apiKey or accessToken, not both."
|
|
197
477
|
);
|
|
198
478
|
}
|
|
199
479
|
const fetcher = opts.fetch ?? globalThis.fetch;
|
|
@@ -202,11 +482,49 @@ var Seclai = class {
|
|
|
202
482
|
"No fetch implementation available. Provide opts.fetch or run in an environment with global fetch."
|
|
203
483
|
);
|
|
204
484
|
}
|
|
205
|
-
this.
|
|
206
|
-
this.baseUrl = opts.baseUrl ?? getEnv("SECLAI_API_URL") ?? SECLAI_API_URL;
|
|
207
|
-
this.apiKeyHeader = opts.apiKeyHeader ?? "x-api-key";
|
|
485
|
+
this.baseUrl = opts.baseUrl ?? getEnv2("SECLAI_API_URL") ?? SECLAI_API_URL;
|
|
208
486
|
this.defaultHeaders = { ...opts.defaultHeaders ?? {} };
|
|
209
487
|
this.fetcher = fetcher;
|
|
488
|
+
const accessTokenProvider = typeof opts.accessToken === "function" ? opts.accessToken : void 0;
|
|
489
|
+
const accessTokenStatic = typeof opts.accessToken === "string" ? opts.accessToken : void 0;
|
|
490
|
+
this._authInitPromise = resolveCredentialChain({
|
|
491
|
+
apiKey: opts.apiKey,
|
|
492
|
+
accessToken: accessTokenStatic,
|
|
493
|
+
accessTokenProvider,
|
|
494
|
+
profile: opts.profile,
|
|
495
|
+
configDir: opts.configDir,
|
|
496
|
+
autoRefresh: opts.autoRefresh,
|
|
497
|
+
accountId: opts.accountId,
|
|
498
|
+
apiKeyHeader: opts.apiKeyHeader,
|
|
499
|
+
fetch: fetcher
|
|
500
|
+
}).then((state) => {
|
|
501
|
+
this._authState = state;
|
|
502
|
+
}).catch((err) => {
|
|
503
|
+
this._authInitError = new SeclaiConfigurationError(
|
|
504
|
+
err instanceof Error ? err.message : String(err)
|
|
505
|
+
);
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
/** Ensure the credential chain has been resolved. */
|
|
509
|
+
async ensureAuth() {
|
|
510
|
+
if (this._authInitPromise) {
|
|
511
|
+
await this._authInitPromise;
|
|
512
|
+
this._authInitPromise = null;
|
|
513
|
+
}
|
|
514
|
+
if (this._authInitError) {
|
|
515
|
+
throw this._authInitError;
|
|
516
|
+
}
|
|
517
|
+
if (!this._authState) {
|
|
518
|
+
throw new SeclaiConfigurationError(
|
|
519
|
+
"Missing credentials. Provide apiKey, accessToken, set SECLAI_API_KEY, or run `seclai auth login`."
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
return this._authState;
|
|
523
|
+
}
|
|
524
|
+
/** Resolve auth headers for the current request. */
|
|
525
|
+
async authHeaders() {
|
|
526
|
+
const state = await this.ensureAuth();
|
|
527
|
+
return resolveAuthHeaders(state);
|
|
210
528
|
}
|
|
211
529
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
212
530
|
// Low-level request
|
|
@@ -225,10 +543,11 @@ var Seclai = class {
|
|
|
225
543
|
*/
|
|
226
544
|
async request(method, path, opts) {
|
|
227
545
|
const url = buildURL(this.baseUrl, path, opts?.query);
|
|
546
|
+
const authHeaders = await this.authHeaders();
|
|
228
547
|
const headers = {
|
|
229
548
|
...this.defaultHeaders,
|
|
230
549
|
...opts?.headers ?? {},
|
|
231
|
-
|
|
550
|
+
...authHeaders
|
|
232
551
|
};
|
|
233
552
|
let body;
|
|
234
553
|
if (opts?.json !== void 0) {
|
|
@@ -280,13 +599,16 @@ var Seclai = class {
|
|
|
280
599
|
* @param path - Request path relative to `baseUrl`.
|
|
281
600
|
* @param opts - Query params, JSON body, per-request headers, and optional AbortSignal.
|
|
282
601
|
* @returns The raw `Response` object.
|
|
602
|
+
* @throws {SeclaiAPIValidationError} On HTTP 422 responses.
|
|
603
|
+
* @throws {SeclaiAPIStatusError} On other non-2xx responses.
|
|
283
604
|
*/
|
|
284
605
|
async requestRaw(method, path, opts) {
|
|
285
606
|
const url = buildURL(this.baseUrl, path, opts?.query);
|
|
607
|
+
const authHeaders = await this.authHeaders();
|
|
286
608
|
const headers = {
|
|
287
609
|
...this.defaultHeaders,
|
|
288
610
|
...opts?.headers ?? {},
|
|
289
|
-
|
|
611
|
+
...authHeaders
|
|
290
612
|
};
|
|
291
613
|
let body;
|
|
292
614
|
if (opts?.json !== void 0) {
|
|
@@ -323,9 +645,10 @@ var Seclai = class {
|
|
|
323
645
|
/** Shared multipart upload helper. */
|
|
324
646
|
async uploadFile(path, opts) {
|
|
325
647
|
const url = buildURL(this.baseUrl, path);
|
|
648
|
+
const authHeaders = await this.authHeaders();
|
|
326
649
|
const headers = {
|
|
327
650
|
...this.defaultHeaders,
|
|
328
|
-
|
|
651
|
+
...authHeaders
|
|
329
652
|
};
|
|
330
653
|
delete headers["content-type"];
|
|
331
654
|
delete headers["Content-Type"];
|
|
@@ -513,9 +836,10 @@ var Seclai = class {
|
|
|
513
836
|
*/
|
|
514
837
|
async runStreamingAgentAndWait(agentId, body, opts) {
|
|
515
838
|
const url = buildURL(this.baseUrl, `/agents/${agentId}/runs/stream`);
|
|
839
|
+
const authHdrs = await this.authHeaders();
|
|
516
840
|
const headers = {
|
|
517
841
|
...this.defaultHeaders,
|
|
518
|
-
|
|
842
|
+
...authHdrs,
|
|
519
843
|
accept: "text/event-stream",
|
|
520
844
|
"content-type": "application/json"
|
|
521
845
|
};
|
|
@@ -622,9 +946,10 @@ var Seclai = class {
|
|
|
622
946
|
*/
|
|
623
947
|
async *runStreamingAgent(agentId, body, opts) {
|
|
624
948
|
const url = buildURL(this.baseUrl, `/agents/${agentId}/runs/stream`);
|
|
949
|
+
const authHdrs = await this.authHeaders();
|
|
625
950
|
const headers = {
|
|
626
951
|
...this.defaultHeaders,
|
|
627
|
-
|
|
952
|
+
...authHdrs,
|
|
628
953
|
accept: "text/event-stream",
|
|
629
954
|
"content-type": "application/json"
|
|
630
955
|
};
|