@opengeni/sdk 3.1.0 → 3.3.2
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 +60 -8
- package/dist/accounts.d.ts +5 -1
- package/dist/accounts.js +13 -1
- package/dist/accounts.js.map +1 -1
- package/dist/artifacts.js +5 -5
- package/dist/browser.js +3 -3
- package/dist/{chunk-YTAWBDO2.js → chunk-JUS2UYRP.js} +2 -1
- package/dist/chunk-JUS2UYRP.js.map +1 -0
- package/dist/{chunk-GW3EJ2GP.js → chunk-KKRO2VCP.js} +27 -2
- package/dist/{chunk-GW3EJ2GP.js.map → chunk-KKRO2VCP.js.map} +1 -1
- package/dist/{chunk-VUQZAB3O.js → chunk-QT3KFVDP.js} +2 -2
- package/dist/{chunk-7ZXBPJZP.js → chunk-TRNI7KEO.js} +213 -42
- package/dist/chunk-TRNI7KEO.js.map +1 -0
- package/dist/{chunk-TX3EIENU.js → chunk-YXQX7RQT.js} +2 -2
- package/dist/client.d.ts +35 -11
- package/dist/company-profile.d.ts +13 -0
- package/dist/core.js +4 -4
- package/dist/document-authority.js +4 -4
- package/dist/editable-artifacts.js +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +215 -5
- package/dist/index.js.map +1 -1
- package/dist/interaction.d.ts +3 -0
- package/dist/interaction.js +3 -1
- package/dist/realtime.d.ts +3 -1
- package/dist/realtime.js.map +1 -1
- package/dist/session-titles.d.ts +28 -0
- package/dist/types.d.ts +58 -2
- package/package.json +2 -2
- package/src/accounts.ts +18 -0
- package/src/client.ts +291 -35
- package/src/company-profile.ts +13 -0
- package/src/index.ts +18 -0
- package/src/interaction.ts +32 -0
- package/src/realtime.ts +1 -0
- package/src/session-titles.ts +84 -0
- package/src/types.ts +64 -1
- package/dist/chunk-7ZXBPJZP.js.map +0 -1
- package/dist/chunk-YTAWBDO2.js.map +0 -1
- /package/dist/{chunk-VUQZAB3O.js.map → chunk-QT3KFVDP.js.map} +0 -0
- /package/dist/{chunk-TX3EIENU.js.map → chunk-YXQX7RQT.js.map} +0 -0
package/src/client.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
} from "./workspace-live-stream";
|
|
24
24
|
import {
|
|
25
25
|
OpenGeniInteractionClient,
|
|
26
|
+
decodeComputerFrameMetadataHeader,
|
|
26
27
|
type AuthRun,
|
|
27
28
|
type AuthRunListOptions,
|
|
28
29
|
type AuthRunListResponse,
|
|
@@ -57,6 +58,7 @@ import {
|
|
|
57
58
|
type ComputerActionReceipt,
|
|
58
59
|
type ComputerActionRequest,
|
|
59
60
|
type ComputerClipboard,
|
|
61
|
+
type ComputerFrame,
|
|
60
62
|
type ComputerObservation,
|
|
61
63
|
type ComputerSession,
|
|
62
64
|
type ComputerSessionAttachment,
|
|
@@ -184,6 +186,7 @@ import type {
|
|
|
184
186
|
VerifyPersonalGitHubRepositorySelectionsRequest,
|
|
185
187
|
CreateApiKeyRequest,
|
|
186
188
|
CreateApiKeyResponse,
|
|
189
|
+
CreateOrganizationApiKeyRequest,
|
|
187
190
|
CreateCapabilityCatalogItemRequest,
|
|
188
191
|
InstallSkillRequest,
|
|
189
192
|
InstallLibrarySkillRequest,
|
|
@@ -216,6 +219,8 @@ import type {
|
|
|
216
219
|
ResolveVariableSetAttachmentsResponse,
|
|
217
220
|
CreateRigRequest,
|
|
218
221
|
CreateWorkspaceRequest,
|
|
222
|
+
EnsureWorkspaceRequest,
|
|
223
|
+
EnsureWorkspaceResponse,
|
|
219
224
|
// Enrollment UX (design 11): the click-Grant approve-page lookup/deny + headless
|
|
220
225
|
// enroll-token mint.
|
|
221
226
|
DeviceEnrollmentApproveRequest,
|
|
@@ -293,6 +298,7 @@ import type {
|
|
|
293
298
|
SwapActiveSandboxRequest,
|
|
294
299
|
SwapActiveSandboxResponse,
|
|
295
300
|
ListWorkspaceMembersResponse,
|
|
301
|
+
ListWorkspaceMemberCandidatesResponse,
|
|
296
302
|
InstallPackRequest,
|
|
297
303
|
PackInstallationPreview,
|
|
298
304
|
ListSlackUserLinkAccessRequestsResponse,
|
|
@@ -454,6 +460,7 @@ import type {
|
|
|
454
460
|
RigChange,
|
|
455
461
|
ProposeRigChangeRequest,
|
|
456
462
|
WorkspaceMember,
|
|
463
|
+
WorkspaceMemberCandidate,
|
|
457
464
|
WorkspaceMemorySearchRequest,
|
|
458
465
|
WorkspaceMemorySearchResponse,
|
|
459
466
|
WorkspaceRegisteredPack,
|
|
@@ -504,6 +511,7 @@ import type {
|
|
|
504
511
|
} from "./workspace-learning";
|
|
505
512
|
import type {
|
|
506
513
|
ActivateCompanyProfileRevisionRequest,
|
|
514
|
+
CompanyProfileAgentPolicy,
|
|
507
515
|
CompanyProfileDiffRequest,
|
|
508
516
|
CompanyProfileDiffResponse,
|
|
509
517
|
CompanyProfileListOptions,
|
|
@@ -512,6 +520,7 @@ import type {
|
|
|
512
520
|
CompanyProfileRevision,
|
|
513
521
|
RollbackCompanyProfileRequest,
|
|
514
522
|
UpdateCompanyProfileRequest,
|
|
523
|
+
UpdateCompanyProfileAgentPolicyRequest,
|
|
515
524
|
} from "./company-profile";
|
|
516
525
|
import type {
|
|
517
526
|
WorkspaceStateExportResponse,
|
|
@@ -594,6 +603,12 @@ export type SharedSessionReadOptions = {
|
|
|
594
603
|
* client has a `beginSharedRead` clock.
|
|
595
604
|
*/
|
|
596
605
|
onRequestStart?: ((readGeneration?: number) => void) | undefined;
|
|
606
|
+
/**
|
|
607
|
+
* Stop this caller's interest in the shared read. The native request is
|
|
608
|
+
* aborted only after every caller that joined the same generation has
|
|
609
|
+
* stopped waiting for it.
|
|
610
|
+
*/
|
|
611
|
+
signal?: AbortSignal | undefined;
|
|
597
612
|
};
|
|
598
613
|
|
|
599
614
|
export type GetSessionOptions = SharedSessionReadOptions & {
|
|
@@ -607,6 +622,8 @@ export type GetSessionOptions = SharedSessionReadOptions & {
|
|
|
607
622
|
export type GetSessionLineageOptions = SharedSessionReadOptions;
|
|
608
623
|
|
|
609
624
|
type SingleFlightReadEntry = {
|
|
625
|
+
controller: AbortController;
|
|
626
|
+
consumers: number;
|
|
610
627
|
generation: number;
|
|
611
628
|
promise: Promise<unknown>;
|
|
612
629
|
resolve: (value: unknown) => void;
|
|
@@ -627,6 +644,8 @@ function createSingleFlightReadEntry(
|
|
|
627
644
|
reject = entryReject;
|
|
628
645
|
});
|
|
629
646
|
return {
|
|
647
|
+
controller: new AbortController(),
|
|
648
|
+
consumers: 0,
|
|
630
649
|
generation,
|
|
631
650
|
promise,
|
|
632
651
|
resolve,
|
|
@@ -693,6 +712,29 @@ export type FinalizeTranscriptionRecordingInput = {
|
|
|
693
712
|
signal?: AbortSignal | undefined;
|
|
694
713
|
};
|
|
695
714
|
|
|
715
|
+
function normalizeScheduledTaskMachineTarget<
|
|
716
|
+
T extends CreateScheduledTaskRequest | UpdateScheduledTaskRequest,
|
|
717
|
+
>(request: T): T {
|
|
718
|
+
if (!("agentConfig" in request) || !request.agentConfig?.machineTarget) {
|
|
719
|
+
return request;
|
|
720
|
+
}
|
|
721
|
+
const { workingDir, ...machineTarget } = request.agentConfig.machineTarget;
|
|
722
|
+
if (workingDir === undefined) {
|
|
723
|
+
return request;
|
|
724
|
+
}
|
|
725
|
+
const normalizedWorkingDir = workingDir.trim();
|
|
726
|
+
return {
|
|
727
|
+
...request,
|
|
728
|
+
agentConfig: {
|
|
729
|
+
...request.agentConfig,
|
|
730
|
+
machineTarget: {
|
|
731
|
+
...machineTarget,
|
|
732
|
+
...(normalizedWorkingDir ? { workingDir: normalizedWorkingDir } : {}),
|
|
733
|
+
},
|
|
734
|
+
},
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
|
|
696
738
|
/**
|
|
697
739
|
* Typed client for the OpenGeni public API. Framework-agnostic: only needs
|
|
698
740
|
* WHATWG `fetch` + streams, so it runs in Node 18+, Bun, Deno, browsers, and
|
|
@@ -981,7 +1023,11 @@ export class OpenGeniClient {
|
|
|
981
1023
|
options: GetSessionOptions = {},
|
|
982
1024
|
): Promise<Session> {
|
|
983
1025
|
const path = `/v1/workspaces/${workspaceId}/sessions/${sessionId}`;
|
|
984
|
-
return await this.sharedRead(
|
|
1026
|
+
return await this.sharedRead(
|
|
1027
|
+
path,
|
|
1028
|
+
(signal) => this.requestJson<Session>("GET", path, undefined, {}, { signal }),
|
|
1029
|
+
options,
|
|
1030
|
+
);
|
|
985
1031
|
}
|
|
986
1032
|
|
|
987
1033
|
async updateSession(
|
|
@@ -1135,6 +1181,8 @@ export class OpenGeniClient {
|
|
|
1135
1181
|
pinsOnly?: boolean;
|
|
1136
1182
|
/** Return archived root chats instead of the active session list. */
|
|
1137
1183
|
archivedOnly?: boolean;
|
|
1184
|
+
/** Stop this caller's finite page read when its owning route is abandoned. */
|
|
1185
|
+
signal?: AbortSignal | undefined;
|
|
1138
1186
|
} = {},
|
|
1139
1187
|
): Promise<SessionListResponse> {
|
|
1140
1188
|
const search = options.search?.trim();
|
|
@@ -1152,6 +1200,7 @@ export class OpenGeniClient {
|
|
|
1152
1200
|
...(options.pinsOnly ? { pinsOnly: "true" } : {}),
|
|
1153
1201
|
...(options.archivedOnly ? { archivedOnly: "true" } : {}),
|
|
1154
1202
|
},
|
|
1203
|
+
{ signal: options.signal },
|
|
1155
1204
|
);
|
|
1156
1205
|
} catch (error) {
|
|
1157
1206
|
if (error instanceof OpenGeniApiError && error.status === 410) {
|
|
@@ -1303,30 +1352,35 @@ export class OpenGeniClient {
|
|
|
1303
1352
|
const path = `/v1/workspaces/${workspaceId}/sessions/${sessionId}/lineage`;
|
|
1304
1353
|
return await this.sharedRead(
|
|
1305
1354
|
path,
|
|
1306
|
-
() => this.requestJson<SessionLineageResponse>("GET", path),
|
|
1355
|
+
(signal) => this.requestJson<SessionLineageResponse>("GET", path, undefined, {}, { signal }),
|
|
1307
1356
|
options,
|
|
1308
1357
|
);
|
|
1309
1358
|
}
|
|
1310
1359
|
|
|
1311
1360
|
private sharedRead<T>(
|
|
1312
1361
|
key: string,
|
|
1313
|
-
read: () => Promise<T>,
|
|
1362
|
+
read: (signal: AbortSignal) => Promise<T>,
|
|
1314
1363
|
options: GetSessionOptions = {},
|
|
1315
1364
|
): Promise<T> {
|
|
1365
|
+
if (options.signal?.aborted) {
|
|
1366
|
+
return Promise.reject(
|
|
1367
|
+
options.signal.reason ?? new DOMException("Request aborted", "AbortError"),
|
|
1368
|
+
);
|
|
1369
|
+
}
|
|
1316
1370
|
const existing = this.active.get(key);
|
|
1317
1371
|
if (existing) {
|
|
1318
1372
|
if (!options.fresh) {
|
|
1319
1373
|
this.observeRead(existing, options.onRequestStart);
|
|
1320
|
-
return
|
|
1374
|
+
return this.consumeSharedRead(key, existing, options.signal);
|
|
1321
1375
|
}
|
|
1322
1376
|
const requiredGeneration = existing.generation + 1;
|
|
1323
1377
|
const queued = this.queued.get(key);
|
|
1324
1378
|
if (queued && queued.generation >= requiredGeneration) {
|
|
1325
1379
|
this.observeRead(queued, options.onRequestStart);
|
|
1326
|
-
return
|
|
1380
|
+
return this.consumeSharedRead(key, queued, options.signal);
|
|
1327
1381
|
}
|
|
1328
1382
|
const predecessor = queued?.promise ?? existing.promise;
|
|
1329
|
-
return this.queueRead(key, predecessor, requiredGeneration, read, options
|
|
1383
|
+
return this.queueRead(key, predecessor, requiredGeneration, read, options);
|
|
1330
1384
|
}
|
|
1331
1385
|
// The active entry clears in its finally before reactions on its public
|
|
1332
1386
|
// promise run. During that settlement gap a successor may already be
|
|
@@ -1335,31 +1389,27 @@ export class OpenGeniClient {
|
|
|
1335
1389
|
const queued = this.queued.get(key);
|
|
1336
1390
|
if (queued && (!options.fresh || !queued.started)) {
|
|
1337
1391
|
this.observeRead(queued, options.onRequestStart);
|
|
1338
|
-
return
|
|
1392
|
+
return this.consumeSharedRead(key, queued, options.signal);
|
|
1339
1393
|
}
|
|
1340
1394
|
if (queued) {
|
|
1341
|
-
return this.queueRead(
|
|
1342
|
-
key,
|
|
1343
|
-
queued.promise,
|
|
1344
|
-
queued.generation + 1,
|
|
1345
|
-
read,
|
|
1346
|
-
options.onRequestStart,
|
|
1347
|
-
);
|
|
1395
|
+
return this.queueRead(key, queued.promise, queued.generation + 1, read, options);
|
|
1348
1396
|
}
|
|
1349
1397
|
const generation = (this.generations.get(key) ?? 0) + 1;
|
|
1350
1398
|
const entry = createSingleFlightReadEntry(generation, options.onRequestStart);
|
|
1399
|
+
const consumed = this.consumeSharedRead<T>(key, entry, options.signal);
|
|
1351
1400
|
this.launchRead(key, entry, read);
|
|
1352
|
-
return
|
|
1401
|
+
return consumed;
|
|
1353
1402
|
}
|
|
1354
1403
|
|
|
1355
1404
|
private queueRead<T>(
|
|
1356
1405
|
key: string,
|
|
1357
1406
|
predecessor: Promise<unknown>,
|
|
1358
1407
|
generation: number,
|
|
1359
|
-
read: () => Promise<T>,
|
|
1360
|
-
|
|
1408
|
+
read: (signal: AbortSignal) => Promise<T>,
|
|
1409
|
+
options: GetSessionOptions,
|
|
1361
1410
|
): Promise<T> {
|
|
1362
|
-
const entry = createSingleFlightReadEntry(generation, onRequestStart);
|
|
1411
|
+
const entry = createSingleFlightReadEntry(generation, options.onRequestStart);
|
|
1412
|
+
const consumed = this.consumeSharedRead<T>(key, entry, options.signal);
|
|
1363
1413
|
this.queued.set(key, entry);
|
|
1364
1414
|
const launch = () => this.launchRead(key, entry, read);
|
|
1365
1415
|
void predecessor.then(launch, launch);
|
|
@@ -1369,10 +1419,15 @@ export class OpenGeniClient {
|
|
|
1369
1419
|
if (!this.active.has(key)) this.generations.delete(key);
|
|
1370
1420
|
};
|
|
1371
1421
|
void entry.promise.then(clear, clear);
|
|
1372
|
-
return
|
|
1422
|
+
return consumed;
|
|
1373
1423
|
}
|
|
1374
1424
|
|
|
1375
|
-
private launchRead<T>(
|
|
1425
|
+
private launchRead<T>(
|
|
1426
|
+
key: string,
|
|
1427
|
+
entry: SingleFlightReadEntry,
|
|
1428
|
+
read: (signal: AbortSignal) => Promise<T>,
|
|
1429
|
+
): void {
|
|
1430
|
+
if (entry.controller.signal.aborted) return;
|
|
1376
1431
|
entry.started = true;
|
|
1377
1432
|
this.generations.set(key, entry.generation);
|
|
1378
1433
|
this.active.set(key, entry);
|
|
@@ -1396,7 +1451,7 @@ export class OpenGeniClient {
|
|
|
1396
1451
|
};
|
|
1397
1452
|
let request: Promise<T>;
|
|
1398
1453
|
try {
|
|
1399
|
-
request = read();
|
|
1454
|
+
request = read(entry.controller.signal);
|
|
1400
1455
|
} catch (error) {
|
|
1401
1456
|
settle();
|
|
1402
1457
|
entry.reject(error);
|
|
@@ -1414,6 +1469,33 @@ export class OpenGeniClient {
|
|
|
1414
1469
|
);
|
|
1415
1470
|
}
|
|
1416
1471
|
|
|
1472
|
+
private consumeSharedRead<T>(
|
|
1473
|
+
key: string,
|
|
1474
|
+
entry: SingleFlightReadEntry,
|
|
1475
|
+
signal: AbortSignal | undefined,
|
|
1476
|
+
): Promise<T> {
|
|
1477
|
+
entry.consumers += 1;
|
|
1478
|
+
let released = false;
|
|
1479
|
+
const release = () => {
|
|
1480
|
+
if (released) return;
|
|
1481
|
+
released = true;
|
|
1482
|
+
entry.consumers -= 1;
|
|
1483
|
+
if (!signal?.aborted || entry.consumers > 0) return;
|
|
1484
|
+
const reason = signal.reason;
|
|
1485
|
+
entry.controller.abort(reason);
|
|
1486
|
+
if (this.active.get(key) === entry) this.active.delete(key);
|
|
1487
|
+
if (this.queued.get(key) === entry) this.queued.delete(key);
|
|
1488
|
+
if (!this.active.has(key) && !this.queued.has(key)) this.generations.delete(key);
|
|
1489
|
+
entry.reject(reason);
|
|
1490
|
+
};
|
|
1491
|
+
signal?.addEventListener("abort", release, { once: true });
|
|
1492
|
+
const consumed = awaitWithAbort(entry.promise as Promise<T>, signal);
|
|
1493
|
+
return consumed.finally(() => {
|
|
1494
|
+
signal?.removeEventListener("abort", release);
|
|
1495
|
+
release();
|
|
1496
|
+
});
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1417
1499
|
private observeRead(
|
|
1418
1500
|
entry: SingleFlightReadEntry,
|
|
1419
1501
|
listener: ((readGeneration?: number) => void) | undefined,
|
|
@@ -1557,7 +1639,7 @@ export class OpenGeniClient {
|
|
|
1557
1639
|
async listTurns(
|
|
1558
1640
|
workspaceId: string,
|
|
1559
1641
|
sessionId: string,
|
|
1560
|
-
options: { limit?: number; latestStarted?: boolean } = {},
|
|
1642
|
+
options: { limit?: number; latestStarted?: boolean; signal?: AbortSignal | undefined } = {},
|
|
1561
1643
|
): Promise<SessionTurn[]> {
|
|
1562
1644
|
return await this.requestJson<SessionTurn[]>(
|
|
1563
1645
|
"GET",
|
|
@@ -1567,13 +1649,19 @@ export class OpenGeniClient {
|
|
|
1567
1649
|
...(options.limit !== undefined ? { limit: String(options.limit) } : {}),
|
|
1568
1650
|
...(options.latestStarted ? { latestStarted: "1" } : {}),
|
|
1569
1651
|
},
|
|
1652
|
+
{ signal: options.signal },
|
|
1570
1653
|
);
|
|
1571
1654
|
}
|
|
1572
1655
|
|
|
1573
1656
|
/** Newest turn that durably emitted `turn.started`, or null before any admission. */
|
|
1574
|
-
async getLatestStartedTurn(
|
|
1657
|
+
async getLatestStartedTurn(
|
|
1658
|
+
workspaceId: string,
|
|
1659
|
+
sessionId: string,
|
|
1660
|
+
options: OpenGeniRequestOptions = {},
|
|
1661
|
+
): Promise<SessionTurn | null> {
|
|
1575
1662
|
const turns = await this.listTurns(workspaceId, sessionId, {
|
|
1576
1663
|
latestStarted: true,
|
|
1664
|
+
signal: options.signal,
|
|
1577
1665
|
});
|
|
1578
1666
|
return turns[0] ?? null;
|
|
1579
1667
|
}
|
|
@@ -2147,10 +2235,16 @@ export class OpenGeniClient {
|
|
|
2147
2235
|
);
|
|
2148
2236
|
}
|
|
2149
2237
|
|
|
2150
|
-
async getComposerDraft(
|
|
2238
|
+
async getComposerDraft(
|
|
2239
|
+
workspaceId: string,
|
|
2240
|
+
sessionId: string,
|
|
2241
|
+
options: OpenGeniRequestOptions = {},
|
|
2242
|
+
): Promise<ComposerDraft> {
|
|
2151
2243
|
return await this.requestSessionCommand<ComposerDraft>(
|
|
2152
2244
|
"GET",
|
|
2153
2245
|
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/composer-draft`,
|
|
2246
|
+
undefined,
|
|
2247
|
+
options,
|
|
2154
2248
|
);
|
|
2155
2249
|
}
|
|
2156
2250
|
|
|
@@ -2424,9 +2518,17 @@ export class OpenGeniClient {
|
|
|
2424
2518
|
// --- Goals -------------------------------------------------------------------
|
|
2425
2519
|
|
|
2426
2520
|
/** The session's goal. 404s when the session never had one. */
|
|
2427
|
-
async getGoal(
|
|
2521
|
+
async getGoal(
|
|
2522
|
+
workspaceId: string,
|
|
2523
|
+
sessionId: string,
|
|
2524
|
+
options: SharedSessionReadOptions = {},
|
|
2525
|
+
): Promise<SessionGoal> {
|
|
2428
2526
|
const path = `/v1/workspaces/${workspaceId}/sessions/${sessionId}/goal`;
|
|
2429
|
-
return await this.sharedRead(
|
|
2527
|
+
return await this.sharedRead(
|
|
2528
|
+
path,
|
|
2529
|
+
(signal) => this.requestJson<SessionGoal>("GET", path, undefined, {}, { signal }),
|
|
2530
|
+
options,
|
|
2531
|
+
);
|
|
2430
2532
|
}
|
|
2431
2533
|
|
|
2432
2534
|
async updateGoal(
|
|
@@ -3787,6 +3889,48 @@ export class OpenGeniClient {
|
|
|
3787
3889
|
);
|
|
3788
3890
|
}
|
|
3789
3891
|
|
|
3892
|
+
async captureComputerTarget(
|
|
3893
|
+
workspaceId: string,
|
|
3894
|
+
computerSessionId: string,
|
|
3895
|
+
targetId: string,
|
|
3896
|
+
options: OpenGeniRequestOptions = {},
|
|
3897
|
+
): Promise<ComputerFrame> {
|
|
3898
|
+
const response = await this.requestResponse(
|
|
3899
|
+
"GET",
|
|
3900
|
+
`/v1/workspaces/${workspaceId}/computer-sessions/${encodeURIComponent(computerSessionId)}/targets/${encodeURIComponent(targetId)}/screenshot`,
|
|
3901
|
+
{},
|
|
3902
|
+
options,
|
|
3903
|
+
);
|
|
3904
|
+
const mediaType = response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
3905
|
+
if (mediaType !== "image/jpeg" && mediaType !== "image/png") {
|
|
3906
|
+
await cancelResponseBody(response, "computer frame media type is invalid");
|
|
3907
|
+
throw new OpenGeniApiError(502, "computer frame media type is invalid");
|
|
3908
|
+
}
|
|
3909
|
+
const metadataHeader = response.headers.get("x-opengeni-computer-frame");
|
|
3910
|
+
if (!metadataHeader || metadataHeader.length > 32 * 1024) {
|
|
3911
|
+
await cancelResponseBody(response, "computer frame metadata is invalid");
|
|
3912
|
+
throw new OpenGeniApiError(502, "computer frame metadata is invalid");
|
|
3913
|
+
}
|
|
3914
|
+
let metadata: ReturnType<typeof decodeComputerFrameMetadataHeader>;
|
|
3915
|
+
try {
|
|
3916
|
+
metadata = decodeComputerFrameMetadataHeader(metadataHeader);
|
|
3917
|
+
} catch {
|
|
3918
|
+
await cancelResponseBody(response, "computer frame metadata is invalid");
|
|
3919
|
+
throw new OpenGeniApiError(502, "computer frame metadata is invalid");
|
|
3920
|
+
}
|
|
3921
|
+
const bytes = await readBoundedResponseBytes(response, 256 * 1024, null);
|
|
3922
|
+
const mismatchReason = computerFrameEvidenceMismatchReason(metadata, {
|
|
3923
|
+
computerSessionId,
|
|
3924
|
+
targetId,
|
|
3925
|
+
mediaType,
|
|
3926
|
+
sha256: await sha256Hex(bytes),
|
|
3927
|
+
});
|
|
3928
|
+
if (mismatchReason) {
|
|
3929
|
+
throw new OpenGeniApiError(502, "computer frame evidence does not match its request");
|
|
3930
|
+
}
|
|
3931
|
+
return { ...metadata, data: bytes };
|
|
3932
|
+
}
|
|
3933
|
+
|
|
3790
3934
|
async actInComputer(
|
|
3791
3935
|
workspaceId: string,
|
|
3792
3936
|
computerSessionId: string,
|
|
@@ -3870,8 +4014,14 @@ export class OpenGeniClient {
|
|
|
3870
4014
|
* expected to authenticate. Drives a composer's model picker without prior
|
|
3871
4015
|
* knowledge of the host setup; safe to call before any auth is established.
|
|
3872
4016
|
*/
|
|
3873
|
-
async getClientConfig(): Promise<ClientConfig> {
|
|
3874
|
-
const config = await this.requestJson<ClientConfig>(
|
|
4017
|
+
async getClientConfig(options: OpenGeniRequestOptions = {}): Promise<ClientConfig> {
|
|
4018
|
+
const config = await this.requestJson<ClientConfig>(
|
|
4019
|
+
"GET",
|
|
4020
|
+
"/v1/config/client",
|
|
4021
|
+
undefined,
|
|
4022
|
+
{},
|
|
4023
|
+
options,
|
|
4024
|
+
);
|
|
3875
4025
|
if (config.apiContractRevision !== OPENGENI_API_CONTRACT_REVISION) {
|
|
3876
4026
|
throw new OpenGeniApiContractMismatchError(
|
|
3877
4027
|
OPENGENI_API_CONTRACT_REVISION,
|
|
@@ -3882,10 +4032,16 @@ export class OpenGeniClient {
|
|
|
3882
4032
|
}
|
|
3883
4033
|
|
|
3884
4034
|
/** Authenticated model definitions plus workspace-specific selectability. */
|
|
3885
|
-
async getWorkspaceModelCatalog(
|
|
4035
|
+
async getWorkspaceModelCatalog(
|
|
4036
|
+
workspaceId: string,
|
|
4037
|
+
options: OpenGeniRequestOptions = {},
|
|
4038
|
+
): Promise<WorkspaceModelCatalogResponse> {
|
|
3886
4039
|
return await this.requestJson<WorkspaceModelCatalogResponse>(
|
|
3887
4040
|
"GET",
|
|
3888
4041
|
`/v1/workspaces/${workspaceId}/model-catalog`,
|
|
4042
|
+
undefined,
|
|
4043
|
+
{},
|
|
4044
|
+
options,
|
|
3889
4045
|
);
|
|
3890
4046
|
}
|
|
3891
4047
|
|
|
@@ -3912,10 +4068,14 @@ export class OpenGeniClient {
|
|
|
3912
4068
|
/** Authenticated realtime voice models and credential readiness. */
|
|
3913
4069
|
async getWorkspaceRealtimeModelCatalog(
|
|
3914
4070
|
workspaceId: string,
|
|
4071
|
+
options: OpenGeniRequestOptions = {},
|
|
3915
4072
|
): Promise<WorkspaceRealtimeModelCatalogResponse> {
|
|
3916
4073
|
return await this.requestJson<WorkspaceRealtimeModelCatalogResponse>(
|
|
3917
4074
|
"GET",
|
|
3918
4075
|
`/v1/workspaces/${workspaceId}/realtime-model-catalog`,
|
|
4076
|
+
undefined,
|
|
4077
|
+
{},
|
|
4078
|
+
options,
|
|
3919
4079
|
);
|
|
3920
4080
|
}
|
|
3921
4081
|
|
|
@@ -4271,6 +4431,18 @@ export class OpenGeniClient {
|
|
|
4271
4431
|
return await this.requestJson<Workspace>("POST", "/v1/workspaces", request);
|
|
4272
4432
|
}
|
|
4273
4433
|
|
|
4434
|
+
/**
|
|
4435
|
+
* Create an organization workspace once for a stable external tenant
|
|
4436
|
+
* identity, or return the existing workspace without overwriting it.
|
|
4437
|
+
*/
|
|
4438
|
+
async ensureWorkspace(request: EnsureWorkspaceRequest): Promise<EnsureWorkspaceResponse> {
|
|
4439
|
+
return await this.requestJson<EnsureWorkspaceResponse>(
|
|
4440
|
+
"PUT",
|
|
4441
|
+
"/v1/workspaces/external",
|
|
4442
|
+
request,
|
|
4443
|
+
);
|
|
4444
|
+
}
|
|
4445
|
+
|
|
4274
4446
|
async getWorkspace(workspaceId: string): Promise<Workspace> {
|
|
4275
4447
|
return await this.requestJson<Workspace>("GET", `/v1/workspaces/${workspaceId}`);
|
|
4276
4448
|
}
|
|
@@ -4531,6 +4703,24 @@ export class OpenGeniClient {
|
|
|
4531
4703
|
);
|
|
4532
4704
|
}
|
|
4533
4705
|
|
|
4706
|
+
async getCompanyProfileAgentPolicy(workspaceId: string): Promise<CompanyProfileAgentPolicy> {
|
|
4707
|
+
return await this.requestJson<CompanyProfileAgentPolicy>(
|
|
4708
|
+
"GET",
|
|
4709
|
+
`/v1/workspaces/${workspaceId}/company-profile/agent-policy`,
|
|
4710
|
+
);
|
|
4711
|
+
}
|
|
4712
|
+
|
|
4713
|
+
async updateCompanyProfileAgentPolicy(
|
|
4714
|
+
workspaceId: string,
|
|
4715
|
+
request: UpdateCompanyProfileAgentPolicyRequest,
|
|
4716
|
+
): Promise<CompanyProfileAgentPolicy> {
|
|
4717
|
+
return await this.requestJson<CompanyProfileAgentPolicy>(
|
|
4718
|
+
"PATCH",
|
|
4719
|
+
`/v1/workspaces/${workspaceId}/company-profile/agent-policy`,
|
|
4720
|
+
request,
|
|
4721
|
+
);
|
|
4722
|
+
}
|
|
4723
|
+
|
|
4534
4724
|
async updateCompanyProfile(
|
|
4535
4725
|
workspaceId: string,
|
|
4536
4726
|
request: UpdateCompanyProfileRequest,
|
|
@@ -4721,9 +4911,17 @@ export class OpenGeniClient {
|
|
|
4721
4911
|
return response.members;
|
|
4722
4912
|
}
|
|
4723
4913
|
|
|
4914
|
+
/** Active organization members who can be added to this workspace. */
|
|
4915
|
+
async listWorkspaceMemberCandidates(workspaceId: string): Promise<WorkspaceMemberCandidate[]> {
|
|
4916
|
+
const response = await this.requestJson<ListWorkspaceMemberCandidatesResponse>(
|
|
4917
|
+
"GET",
|
|
4918
|
+
`/v1/workspaces/${workspaceId}/member-candidates`,
|
|
4919
|
+
);
|
|
4920
|
+
return response.members;
|
|
4921
|
+
}
|
|
4922
|
+
|
|
4724
4923
|
/**
|
|
4725
|
-
* Add
|
|
4726
|
-
* exists (email invites for unknown users are deferred).
|
|
4924
|
+
* Add one active member selected from the workspace candidate inventory.
|
|
4727
4925
|
*/
|
|
4728
4926
|
async addWorkspaceMember(
|
|
4729
4927
|
workspaceId: string,
|
|
@@ -4848,7 +5046,7 @@ export class OpenGeniClient {
|
|
|
4848
5046
|
return await this.requestJson<ScheduledTask>(
|
|
4849
5047
|
"POST",
|
|
4850
5048
|
`/v1/workspaces/${workspaceId}/scheduled-tasks`,
|
|
4851
|
-
request,
|
|
5049
|
+
normalizeScheduledTaskMachineTarget(request),
|
|
4852
5050
|
);
|
|
4853
5051
|
}
|
|
4854
5052
|
|
|
@@ -4860,7 +5058,7 @@ export class OpenGeniClient {
|
|
|
4860
5058
|
return await this.requestJson<ScheduledTask>(
|
|
4861
5059
|
"PATCH",
|
|
4862
5060
|
`/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}`,
|
|
4863
|
-
request,
|
|
5061
|
+
normalizeScheduledTaskMachineTarget(request),
|
|
4864
5062
|
);
|
|
4865
5063
|
}
|
|
4866
5064
|
|
|
@@ -6755,6 +6953,34 @@ export class OpenGeniClient {
|
|
|
6755
6953
|
);
|
|
6756
6954
|
}
|
|
6757
6955
|
|
|
6956
|
+
async listOrganizationApiKeys(organizationId: string): Promise<ApiKey[]> {
|
|
6957
|
+
const response = await this.requestJson<ListApiKeysResponse>(
|
|
6958
|
+
"GET",
|
|
6959
|
+
`/v1/organizations/${organizationId}/api-keys`,
|
|
6960
|
+
);
|
|
6961
|
+
return response.apiKeys;
|
|
6962
|
+
}
|
|
6963
|
+
|
|
6964
|
+
/** The returned `token` is shown once; only its prefix is stored. */
|
|
6965
|
+
async createOrganizationApiKey(
|
|
6966
|
+
organizationId: string,
|
|
6967
|
+
request: CreateOrganizationApiKeyRequest,
|
|
6968
|
+
): Promise<CreateApiKeyResponse> {
|
|
6969
|
+
return await this.requestJson<CreateApiKeyResponse>(
|
|
6970
|
+
"POST",
|
|
6971
|
+
`/v1/organizations/${organizationId}/api-keys`,
|
|
6972
|
+
request,
|
|
6973
|
+
);
|
|
6974
|
+
}
|
|
6975
|
+
|
|
6976
|
+
/** Revoke an organization-scoped API key. Returns the revoked key. */
|
|
6977
|
+
async deleteOrganizationApiKey(organizationId: string, apiKeyId: string): Promise<ApiKey> {
|
|
6978
|
+
return await this.requestJson<ApiKey>(
|
|
6979
|
+
"DELETE",
|
|
6980
|
+
`/v1/organizations/${organizationId}/api-keys/${apiKeyId}`,
|
|
6981
|
+
);
|
|
6982
|
+
}
|
|
6983
|
+
|
|
6758
6984
|
// --- Billing (account-scoped) --------------------------------------------------------------------
|
|
6759
6985
|
|
|
6760
6986
|
async getBilling(options: { accountId?: string } = {}): Promise<BillingSummary> {
|
|
@@ -7105,14 +7331,20 @@ export class OpenGeniClient {
|
|
|
7105
7331
|
}
|
|
7106
7332
|
|
|
7107
7333
|
/** Contract-checked JSON transport shared by opt-in typed SDK clients. */
|
|
7108
|
-
private async requestSessionCommand<T>(
|
|
7334
|
+
private async requestSessionCommand<T>(
|
|
7335
|
+
method: string,
|
|
7336
|
+
path: string,
|
|
7337
|
+
body?: unknown,
|
|
7338
|
+
options: OpenGeniRequestOptions = {},
|
|
7339
|
+
): Promise<T> {
|
|
7109
7340
|
return await this.requestJson<T>(
|
|
7110
7341
|
method,
|
|
7111
7342
|
path,
|
|
7112
7343
|
body,
|
|
7113
7344
|
{},
|
|
7114
7345
|
{
|
|
7115
|
-
|
|
7346
|
+
signal: options.signal,
|
|
7347
|
+
timeoutMs: options.timeoutMs ?? this.sessionCommandTimeoutMs,
|
|
7116
7348
|
},
|
|
7117
7349
|
);
|
|
7118
7350
|
}
|
|
@@ -7486,6 +7718,30 @@ async function sha256Hex(bytes: Uint8Array): Promise<string> {
|
|
|
7486
7718
|
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
7487
7719
|
}
|
|
7488
7720
|
|
|
7721
|
+
type ComputerFrameEvidenceMismatchReason =
|
|
7722
|
+
| "frame_session_mismatch"
|
|
7723
|
+
| "frame_target_mismatch"
|
|
7724
|
+
| "frame_media_mismatch"
|
|
7725
|
+
| "frame_digest_mismatch";
|
|
7726
|
+
|
|
7727
|
+
function computerFrameEvidenceMismatchReason(
|
|
7728
|
+
metadata: ReturnType<typeof decodeComputerFrameMetadataHeader>,
|
|
7729
|
+
expected: {
|
|
7730
|
+
computerSessionId: string;
|
|
7731
|
+
targetId: string;
|
|
7732
|
+
mediaType: "image/jpeg" | "image/png";
|
|
7733
|
+
sha256: string;
|
|
7734
|
+
},
|
|
7735
|
+
): ComputerFrameEvidenceMismatchReason | null {
|
|
7736
|
+
if (metadata.computerSessionId !== expected.computerSessionId) {
|
|
7737
|
+
return "frame_session_mismatch";
|
|
7738
|
+
}
|
|
7739
|
+
if (metadata.targetId !== expected.targetId) return "frame_target_mismatch";
|
|
7740
|
+
if (metadata.mediaType !== expected.mediaType) return "frame_media_mismatch";
|
|
7741
|
+
if (metadata.sha256 !== expected.sha256) return "frame_digest_mismatch";
|
|
7742
|
+
return null;
|
|
7743
|
+
}
|
|
7744
|
+
|
|
7489
7745
|
async function cancelResponseBody(response: Response, reason: string): Promise<void> {
|
|
7490
7746
|
await response.body?.cancel(reason).catch(() => undefined);
|
|
7491
7747
|
}
|
package/src/company-profile.ts
CHANGED
|
@@ -82,6 +82,19 @@ export type CompanyProfileMutationResponse = {
|
|
|
82
82
|
head: CompanyProfileHead | null;
|
|
83
83
|
event: CompanyProfileActivationEvent | null;
|
|
84
84
|
};
|
|
85
|
+
export type CompanyProfileAgentPolicyMode = "off" | "suggest" | "automatic";
|
|
86
|
+
export type CompanyProfileAgentPolicy = {
|
|
87
|
+
organizationId: string;
|
|
88
|
+
mode: CompanyProfileAgentPolicyMode;
|
|
89
|
+
version: number;
|
|
90
|
+
updatedAt: string;
|
|
91
|
+
changed?: boolean;
|
|
92
|
+
};
|
|
93
|
+
export type UpdateCompanyProfileAgentPolicyRequest = {
|
|
94
|
+
mode: CompanyProfileAgentPolicyMode;
|
|
95
|
+
expectedVersion: number;
|
|
96
|
+
operationId: string;
|
|
97
|
+
};
|
|
85
98
|
export type CompanyProfileDiffRequest = { fromRevisionId: string; toRevisionId: string };
|
|
86
99
|
export type CompanyProfileDiffResponse = {
|
|
87
100
|
from: CompanyProfileRevision;
|