@opengeni/sdk 0.48.0 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +147 -1
  2. package/dist/artifact-client.d.ts +20 -2
  3. package/dist/artifacts.d.ts +4 -0
  4. package/dist/artifacts.js +11 -0
  5. package/dist/artifacts.js.map +1 -0
  6. package/dist/{chunk-V5F253OG.js → chunk-GU6JF75T.js} +6 -3
  7. package/dist/chunk-GU6JF75T.js.map +1 -0
  8. package/dist/chunk-HJ3HHUT5.js +222 -0
  9. package/dist/chunk-HJ3HHUT5.js.map +1 -0
  10. package/dist/{chunk-KIHGPM7H.js → chunk-JDLDDRNE.js} +20 -14
  11. package/dist/chunk-JDLDDRNE.js.map +1 -0
  12. package/dist/chunk-JRPFWI6T.js +128 -0
  13. package/dist/chunk-JRPFWI6T.js.map +1 -0
  14. package/dist/{chunk-MBGBLVUV.js → chunk-PKQ377ED.js} +1725 -555
  15. package/dist/chunk-PKQ377ED.js.map +1 -0
  16. package/dist/chunk-ST5DDKJP.js +987 -0
  17. package/dist/chunk-ST5DDKJP.js.map +1 -0
  18. package/dist/chunk-VWE2QIVO.js +1162 -0
  19. package/dist/chunk-VWE2QIVO.js.map +1 -0
  20. package/dist/chunk-VYCTL62C.js +230 -0
  21. package/dist/chunk-VYCTL62C.js.map +1 -0
  22. package/dist/{chunk-DXDL7EEW.js → chunk-YKZME56C.js} +197 -113
  23. package/dist/chunk-YKZME56C.js.map +1 -0
  24. package/dist/client.d.ts +240 -16
  25. package/dist/codex-realtime-controller.d.ts +9 -6
  26. package/dist/codex-realtime-controller.js +2 -2
  27. package/dist/codex-realtime-lifecycle.d.ts +1 -1
  28. package/dist/codex-realtime-v3.d.ts +3 -3
  29. package/dist/codex-realtime.d.ts +1 -1
  30. package/dist/company-profile.d.ts +100 -0
  31. package/dist/core.d.ts +5 -5
  32. package/dist/core.js +10 -5
  33. package/dist/desktop.d.ts +9 -1
  34. package/dist/editable-artifact-resources.d.ts +96 -0
  35. package/dist/editable-artifacts/browser-session.d.ts +35 -0
  36. package/dist/editable-artifacts/controller.d.ts +60 -0
  37. package/dist/editable-artifacts/errors.d.ts +23 -0
  38. package/dist/editable-artifacts/http-live-transport.d.ts +46 -0
  39. package/dist/editable-artifacts/index.d.ts +19 -0
  40. package/dist/editable-artifacts/pool.d.ts +15 -0
  41. package/dist/editable-artifacts/session.d.ts +96 -0
  42. package/dist/editable-artifacts/storage.d.ts +72 -0
  43. package/dist/editable-artifacts/types.d.ts +416 -0
  44. package/dist/editable-artifacts/worker/browser-client.d.ts +80 -0
  45. package/dist/editable-artifacts/worker/browser-entry.d.ts +6 -0
  46. package/dist/editable-artifacts/worker/kernel-adapter.d.ts +45 -0
  47. package/dist/editable-artifacts/worker/rpc-protocol.d.ts +92 -0
  48. package/dist/editable-artifacts/worker/runtime.d.ts +66 -0
  49. package/dist/editable-artifacts/worker/wire-codec.d.ts +52 -0
  50. package/dist/editable-artifacts-worker.d.ts +8 -0
  51. package/dist/editable-artifacts-worker.js +1708 -0
  52. package/dist/editable-artifacts-worker.js.map +1 -0
  53. package/dist/editable-artifacts.d.ts +6 -0
  54. package/dist/editable-artifacts.js +5954 -0
  55. package/dist/editable-artifacts.js.map +1 -0
  56. package/dist/gateway-realtime-transport.d.ts +2 -1
  57. package/dist/gateway-realtime-transport.js +5 -3
  58. package/dist/index.d.ts +45 -35
  59. package/dist/index.js +134 -64
  60. package/dist/index.js.map +1 -1
  61. package/dist/interaction-revision-stream.d.ts +11 -0
  62. package/dist/interaction.d.ts +1484 -0
  63. package/dist/interaction.js +81 -0
  64. package/dist/interaction.js.map +1 -0
  65. package/dist/memory-slack-client.d.ts +13 -0
  66. package/dist/memory-slack-delivery.d.ts +99 -0
  67. package/dist/memory-slack.d.ts +4 -0
  68. package/dist/memory-slack.js +44 -0
  69. package/dist/memory-slack.js.map +1 -0
  70. package/dist/proxy.d.ts +3 -3
  71. package/dist/realtime.d.ts +14 -14
  72. package/dist/realtime.js +11 -7
  73. package/dist/realtime.js.map +1 -1
  74. package/dist/retained-artifacts.d.ts +12 -0
  75. package/dist/stream.d.ts +1 -1
  76. package/dist/terminal.d.ts +1 -1
  77. package/dist/types.d.ts +1347 -34
  78. package/dist/workspace-control-stream.d.ts +2 -2
  79. package/dist/workspace-live-stream.d.ts +14 -0
  80. package/dist/workspace-state.d.ts +1 -1
  81. package/package.json +29 -3
  82. package/src/artifact-client.ts +129 -0
  83. package/src/artifacts.ts +17 -0
  84. package/src/client.ts +3022 -910
  85. package/src/codex-realtime-controller.ts +25 -7
  86. package/src/codex-realtime-lifecycle.ts +1 -0
  87. package/src/company-profile.ts +92 -0
  88. package/src/desktop.ts +11 -1
  89. package/src/editable-artifact-resources.ts +119 -0
  90. package/src/editable-artifacts/browser-session.ts +176 -0
  91. package/src/editable-artifacts/controller.ts +2632 -0
  92. package/src/editable-artifacts/errors.ts +52 -0
  93. package/src/editable-artifacts/http-live-transport.ts +1449 -0
  94. package/src/editable-artifacts/index.ts +175 -0
  95. package/src/editable-artifacts/pool.ts +81 -0
  96. package/src/editable-artifacts/session.ts +778 -0
  97. package/src/editable-artifacts/storage.ts +1718 -0
  98. package/src/editable-artifacts/types.ts +499 -0
  99. package/src/editable-artifacts/worker/browser-client.ts +1167 -0
  100. package/src/editable-artifacts/worker/browser-entry.ts +57 -0
  101. package/src/editable-artifacts/worker/kernel-adapter.ts +1039 -0
  102. package/src/editable-artifacts/worker/rpc-protocol.ts +622 -0
  103. package/src/editable-artifacts/worker/runtime.ts +1204 -0
  104. package/src/editable-artifacts/worker/wire-codec.ts +852 -0
  105. package/src/editable-artifacts-worker.ts +8 -0
  106. package/src/editable-artifacts.ts +6 -0
  107. package/src/errors.ts +16 -2
  108. package/src/gateway-realtime-transport.ts +252 -109
  109. package/src/index.ts +215 -1
  110. package/src/interaction-revision-stream.ts +117 -0
  111. package/src/interaction.ts +2874 -0
  112. package/src/memory-slack-client.ts +71 -0
  113. package/src/memory-slack-delivery.ts +128 -0
  114. package/src/memory-slack.ts +19 -0
  115. package/src/realtime.ts +14 -4
  116. package/src/retained-artifacts.ts +326 -0
  117. package/src/types.ts +1636 -52
  118. package/src/workspace-live-stream.ts +137 -0
  119. package/dist/chunk-DXDL7EEW.js.map +0 -1
  120. package/dist/chunk-KIHGPM7H.js.map +0 -1
  121. package/dist/chunk-MBGBLVUV.js.map +0 -1
  122. package/dist/chunk-V5F253OG.js.map +0 -1
package/src/client.ts CHANGED
@@ -12,6 +12,95 @@ import {
12
12
  streamWorkspaceControlEvents,
13
13
  type WorkspaceControlStreamTransport,
14
14
  } from "./workspace-control-stream";
15
+ import {
16
+ streamWorkspaceInteractionRevisions,
17
+ type WorkspaceInteractionRevisionStreamTransport,
18
+ } from "./interaction-revision-stream";
19
+ import {
20
+ streamWorkspaceLiveEvents,
21
+ type WorkspaceLiveStreamOptions,
22
+ type WorkspaceLiveStreamTransport,
23
+ } from "./workspace-live-stream";
24
+ import {
25
+ OpenGeniInteractionClient,
26
+ type AuthRun,
27
+ type AuthRunListOptions,
28
+ type AuthRunListResponse,
29
+ type AuthRunMutationResponse,
30
+ type AttachedBrowserDevice,
31
+ type AttachedBrowserDeviceListOptions,
32
+ type AttachedBrowserDeviceListResponse,
33
+ type BrowserActionReceipt,
34
+ type BrowserActionRequest,
35
+ type BrowserClipboard,
36
+ type BrowserDiagnosticBatch,
37
+ type BrowserDiagnosticsOptions,
38
+ type BrowserDownload,
39
+ type BrowserDownloadListResponse,
40
+ type BrowserDownloadSaveRequest,
41
+ type BrowserDownloadSaveResponse,
42
+ type BrowserIdentity,
43
+ type BrowserIdentityListOptions,
44
+ type BrowserIdentityListResponse,
45
+ type BrowserIdentityMutationResponse,
46
+ type BrowserObservation,
47
+ type BrowserOpenTargetRequest,
48
+ type BrowserSession,
49
+ type BrowserSessionAttachment,
50
+ type BrowserSessionAttachmentRequest,
51
+ type BrowserSessionHeartbeatResponse,
52
+ type BrowserSessionLifecycleRequest,
53
+ type BrowserSessionListResponse,
54
+ type BrowserSessionMutationResponse,
55
+ type BrowserTargetListResponse,
56
+ type BrowserRevisionListResponse,
57
+ type ComputerActionReceipt,
58
+ type ComputerActionRequest,
59
+ type ComputerClipboard,
60
+ type ComputerObservation,
61
+ type ComputerSession,
62
+ type ComputerSessionAttachment,
63
+ type ComputerSessionAttachmentRequest,
64
+ type ComputerSessionHeartbeatResponse,
65
+ type ComputerSessionLifecycleRequest,
66
+ type ComputerSessionListResponse,
67
+ type ComputerSessionMutationResponse,
68
+ type ComputerTargetListResponse,
69
+ type CreateBrowserIdentityRequest,
70
+ type CreateBrowserSessionRequest,
71
+ type CreateComputerSessionRequest,
72
+ type CreateInteractionInterventionRequest,
73
+ type CreateNetworkRouteRequest,
74
+ type CreateSiteAuthConnectionRequest,
75
+ type ExternalAuthInteractiveRequest,
76
+ type ExternalAuthInteractiveResponse,
77
+ type ExternalAuthRunRequest,
78
+ type ExternalAuthRunResponse,
79
+ type InteractionIntervention,
80
+ type InteractionInterventionListOptions,
81
+ type InteractionInterventionListResponse,
82
+ type InteractionInterventionMutationResponse,
83
+ type NetworkRoute,
84
+ type NetworkRouteListOptions,
85
+ type NetworkRouteListResponse,
86
+ type NetworkRouteMutationResponse,
87
+ type ProtectedAuthFillRequest,
88
+ type ProtectedAuthFillResponse,
89
+ type PublishBrowserRevisionRequest,
90
+ type PublishBrowserRevisionResponse,
91
+ type ReportAuthRunRequest,
92
+ type ResolveInteractionInterventionRequest,
93
+ type SiteAuthConnection,
94
+ type SiteAuthConnectionListOptions,
95
+ type SiteAuthConnectionListResponse,
96
+ type SiteAuthConnectionMutationResponse,
97
+ type StartAuthRunRequest,
98
+ type UpdateNetworkRouteRequest,
99
+ type UpdateBrowserIdentityRequest,
100
+ type UpdateSiteAuthConnectionRequest,
101
+ type VerifyAuthRunRequest,
102
+ type WorkspaceInteractionRevisionEvent,
103
+ } from "./interaction";
15
104
  import type {
16
105
  AccessContext,
17
106
  ActivateCodexRealtimeConnectionRequest,
@@ -33,6 +122,14 @@ import type {
33
122
  CodexConnectStart,
34
123
  CodexUsage,
35
124
  CodexUsageMap,
125
+ SuperGrokAccount,
126
+ SuperGrokAccountsResponse,
127
+ SuperGrokAccountScope,
128
+ SuperGrokAllocatorUpdate,
129
+ SuperGrokConnectionStatus,
130
+ SuperGrokConnectPoll,
131
+ SuperGrokConnectStart,
132
+ SuperGrokRotationSettings,
36
133
  BillingSummary,
37
134
  BillingUsageResponse,
38
135
  InsightsRange,
@@ -41,6 +138,29 @@ import type {
41
138
  CapabilityCatalogItem,
42
139
  CapabilityCatalogResponse,
43
140
  CapabilityInstallation,
141
+ ApiIntegrationPreview,
142
+ ApiIntegrationOAuthStartRequest,
143
+ ApiIntegrationUninstallPreview,
144
+ InstallApiIntegrationRequest,
145
+ InstalledApiIntegration,
146
+ IntegrationFacetMutationResult,
147
+ IntegrationFacetRemovalResult,
148
+ IntegrationInstanceFacetsResponse,
149
+ ListIntegrationDefinitionsResponse,
150
+ ListApiIntegrationsResponse,
151
+ MutateIntegrationFacetRequest,
152
+ PreviewApiIntegrationRequest,
153
+ UninstallApiIntegrationRequest,
154
+ UninstallApiIntegrationResult,
155
+ UpsertIntegrationFacetRequest,
156
+ PreviewPluginRequest,
157
+ PluginPreview,
158
+ InstallPluginRequest,
159
+ InstalledPlugin,
160
+ ListInstalledPluginsResponse,
161
+ PluginUninstallPreview,
162
+ UninstallPluginRequest,
163
+ UninstallPluginResult,
44
164
  AddDocumentRequest,
45
165
  CreateKnowledgeDropRequest,
46
166
  MoveDocumentRequest,
@@ -54,11 +174,18 @@ import type {
54
174
  CreateApiKeyRequest,
55
175
  CreateApiKeyResponse,
56
176
  CreateCapabilityCatalogItemRequest,
177
+ InstallSkillRequest,
178
+ InstallLibrarySkillRequest,
179
+ InstalledSkill,
180
+ ListInstalledSkillsResponse,
57
181
  CreateCheckoutRequest,
58
182
  CreateCheckoutResponse,
59
183
  OpenGeniSlackBotInstallRequest,
60
184
  OpenGeniSlackBotInstallStart,
61
185
  SlackReactionChannelListResponse,
186
+ FikenInstallRequest,
187
+ FikenOAuthStartRequest,
188
+ FikenOAuthStartResponse,
62
189
  CreateConnectionRequest,
63
190
  CreateDocumentBaseRequest,
64
191
  CreateFileUploadRequest,
@@ -91,11 +218,14 @@ import type {
91
218
  GetPackResponse,
92
219
  GitHubAppInfo,
93
220
  GitHubRepositoriesResponse,
221
+ GoogleDriveBrowseResponse,
94
222
  GoogleDriveDisconnectRequest,
223
+ SaveGoogleDriveIntegrationSourceRequest,
95
224
  GoogleDriveLifecycleActionRequest,
96
225
  KnowledgeMemory,
97
226
  KnowledgeMemorySearchRequest,
98
227
  ListApiKeysResponse,
228
+ ListManagedOrganizationMembershipsResponse,
99
229
  ListPacksResponse,
100
230
  // Bring-your-own-compute: the Machines dashboard + per-machine metrics (M10).
101
231
  MachinesResponse,
@@ -107,27 +237,50 @@ import type {
107
237
  SwapActiveSandboxRequest,
108
238
  SwapActiveSandboxResponse,
109
239
  ListWorkspaceMembersResponse,
240
+ InstallPackRequest,
241
+ PackInstallationPreview,
242
+ ListSlackUserLinkAccessRequestsResponse,
243
+ PrepareSlackUserLinkAccessRequest,
244
+ SlackUserLinkAccessMutationRequest,
245
+ SlackUserLinkAccessRequest,
246
+ ApproveSlackUserLinkAccessRequest,
110
247
  PackInstallation,
248
+ PackUninstallPreview,
111
249
  LatencyMode,
112
250
  ReasoningEffort,
113
251
  RetainedScreenshotDownload,
114
252
  RetainedScreenshotDownloadOptions,
253
+ RetainedArtifactDownload,
254
+ RetainedArtifactDownloadOptions,
255
+ RetainedArtifactReference,
115
256
  RetainedArtifactContent,
116
257
  RetainedArtifactContentOptions,
117
258
  RetainedArtifactMetadata,
259
+ UpdateVideoGenerationPolicyRequest,
260
+ VideoArtifactPlaybackSource,
261
+ VideoGenerationOperationSummary,
262
+ VideoGenerationPolicy,
263
+ WorkspaceVideoGenerationSettings,
118
264
  RegisterCapabilityPackRequest,
119
265
  ResourceRef,
266
+ PreviewPackInstallationRequest,
267
+ PreviewSkillImportRequest,
120
268
  ScheduledTask,
121
269
  ScheduledTaskRun,
122
270
  Session,
123
271
  SessionListResponse,
272
+ AgentTopologyPageResponse,
273
+ UpdateSessionChannelRequest,
124
274
  UpdateSessionPinRequest,
275
+ UninstallPackRequest,
276
+ UninstallPackResult,
125
277
  SessionEvent,
126
278
  SessionEventCompactResult,
127
279
  SessionEventCompactResultOptions,
128
280
  SessionEventListOptions,
129
281
  SessionEventPage,
130
282
  SessionGoal,
283
+ SessionGoalRevision,
131
284
  SessionHumanInputRequest,
132
285
  SessionLineageResponse,
133
286
  SessionRealtimeMutationResponse,
@@ -135,6 +288,7 @@ import type {
135
288
  SyncSessionRealtimeLedgerResponse,
136
289
  RenewSessionRealtimeRequest,
137
290
  SessionMcpCredentialUpdateInput,
291
+ SubmittedTimelineAnnotation,
138
292
  UpdateSessionMcpApprovalPolicyRequest,
139
293
  UpdateSessionMcpApprovalPolicyResponse,
140
294
  SessionQueueSnapshot,
@@ -204,6 +358,7 @@ import type {
204
358
  UpdateKnowledgeMemoryRequest,
205
359
  UpdateScheduledTaskRequest,
206
360
  UpdateSessionGoalRequest,
361
+ ApplySessionGoalRevisionRequest,
207
362
  UpdateSessionRequest,
208
363
  UpdateSessionToolPolicyRequest,
209
364
  UpdateVariableSetRequest,
@@ -216,6 +371,9 @@ import type {
216
371
  VariableSet,
217
372
  VariableSetSecret,
218
373
  VariableSetVariableMetadata,
374
+ Channel,
375
+ CreateChannelRequest,
376
+ UpdateChannelRequest,
219
377
  Rig,
220
378
  RigVersion,
221
379
  RigChange,
@@ -226,12 +384,20 @@ import type {
226
384
  WorkspaceRegisteredPack,
227
385
  Workspace,
228
386
  ListConnectionsResponse,
387
+ ListSlackInstallationBindingsResponse,
388
+ SlackInstallationBinding,
229
389
  ConnectionResponse,
230
390
  OAuthStartRequest,
231
391
  OAuthStartResponse,
232
392
  SocialConnection,
233
393
  SocialOAuthStartRequest,
394
+ SkillImportPreview,
395
+ SkillUninstallPreview,
396
+ UninstallSkillRequest,
397
+ UninstallSkillResult,
234
398
  } from "./types";
399
+ import { GENERATED_VIDEO_MAX_BYTES } from "./types";
400
+ import { parseRetainedGeneratedImageReference } from "./retained-artifacts";
235
401
  import type {
236
402
  ActivateWorkspaceInstructionPolicyRequest,
237
403
  CreateWorkspaceInstructionPolicyDraftRequest,
@@ -248,6 +414,17 @@ import type {
248
414
  WorkspaceInstructionPolicyOnboardingProposalListResponse,
249
415
  WorkspaceInstructionPolicyRevision,
250
416
  } from "./workspace-instruction-policies";
417
+ import type {
418
+ ActivateCompanyProfileRevisionRequest,
419
+ CompanyProfileDiffRequest,
420
+ CompanyProfileDiffResponse,
421
+ CompanyProfileListOptions,
422
+ CompanyProfileListResponse,
423
+ CompanyProfileMutationResponse,
424
+ CompanyProfileRevision,
425
+ RollbackCompanyProfileRequest,
426
+ UpdateCompanyProfileRequest,
427
+ } from "./company-profile";
251
428
  import type {
252
429
  WorkspaceStateExportResponse,
253
430
  WorkspaceStateGetOptions,
@@ -315,6 +492,7 @@ export type OpenGeniRequestOptions = {
315
492
 
316
493
  export type SendMessageInput = {
317
494
  text: string;
495
+ annotations?: SubmittedTimelineAnnotation[];
318
496
  /** System instructions scoped to this exact turn; never visible timeline text. */
319
497
  turnInstructions?: string;
320
498
  resources?: ResourceRef[];
@@ -333,6 +511,10 @@ export type SteerMessageResult = {
333
511
  accepted: SessionEvent;
334
512
  /** The exact turn created for this message in the same server transaction. */
335
513
  turn: SessionTurn;
514
+ /** Number of live attempts durably asked to stop by this atomic Steer. */
515
+ interruptionCount?: number;
516
+ /** True when this response came from the command's immutable idempotency receipt. */
517
+ replay?: boolean;
336
518
  };
337
519
 
338
520
  export type TranscribeAudioInput = {
@@ -375,12 +557,15 @@ export class OpenGeniClient {
375
557
  private readonly fetchImpl: FetchLike;
376
558
  private readonly readInFlight = new Map<string, Promise<unknown>>();
377
559
  private readonly readTrailing = new Map<string, Promise<unknown>>();
560
+ /** Resource-oriented Browser/Computer facade over this exact authenticated client. */
561
+ readonly interaction: OpenGeniInteractionClient;
378
562
 
379
563
  constructor(options: OpenGeniClientOptions) {
380
564
  this.baseUrl = options.baseUrl.replace(/\/+$/, "");
381
565
  this.options = options;
382
566
  // Bind lazily so variable sets that polyfill fetch after module load work.
383
567
  this.fetchImpl = options.fetch ?? ((input, init) => fetch(input, init));
568
+ this.interaction = new OpenGeniInteractionClient(this);
384
569
  }
385
570
 
386
571
  // --- Session lifecycle ---------------------------------------------------
@@ -769,6 +954,32 @@ export class OpenGeniClient {
769
954
  return response;
770
955
  }
771
956
 
957
+ /** Compact, bounded workspace agent hierarchy page. */
958
+ async listAgentTopology(
959
+ workspaceId: string,
960
+ options: {
961
+ limit?: number;
962
+ parentSessionId?: string | null;
963
+ cursor?: string;
964
+ search?: string;
965
+ } = {},
966
+ ): Promise<AgentTopologyPageResponse> {
967
+ const search = options.search?.trim();
968
+ return await this.requestJson<AgentTopologyPageResponse>(
969
+ "GET",
970
+ `/v1/workspaces/${workspaceId}/agent-topology`,
971
+ undefined,
972
+ {
973
+ ...(options.limit !== undefined ? { limit: String(options.limit) } : {}),
974
+ ...(options.parentSessionId === undefined
975
+ ? {}
976
+ : { parentSessionId: options.parentSessionId ?? "null" }),
977
+ ...(options.cursor ? { cursor: options.cursor } : {}),
978
+ ...(search ? { search } : {}),
979
+ },
980
+ );
981
+ }
982
+
772
983
  /** Set this authenticated member's personal workspace pin for a session. */
773
984
  async updateSessionPin(
774
985
  workspaceId: string,
@@ -849,6 +1060,22 @@ export class OpenGeniClient {
849
1060
  );
850
1061
  }
851
1062
 
1063
+ /** Mint a short-lived browser token from a connected SuperGrok account. */
1064
+ async negotiateXaiSubscriptionRealtime(
1065
+ workspaceId: string,
1066
+ sessionId: string,
1067
+ request: GatewayRealtimeConnectRequest,
1068
+ options: { signal?: AbortSignal | undefined } = {},
1069
+ ): Promise<GatewayRealtimeConnectResponse> {
1070
+ return await this.requestJson<GatewayRealtimeConnectResponse>(
1071
+ "POST",
1072
+ `/v1/workspaces/${workspaceId}/sessions/${sessionId}/realtime/supergrok`,
1073
+ request,
1074
+ {},
1075
+ { signal: options.signal },
1076
+ );
1077
+ }
1078
+
852
1079
  /** Promote a negotiated connection only after its browser data channel is ready. */
853
1080
  async activateCodexRealtimeConnection(
854
1081
  workspaceId: string,
@@ -1633,6 +1860,61 @@ export class OpenGeniClient {
1633
1860
  return streamWorkspaceControlEvents(this.workspaceControlStreamTransport(workspaceId), options);
1634
1861
  }
1635
1862
 
1863
+ /**
1864
+ * Multiplex workspace control and interaction invalidations over one HTTP
1865
+ * connection while retaining an independent durable cursor for each domain.
1866
+ */
1867
+ streamWorkspaceLiveEvents(workspaceId: string, options: WorkspaceLiveStreamOptions = {}) {
1868
+ return streamWorkspaceLiveEvents(this.workspaceLiveStreamTransport(workspaceId), options);
1869
+ }
1870
+
1871
+ workspaceLiveStreamTransport(workspaceId: string): WorkspaceLiveStreamTransport {
1872
+ return {
1873
+ openStream: async (controlAfter, interactionAfter, signal) =>
1874
+ await this.openWorkspaceLiveEventStream(workspaceId, {
1875
+ controlAfter,
1876
+ interactionAfter,
1877
+ ...(signal ? { signal } : {}),
1878
+ }),
1879
+ };
1880
+ }
1881
+
1882
+ async openWorkspaceLiveEventStream(
1883
+ workspaceId: string,
1884
+ options: {
1885
+ controlAfter?: number;
1886
+ interactionAfter?: number;
1887
+ signal?: AbortSignal;
1888
+ } = {},
1889
+ ): Promise<ReadableStream<Uint8Array>> {
1890
+ const correlationId = crypto.randomUUID();
1891
+ const response = await this.fetchImpl(
1892
+ this.url(`/v1/workspaces/${workspaceId}/live-events/stream`, {
1893
+ controlAfter: String(options.controlAfter ?? 0),
1894
+ interactionAfter: String(options.interactionAfter ?? 0),
1895
+ }),
1896
+ {
1897
+ method: "GET",
1898
+ headers: {
1899
+ ...this.headers(correlationId),
1900
+ Accept: "text/event-stream",
1901
+ },
1902
+ ...(options.signal ? { signal: options.signal } : {}),
1903
+ },
1904
+ );
1905
+ assertApiContractResponse(response);
1906
+ if (!response.ok) {
1907
+ throw await apiErrorFromResponse(response, {
1908
+ method: "GET",
1909
+ correlationId,
1910
+ });
1911
+ }
1912
+ if (!response.body) {
1913
+ throw new OpenGeniApiError(response.status, "SSE response did not include a readable body");
1914
+ }
1915
+ return response.body;
1916
+ }
1917
+
1636
1918
  workspaceControlStreamTransport(workspaceId: string): WorkspaceControlStreamTransport {
1637
1919
  return {
1638
1920
  openStream: async (after, signal) =>
@@ -1711,6 +1993,26 @@ export class OpenGeniClient {
1711
1993
  );
1712
1994
  }
1713
1995
 
1996
+ async listGoalRevisions(workspaceId: string, sessionId: string): Promise<SessionGoalRevision[]> {
1997
+ return await this.requestJson<SessionGoalRevision[]>(
1998
+ "GET",
1999
+ `/v1/workspaces/${workspaceId}/sessions/${sessionId}/goal/revisions`,
2000
+ );
2001
+ }
2002
+
2003
+ async applyGoalRevision(
2004
+ workspaceId: string,
2005
+ sessionId: string,
2006
+ revisionId: string,
2007
+ request: ApplySessionGoalRevisionRequest,
2008
+ ): Promise<SessionGoal> {
2009
+ return await this.requestJson<SessionGoal>(
2010
+ "POST",
2011
+ `/v1/workspaces/${workspaceId}/sessions/${sessionId}/goal/revisions/${revisionId}/apply`,
2012
+ request,
2013
+ );
2014
+ }
2015
+
1714
2016
  async deleteGoal(workspaceId: string, sessionId: string): Promise<void> {
1715
2017
  await this.requestVoid("DELETE", `/v1/workspaces/${workspaceId}/sessions/${sessionId}/goal`);
1716
2018
  }
@@ -2087,13 +2389,11 @@ export class OpenGeniClient {
2087
2389
  }
2088
2390
 
2089
2391
  /** Attach a viewer holder (refcounted liveness — keeps the box warm while
2090
- * watched/used), spinning the box up in-process when cold, and mint the scoped
2091
- * direct-to-provider URLs for the requested plane(s). `request.desktop:true`
2092
- * opts into the un-redacted pixel plane and mints the noVNC URL — that plane
2093
- * alone throws `OpenGeniApiError(409)` when the un-redacted/shared
2094
- * acknowledgment is missing (the consent gate). A terminal-only attach
2095
- * (`desktop` omitted/false) warms the box + mints the pty-ws terminal cell with
2096
- * NO consent gate. An omitted `viewerId` mints a fresh one. */
2392
+ * watched/used), spinning the box up in-process when cold. Exact plane flags
2393
+ * mint only the requested short-lived credentials and enforce that plane's
2394
+ * permission. `desktop:true` alone carries the un-redacted/shared consent
2395
+ * gate. An entirely omitted plane set retains the legacy terminal-only
2396
+ * meaning; current clients should send all three flags. */
2097
2397
  async attachViewer(
2098
2398
  workspaceId: string,
2099
2399
  sessionId: string,
@@ -2130,1355 +2430,2952 @@ export class OpenGeniClient {
2130
2430
  );
2131
2431
  }
2132
2432
 
2133
- // --- Access + workspaces -----------------------------------------------------
2433
+ // --- Browser / Computer interaction resources --------------------------------
2134
2434
 
2135
- /**
2136
- * The deployment's public client bootstrap config: the host-exposed models
2137
- * (provider-grouped in `models`, flat in `allowedModels` for back-compat),
2138
- * reasoning efforts, MCP servers, file-upload limits, and how the client is
2139
- * expected to authenticate. Drives a composer's model picker without prior
2140
- * knowledge of the host setup; safe to call before any auth is established.
2141
- */
2142
- async getClientConfig(): Promise<ClientConfig> {
2143
- const config = await this.requestJson<ClientConfig>("GET", "/v1/config/client");
2144
- if (config.apiContractRevision !== OPENGENI_API_CONTRACT_REVISION) {
2145
- throw new OpenGeniApiContractMismatchError(
2146
- OPENGENI_API_CONTRACT_REVISION,
2147
- String(config.apiContractRevision || "(missing)"),
2148
- );
2149
- }
2150
- return config;
2435
+ streamWorkspaceInteractionRevisions(
2436
+ workspaceId: string,
2437
+ options: StreamSessionEventsOptions = {},
2438
+ ): AsyncGenerator<WorkspaceInteractionRevisionEvent, void, void> {
2439
+ return streamWorkspaceInteractionRevisions(
2440
+ this.workspaceInteractionRevisionStreamTransport(workspaceId),
2441
+ options,
2442
+ );
2151
2443
  }
2152
2444
 
2153
- /** Authenticated model definitions plus workspace-specific selectability. */
2154
- async getWorkspaceModelCatalog(workspaceId: string): Promise<WorkspaceModelCatalogResponse> {
2155
- return await this.requestJson<WorkspaceModelCatalogResponse>(
2156
- "GET",
2157
- `/v1/workspaces/${workspaceId}/model-catalog`,
2445
+ workspaceInteractionRevisionStreamTransport(
2446
+ workspaceId: string,
2447
+ ): WorkspaceInteractionRevisionStreamTransport {
2448
+ return {
2449
+ openStream: async (after, signal) =>
2450
+ await this.openWorkspaceInteractionRevisionStream(workspaceId, {
2451
+ after,
2452
+ ...(signal ? { signal } : {}),
2453
+ }),
2454
+ };
2455
+ }
2456
+
2457
+ async openWorkspaceInteractionRevisionStream(
2458
+ workspaceId: string,
2459
+ options: { after?: number; signal?: AbortSignal } = {},
2460
+ ): Promise<ReadableStream<Uint8Array>> {
2461
+ const correlationId = crypto.randomUUID();
2462
+ const response = await this.fetchImpl(
2463
+ this.url(`/v1/workspaces/${workspaceId}/interaction-events/stream`, {
2464
+ after: String(options.after ?? 0),
2465
+ }),
2466
+ {
2467
+ method: "GET",
2468
+ headers: {
2469
+ ...this.headers(correlationId),
2470
+ Accept: "text/event-stream",
2471
+ },
2472
+ ...(options.signal ? { signal: options.signal } : {}),
2473
+ },
2158
2474
  );
2475
+ assertApiContractResponse(response);
2476
+ if (!response.ok) {
2477
+ throw await apiErrorFromResponse(response, {
2478
+ method: "GET",
2479
+ correlationId,
2480
+ });
2481
+ }
2482
+ if (!response.body) {
2483
+ throw new OpenGeniApiError(response.status, "SSE response did not include a readable body");
2484
+ }
2485
+ return response.body;
2159
2486
  }
2160
2487
 
2161
- /** Authenticated realtime voice models and credential readiness. */
2162
- async getWorkspaceRealtimeModelCatalog(
2488
+ async listNetworkRoutes(
2163
2489
  workspaceId: string,
2164
- ): Promise<WorkspaceRealtimeModelCatalogResponse> {
2165
- return await this.requestJson<WorkspaceRealtimeModelCatalogResponse>(
2490
+ options: NetworkRouteListOptions = {},
2491
+ ): Promise<NetworkRouteListResponse> {
2492
+ return await this.requestJson<NetworkRouteListResponse>(
2166
2493
  "GET",
2167
- `/v1/workspaces/${workspaceId}/realtime-model-catalog`,
2494
+ `/v1/workspaces/${workspaceId}/network-routes`,
2495
+ undefined,
2496
+ options.includeArchived ? { includeArchived: "true" } : {},
2497
+ options,
2168
2498
  );
2169
2499
  }
2170
2500
 
2171
- /** The caller's access context: subject, account + workspace grants, defaults. */
2172
- async getAccessContext(): Promise<AccessContext> {
2173
- return await this.requestJson<AccessContext>("GET", "/v1/access/me");
2501
+ async getNetworkRoute(
2502
+ workspaceId: string,
2503
+ networkRouteId: string,
2504
+ options: OpenGeniRequestOptions = {},
2505
+ ): Promise<NetworkRoute> {
2506
+ return await this.requestJson<NetworkRoute>(
2507
+ "GET",
2508
+ `/v1/workspaces/${workspaceId}/network-routes/${encodeURIComponent(networkRouteId)}`,
2509
+ undefined,
2510
+ {},
2511
+ options,
2512
+ );
2174
2513
  }
2175
2514
 
2176
- async listWorkspaces(): Promise<Workspace[]> {
2177
- return await this.requestJson<Workspace[]>("GET", "/v1/workspaces");
2515
+ async createNetworkRoute(
2516
+ workspaceId: string,
2517
+ request: CreateNetworkRouteRequest,
2518
+ options: OpenGeniRequestOptions = {},
2519
+ ): Promise<NetworkRouteMutationResponse> {
2520
+ return await this.requestJson<NetworkRouteMutationResponse>(
2521
+ "POST",
2522
+ `/v1/workspaces/${workspaceId}/network-routes`,
2523
+ request,
2524
+ {},
2525
+ options,
2526
+ );
2178
2527
  }
2179
2528
 
2180
- async createWorkspace(request: CreateWorkspaceRequest): Promise<Workspace> {
2181
- return await this.requestJson<Workspace>("POST", "/v1/workspaces", request);
2529
+ async updateNetworkRoute(
2530
+ workspaceId: string,
2531
+ networkRouteId: string,
2532
+ request: UpdateNetworkRouteRequest,
2533
+ options: OpenGeniRequestOptions = {},
2534
+ ): Promise<NetworkRouteMutationResponse> {
2535
+ return await this.requestJson<NetworkRouteMutationResponse>(
2536
+ "PATCH",
2537
+ `/v1/workspaces/${workspaceId}/network-routes/${encodeURIComponent(networkRouteId)}`,
2538
+ request,
2539
+ {},
2540
+ options,
2541
+ );
2182
2542
  }
2183
2543
 
2184
- async getWorkspace(workspaceId: string): Promise<Workspace> {
2185
- return await this.requestJson<Workspace>("GET", `/v1/workspaces/${workspaceId}`);
2544
+ async listSiteAuthConnections(
2545
+ workspaceId: string,
2546
+ options: SiteAuthConnectionListOptions = {},
2547
+ ): Promise<SiteAuthConnectionListResponse> {
2548
+ return await this.requestJson<SiteAuthConnectionListResponse>(
2549
+ "GET",
2550
+ `/v1/workspaces/${workspaceId}/site-auth-connections`,
2551
+ undefined,
2552
+ options.includeArchived ? { includeArchived: "true" } : {},
2553
+ options,
2554
+ );
2186
2555
  }
2187
2556
 
2188
- /** Read-time, secret-safe inventory of policy heads and visible workspace knowledge. */
2189
- async getWorkspaceState(
2557
+ async getSiteAuthConnection(
2190
2558
  workspaceId: string,
2191
- options: WorkspaceStateGetOptions = {},
2192
- ): Promise<WorkspaceStateResponse> {
2193
- const params = new URLSearchParams();
2194
- if (options.attemptId) params.set("attemptId", options.attemptId);
2195
- const query = params.size > 0 ? `?${params.toString()}` : "";
2196
- return await this.requestJson<WorkspaceStateResponse>(
2559
+ siteAuthConnectionId: string,
2560
+ options: OpenGeniRequestOptions = {},
2561
+ ): Promise<SiteAuthConnection> {
2562
+ return await this.requestJson<SiteAuthConnection>(
2197
2563
  "GET",
2198
- `/v1/workspaces/${workspaceId}/workspace-state${query}`,
2564
+ `/v1/workspaces/${workspaceId}/site-auth-connections/${encodeURIComponent(siteAuthConnectionId)}`,
2565
+ undefined,
2566
+ {},
2567
+ options,
2199
2568
  );
2200
2569
  }
2201
2570
 
2202
- /** Download the canonical, explicitly sanitized Workspace State export. */
2203
- async exportWorkspaceState(
2571
+ async createSiteAuthConnection(
2204
2572
  workspaceId: string,
2205
- options: WorkspaceStateGetOptions = {},
2206
- ): Promise<WorkspaceStateExportResponse> {
2207
- const params = new URLSearchParams();
2208
- if (options.attemptId) params.set("attemptId", options.attemptId);
2209
- const query = params.size > 0 ? `?${params.toString()}` : "";
2210
- return await this.requestJson<WorkspaceStateExportResponse>(
2211
- "GET",
2212
- `/v1/workspaces/${workspaceId}/workspace-state/export${query}`,
2573
+ request: CreateSiteAuthConnectionRequest,
2574
+ options: OpenGeniRequestOptions = {},
2575
+ ): Promise<SiteAuthConnectionMutationResponse> {
2576
+ return await this.requestJson<SiteAuthConnectionMutationResponse>(
2577
+ "POST",
2578
+ `/v1/workspaces/${workspaceId}/site-auth-connections`,
2579
+ request,
2580
+ {},
2581
+ options,
2213
2582
  );
2214
2583
  }
2215
2584
 
2216
- async updateWorkspace(workspaceId: string, request: UpdateWorkspaceRequest): Promise<Workspace> {
2217
- return await this.requestJson<Workspace>("PATCH", `/v1/workspaces/${workspaceId}`, request);
2585
+ async updateSiteAuthConnection(
2586
+ workspaceId: string,
2587
+ siteAuthConnectionId: string,
2588
+ request: UpdateSiteAuthConnectionRequest,
2589
+ options: OpenGeniRequestOptions = {},
2590
+ ): Promise<SiteAuthConnectionMutationResponse> {
2591
+ return await this.requestJson<SiteAuthConnectionMutationResponse>(
2592
+ "PATCH",
2593
+ `/v1/workspaces/${workspaceId}/site-auth-connections/${encodeURIComponent(siteAuthConnectionId)}`,
2594
+ request,
2595
+ {},
2596
+ options,
2597
+ );
2218
2598
  }
2219
2599
 
2220
- /** Inspect immutable instruction-policy history, active heads, and activation audit evidence. */
2221
- async listWorkspaceInstructionPolicies(
2600
+ async listAuthRuns(
2222
2601
  workspaceId: string,
2223
- options: WorkspaceInstructionPolicyListOptions = {},
2224
- ): Promise<WorkspaceInstructionPolicyListResponse> {
2225
- const params = new URLSearchParams();
2226
- if (options.kind !== undefined) params.set("kind", options.kind);
2227
- if (options.scope !== undefined) params.set("scope", options.scope);
2228
- if (options.roleKey !== undefined) params.set("roleKey", options.roleKey);
2229
- if (options.afterRevision !== undefined) {
2230
- params.set("afterRevision", String(options.afterRevision));
2231
- }
2232
- if (options.limit !== undefined) params.set("limit", String(options.limit));
2233
- const query = params.toString();
2234
- return await this.requestJson<WorkspaceInstructionPolicyListResponse>(
2602
+ options: AuthRunListOptions = {},
2603
+ ): Promise<AuthRunListResponse> {
2604
+ return await this.requestJson<AuthRunListResponse>(
2235
2605
  "GET",
2236
- `/v1/workspaces/${workspaceId}/instruction-policies${query ? `?${query}` : ""}`,
2606
+ `/v1/workspaces/${workspaceId}/auth-runs`,
2607
+ undefined,
2608
+ {
2609
+ ...(options.browserSessionId ? { browserSessionId: options.browserSessionId } : {}),
2610
+ ...(options.siteAuthConnectionId
2611
+ ? { siteAuthConnectionId: options.siteAuthConnectionId }
2612
+ : {}),
2613
+ ...(options.includeSettled ? { includeSettled: "true" } : {}),
2614
+ },
2615
+ options,
2237
2616
  );
2238
2617
  }
2239
2618
 
2240
- async getWorkspaceInstructionPolicyRevision(
2619
+ async getAuthRun(
2241
2620
  workspaceId: string,
2242
- revisionId: string,
2243
- ): Promise<WorkspaceInstructionPolicyRevision> {
2244
- return await this.requestJson<WorkspaceInstructionPolicyRevision>(
2621
+ authRunId: string,
2622
+ options: OpenGeniRequestOptions = {},
2623
+ ): Promise<AuthRun> {
2624
+ return await this.requestJson<AuthRun>(
2245
2625
  "GET",
2246
- `/v1/workspaces/${workspaceId}/instruction-policies/${encodeURIComponent(revisionId)}`,
2626
+ `/v1/workspaces/${workspaceId}/auth-runs/${encodeURIComponent(authRunId)}`,
2627
+ undefined,
2628
+ {},
2629
+ options,
2247
2630
  );
2248
2631
  }
2249
2632
 
2250
- async createWorkspaceInstructionPolicyDraft(
2633
+ async startBrowserAuthRun(
2251
2634
  workspaceId: string,
2252
- request: CreateWorkspaceInstructionPolicyDraftRequest,
2253
- ): Promise<WorkspaceInstructionPolicyRevision> {
2254
- return await this.requestJson<WorkspaceInstructionPolicyRevision>(
2635
+ browserSessionId: string,
2636
+ request: StartAuthRunRequest,
2637
+ options: OpenGeniRequestOptions = {},
2638
+ ): Promise<AuthRunMutationResponse> {
2639
+ return await this.requestJson<AuthRunMutationResponse>(
2255
2640
  "POST",
2256
- `/v1/workspaces/${workspaceId}/instruction-policies/drafts`,
2641
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/auth-runs`,
2257
2642
  request,
2643
+ {},
2644
+ options,
2258
2645
  );
2259
2646
  }
2260
2647
 
2261
- /** List the newest immutable onboarding proposals and their inactive policy drafts. */
2262
- async listWorkspaceInstructionPolicyOnboardingProposals(
2263
- workspaceId: string,
2264
- options: WorkspaceInstructionPolicyOnboardingProposalListOptions = {},
2265
- ): Promise<WorkspaceInstructionPolicyOnboardingProposalListResponse> {
2266
- const params = new URLSearchParams();
2267
- if (options.limit !== undefined) params.set("limit", String(options.limit));
2268
- const query = params.toString();
2269
- return await this.requestJson<WorkspaceInstructionPolicyOnboardingProposalListResponse>(
2270
- "GET",
2271
- `/v1/workspaces/${workspaceId}/instruction-policies/onboarding-proposals${query ? `?${query}` : ""}`,
2272
- );
2273
- }
2274
-
2275
- /** Create one draft-only proposal against an exact active-policy baseline. */
2276
- async createWorkspaceInstructionPolicyOnboardingProposal(
2648
+ async reportBrowserAuthRun(
2277
2649
  workspaceId: string,
2278
- request: CreateWorkspaceInstructionPolicyOnboardingProposalRequest,
2279
- ): Promise<WorkspaceInstructionPolicyOnboardingProposal> {
2280
- return await this.requestJson<WorkspaceInstructionPolicyOnboardingProposal>(
2650
+ browserSessionId: string,
2651
+ authRunId: string,
2652
+ request: ReportAuthRunRequest,
2653
+ options: OpenGeniRequestOptions = {},
2654
+ ): Promise<AuthRunMutationResponse> {
2655
+ return await this.requestJson<AuthRunMutationResponse>(
2281
2656
  "POST",
2282
- `/v1/workspaces/${workspaceId}/instruction-policies/onboarding-proposals`,
2657
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/auth-runs/${encodeURIComponent(authRunId)}/report`,
2283
2658
  request,
2659
+ {},
2660
+ options,
2284
2661
  );
2285
2662
  }
2286
2663
 
2287
- /** Import the stored legacy workspace override as an inactive charter draft. */
2288
- async importLegacyWorkspaceInstructionPolicyDraft(
2664
+ async protectedBrowserAuthFill(
2289
2665
  workspaceId: string,
2290
- request: ImportLegacyWorkspaceInstructionPolicyDraftRequest = {},
2291
- ): Promise<WorkspaceInstructionPolicyRevision> {
2292
- return await this.requestJson<WorkspaceInstructionPolicyRevision>(
2666
+ browserSessionId: string,
2667
+ authRunId: string,
2668
+ request: ProtectedAuthFillRequest,
2669
+ options: OpenGeniRequestOptions = {},
2670
+ ): Promise<ProtectedAuthFillResponse> {
2671
+ return await this.requestJson<ProtectedAuthFillResponse>(
2293
2672
  "POST",
2294
- `/v1/workspaces/${workspaceId}/instruction-policies/import-legacy`,
2673
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/auth-runs/${encodeURIComponent(authRunId)}/protected-fill`,
2295
2674
  request,
2675
+ {},
2676
+ options,
2296
2677
  );
2297
2678
  }
2298
2679
 
2299
- async diffWorkspaceInstructionPolicyRevisions(
2680
+ async advanceExternalBrowserAuthRun(
2300
2681
  workspaceId: string,
2301
- request: WorkspaceInstructionPolicyDiffRequest,
2302
- ): Promise<WorkspaceInstructionPolicyDiffResponse> {
2303
- const params = new URLSearchParams({
2304
- fromRevisionId: request.fromRevisionId,
2305
- toRevisionId: request.toRevisionId,
2306
- });
2307
- return await this.requestJson<WorkspaceInstructionPolicyDiffResponse>(
2308
- "GET",
2309
- `/v1/workspaces/${workspaceId}/instruction-policies/diff?${params}`,
2682
+ browserSessionId: string,
2683
+ authRunId: string,
2684
+ request: ExternalAuthRunRequest,
2685
+ options: OpenGeniRequestOptions = {},
2686
+ ): Promise<ExternalAuthRunResponse> {
2687
+ return await this.requestJson<ExternalAuthRunResponse>(
2688
+ "POST",
2689
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/auth-runs/${encodeURIComponent(authRunId)}/external-auth`,
2690
+ request,
2691
+ {},
2692
+ options,
2310
2693
  );
2311
2694
  }
2312
2695
 
2313
- async activateWorkspaceInstructionPolicyRevision(
2696
+ async openExternalBrowserAuthFlow(
2314
2697
  workspaceId: string,
2315
- revisionId: string,
2316
- request: ActivateWorkspaceInstructionPolicyRequest,
2317
- ): Promise<WorkspaceInstructionPolicyActivationResponse> {
2318
- return await this.requestJson<WorkspaceInstructionPolicyActivationResponse>(
2698
+ browserSessionId: string,
2699
+ authRunId: string,
2700
+ request: ExternalAuthInteractiveRequest,
2701
+ options: OpenGeniRequestOptions = {},
2702
+ ): Promise<ExternalAuthInteractiveResponse> {
2703
+ return await this.requestJson<ExternalAuthInteractiveResponse>(
2319
2704
  "POST",
2320
- `/v1/workspaces/${workspaceId}/instruction-policies/${encodeURIComponent(revisionId)}/activate`,
2705
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/auth-runs/${encodeURIComponent(authRunId)}/external-auth/interactive`,
2321
2706
  request,
2707
+ {},
2708
+ options,
2322
2709
  );
2323
2710
  }
2324
2711
 
2325
- async rollbackWorkspaceInstructionPolicyRevision(
2712
+ async verifyBrowserAuthRun(
2326
2713
  workspaceId: string,
2327
- request: RollbackWorkspaceInstructionPolicyRequest,
2328
- ): Promise<WorkspaceInstructionPolicyActivationResponse> {
2329
- return await this.requestJson<WorkspaceInstructionPolicyActivationResponse>(
2714
+ browserSessionId: string,
2715
+ authRunId: string,
2716
+ request: VerifyAuthRunRequest,
2717
+ options: OpenGeniRequestOptions = {},
2718
+ ): Promise<AuthRunMutationResponse> {
2719
+ return await this.requestJson<AuthRunMutationResponse>(
2330
2720
  "POST",
2331
- `/v1/workspaces/${workspaceId}/instruction-policies/rollback`,
2721
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/auth-runs/${encodeURIComponent(authRunId)}/verify`,
2332
2722
  request,
2723
+ {},
2724
+ options,
2333
2725
  );
2334
2726
  }
2335
2727
 
2336
- async listPreferenceRegistry(
2728
+ async listInteractionInterventions(
2337
2729
  workspaceId: string,
2338
- options: PreferenceRegistryListOptions = {},
2339
- ): Promise<PreferenceRegistryListResponse> {
2340
- const params = new URLSearchParams();
2341
- if (options.scope) params.set("scope", options.scope);
2342
- if (options.status) params.set("status", options.status);
2343
- if (options.limit !== undefined) params.set("limit", String(options.limit));
2344
- const query = params.toString();
2345
- return await this.requestJson<PreferenceRegistryListResponse>(
2730
+ options: InteractionInterventionListOptions = {},
2731
+ ): Promise<InteractionInterventionListResponse> {
2732
+ return await this.requestJson<InteractionInterventionListResponse>(
2346
2733
  "GET",
2347
- `/v1/workspaces/${workspaceId}/preferences${query ? `?${query}` : ""}`,
2734
+ `/v1/workspaces/${workspaceId}/interaction-interventions`,
2735
+ undefined,
2736
+ {
2737
+ ...(options.resourceKind ? { resourceKind: options.resourceKind } : {}),
2738
+ ...(options.resourceId ? { resourceId: options.resourceId } : {}),
2739
+ ...(options.includeSettled ? { includeSettled: "true" } : {}),
2740
+ },
2741
+ options,
2348
2742
  );
2349
2743
  }
2350
2744
 
2351
- async getPreferenceRegistry(
2745
+ async getInteractionIntervention(
2352
2746
  workspaceId: string,
2353
- preferenceId: string,
2354
- ): Promise<PreferenceRegistryDetailResponse> {
2355
- return await this.requestJson<PreferenceRegistryDetailResponse>(
2747
+ interventionId: string,
2748
+ options: OpenGeniRequestOptions = {},
2749
+ ): Promise<InteractionIntervention> {
2750
+ return await this.requestJson<InteractionIntervention>(
2356
2751
  "GET",
2357
- `/v1/workspaces/${workspaceId}/preferences/${encodeURIComponent(preferenceId)}`,
2752
+ `/v1/workspaces/${workspaceId}/interaction-interventions/${encodeURIComponent(interventionId)}`,
2753
+ undefined,
2754
+ {},
2755
+ options,
2358
2756
  );
2359
2757
  }
2360
2758
 
2361
- async createPreferenceRegistryProposal(
2759
+ async createInteractionIntervention(
2362
2760
  workspaceId: string,
2363
- request: CreatePreferenceRegistryProposalRequest,
2364
- ): Promise<PreferenceRegistryRecord> {
2365
- return await this.requestJson<PreferenceRegistryRecord>(
2761
+ request: CreateInteractionInterventionRequest,
2762
+ options: OpenGeniRequestOptions = {},
2763
+ ): Promise<InteractionInterventionMutationResponse> {
2764
+ return await this.requestJson<InteractionInterventionMutationResponse>(
2366
2765
  "POST",
2367
- `/v1/workspaces/${workspaceId}/preferences/proposals`,
2766
+ `/v1/workspaces/${workspaceId}/interaction-interventions`,
2368
2767
  request,
2768
+ {},
2769
+ options,
2369
2770
  );
2370
2771
  }
2371
2772
 
2372
- async activatePreferenceRegistryRevision(
2773
+ async resolveInteractionIntervention(
2373
2774
  workspaceId: string,
2374
- preferenceId: string,
2375
- request: ActivatePreferenceRegistryRevisionRequest,
2376
- ): Promise<PreferenceRegistryMutationResponse> {
2377
- return await this.requestJson<PreferenceRegistryMutationResponse>(
2775
+ interventionId: string,
2776
+ request: ResolveInteractionInterventionRequest,
2777
+ options: OpenGeniRequestOptions = {},
2778
+ ): Promise<InteractionInterventionMutationResponse> {
2779
+ return await this.requestJson<InteractionInterventionMutationResponse>(
2378
2780
  "POST",
2379
- `/v1/workspaces/${workspaceId}/preferences/${encodeURIComponent(preferenceId)}/activate`,
2781
+ `/v1/workspaces/${workspaceId}/interaction-interventions/${encodeURIComponent(interventionId)}/resolve`,
2380
2782
  request,
2783
+ {},
2784
+ options,
2381
2785
  );
2382
2786
  }
2383
2787
 
2384
- async correctPreferenceRegistry(
2788
+ async listAttachedBrowsers(
2385
2789
  workspaceId: string,
2386
- preferenceId: string,
2387
- request: CorrectPreferenceRegistryRequest,
2388
- ): Promise<PreferenceRegistryMutationResponse> {
2389
- return await this.requestJson<PreferenceRegistryMutationResponse>(
2390
- "POST",
2391
- `/v1/workspaces/${workspaceId}/preferences/${encodeURIComponent(preferenceId)}/correct`,
2392
- request,
2790
+ options: AttachedBrowserDeviceListOptions = {},
2791
+ ): Promise<AttachedBrowserDeviceListResponse> {
2792
+ return await this.requestJson<AttachedBrowserDeviceListResponse>(
2793
+ "GET",
2794
+ `/v1/workspaces/${workspaceId}/attached-browsers`,
2795
+ undefined,
2796
+ options.includeDisconnected ? { includeDisconnected: "true" } : {},
2797
+ options,
2393
2798
  );
2394
2799
  }
2395
2800
 
2396
- async changePreferenceRegistryScope(
2801
+ async getAttachedBrowser(
2397
2802
  workspaceId: string,
2398
- preferenceId: string,
2399
- request: ChangePreferenceRegistryScopeRequest,
2400
- ): Promise<PreferenceRegistryMutationResponse> {
2401
- return await this.requestJson<PreferenceRegistryMutationResponse>(
2402
- "POST",
2403
- `/v1/workspaces/${workspaceId}/preferences/${encodeURIComponent(preferenceId)}/scope`,
2404
- request,
2803
+ deviceId: string,
2804
+ options: OpenGeniRequestOptions = {},
2805
+ ): Promise<AttachedBrowserDevice> {
2806
+ return await this.requestJson<AttachedBrowserDevice>(
2807
+ "GET",
2808
+ `/v1/workspaces/${workspaceId}/attached-browsers/${encodeURIComponent(deviceId)}`,
2809
+ undefined,
2810
+ {},
2811
+ options,
2405
2812
  );
2406
2813
  }
2407
2814
 
2408
- async deactivatePreferenceRegistry(
2815
+ async listBrowserIdentities(
2409
2816
  workspaceId: string,
2410
- preferenceId: string,
2411
- request: DeactivatePreferenceRegistryRequest,
2412
- ): Promise<PreferenceRegistryMutationResponse> {
2413
- return await this.requestJson<PreferenceRegistryMutationResponse>(
2414
- "POST",
2415
- `/v1/workspaces/${workspaceId}/preferences/${encodeURIComponent(preferenceId)}/deactivate`,
2416
- request,
2817
+ options: BrowserIdentityListOptions = {},
2818
+ ): Promise<BrowserIdentityListResponse> {
2819
+ return await this.requestJson<BrowserIdentityListResponse>(
2820
+ "GET",
2821
+ `/v1/workspaces/${workspaceId}/browser-identities`,
2822
+ undefined,
2823
+ options.includeArchived ? { includeArchived: "true" } : {},
2824
+ options,
2417
2825
  );
2418
2826
  }
2419
2827
 
2420
- async supersedePreferenceRegistry(
2828
+ async getBrowserIdentity(
2421
2829
  workspaceId: string,
2422
- preferenceId: string,
2423
- request: SupersedePreferenceRegistryRequest,
2424
- ): Promise<PreferenceRegistryMutationResponse> {
2425
- return await this.requestJson<PreferenceRegistryMutationResponse>(
2830
+ identityId: string,
2831
+ options: OpenGeniRequestOptions = {},
2832
+ ): Promise<BrowserIdentity> {
2833
+ return await this.requestJson<BrowserIdentity>(
2834
+ "GET",
2835
+ `/v1/workspaces/${workspaceId}/browser-identities/${encodeURIComponent(identityId)}`,
2836
+ undefined,
2837
+ {},
2838
+ options,
2839
+ );
2840
+ }
2841
+
2842
+ async createBrowserIdentity(
2843
+ workspaceId: string,
2844
+ request: CreateBrowserIdentityRequest,
2845
+ options: OpenGeniRequestOptions = {},
2846
+ ): Promise<BrowserIdentityMutationResponse> {
2847
+ return await this.requestJson<BrowserIdentityMutationResponse>(
2426
2848
  "POST",
2427
- `/v1/workspaces/${workspaceId}/preferences/${encodeURIComponent(preferenceId)}/supersede`,
2849
+ `/v1/workspaces/${workspaceId}/browser-identities`,
2428
2850
  request,
2851
+ {},
2852
+ options,
2429
2853
  );
2430
2854
  }
2431
2855
 
2432
- async rejectPreferenceRegistryProposal(
2856
+ async updateBrowserIdentity(
2433
2857
  workspaceId: string,
2434
- preferenceId: string,
2435
- request: RejectPreferenceRegistryProposalRequest,
2436
- ): Promise<PreferenceRegistryMutationResponse> {
2437
- return await this.requestJson<PreferenceRegistryMutationResponse>(
2438
- "POST",
2439
- `/v1/workspaces/${workspaceId}/preferences/${encodeURIComponent(preferenceId)}/reject`,
2858
+ identityId: string,
2859
+ request: UpdateBrowserIdentityRequest,
2860
+ options: OpenGeniRequestOptions = {},
2861
+ ): Promise<BrowserIdentityMutationResponse> {
2862
+ return await this.requestJson<BrowserIdentityMutationResponse>(
2863
+ "PATCH",
2864
+ `/v1/workspaces/${workspaceId}/browser-identities/${encodeURIComponent(identityId)}`,
2440
2865
  request,
2866
+ {},
2867
+ options,
2441
2868
  );
2442
2869
  }
2443
2870
 
2444
- async getPreferenceRegistrySummary(workspaceId: string): Promise<PreferenceRegistrySnapshot> {
2445
- return await this.requestJson<PreferenceRegistrySnapshot>(
2871
+ async listBrowserRevisions(
2872
+ workspaceId: string,
2873
+ identityId: string,
2874
+ options: OpenGeniRequestOptions = {},
2875
+ ): Promise<BrowserRevisionListResponse> {
2876
+ return await this.requestJson<BrowserRevisionListResponse>(
2446
2877
  "GET",
2447
- `/v1/workspaces/${workspaceId}/preferences/summary`,
2878
+ `/v1/workspaces/${workspaceId}/browser-identities/${encodeURIComponent(identityId)}/revisions`,
2879
+ undefined,
2880
+ {},
2881
+ options,
2448
2882
  );
2449
2883
  }
2450
2884
 
2451
- async getPreferenceRegistryFullContent(
2885
+ /** Workspace-wide BrowserSession inventory. Associations express relevance,
2886
+ * not access: peers and child agents intentionally remain discoverable. */
2887
+ async listBrowserSessions(
2452
2888
  workspaceId: string,
2453
- retrievalHandle: string,
2454
- ): Promise<PreferenceRegistryFullContent> {
2455
- return await this.requestJson<PreferenceRegistryFullContent>(
2456
- "POST",
2457
- `/v1/workspaces/${workspaceId}/preferences/full-content`,
2458
- { retrievalHandle },
2889
+ options: OpenGeniRequestOptions = {},
2890
+ ): Promise<BrowserSessionListResponse> {
2891
+ return await this.requestJson<BrowserSessionListResponse>(
2892
+ "GET",
2893
+ `/v1/workspaces/${workspaceId}/browser-sessions`,
2894
+ undefined,
2895
+ {},
2896
+ options,
2459
2897
  );
2460
2898
  }
2461
2899
 
2462
- /**
2463
- * Delete a workspace and everything in it. Refused (409) for the account's
2464
- * only workspace and while it still has a running session. Irreversible.
2465
- */
2466
- async deleteWorkspace(workspaceId: string): Promise<void> {
2467
- await this.requestVoid("DELETE", `/v1/workspaces/${workspaceId}`);
2900
+ async getBrowserSession(
2901
+ workspaceId: string,
2902
+ browserSessionId: string,
2903
+ options: OpenGeniRequestOptions = {},
2904
+ ): Promise<BrowserSession> {
2905
+ return await this.requestJson<BrowserSession>(
2906
+ "GET",
2907
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}`,
2908
+ undefined,
2909
+ {},
2910
+ options,
2911
+ );
2468
2912
  }
2469
2913
 
2470
- // --- Members ("People with access") -------------------------------------------
2914
+ async readBrowserClipboard(
2915
+ workspaceId: string,
2916
+ browserSessionId: string,
2917
+ options: OpenGeniRequestOptions = {},
2918
+ ): Promise<BrowserClipboard> {
2919
+ return await this.requestJson<BrowserClipboard>(
2920
+ "GET",
2921
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/clipboard`,
2922
+ undefined,
2923
+ {},
2924
+ options,
2925
+ );
2926
+ }
2471
2927
 
2472
- /** The workspace's members (user + api_key subjects). */
2473
- async listWorkspaceMembers(workspaceId: string): Promise<WorkspaceMember[]> {
2474
- const response = await this.requestJson<ListWorkspaceMembersResponse>(
2928
+ async listBrowserDownloads(
2929
+ workspaceId: string,
2930
+ browserSessionId: string,
2931
+ options: OpenGeniRequestOptions = {},
2932
+ ): Promise<BrowserDownloadListResponse> {
2933
+ return await this.requestJson<BrowserDownloadListResponse>(
2475
2934
  "GET",
2476
- `/v1/workspaces/${workspaceId}/members`,
2935
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/downloads`,
2936
+ undefined,
2937
+ {},
2938
+ options,
2477
2939
  );
2478
- return response.members;
2479
2940
  }
2480
2941
 
2481
- /**
2482
- * Add an already-registered user by email. 404s when no user with that email
2483
- * exists (email invites for unknown users are deferred).
2484
- */
2485
- async addWorkspaceMember(
2942
+ async getBrowserDownload(
2486
2943
  workspaceId: string,
2487
- request: AddWorkspaceMemberRequest,
2488
- ): Promise<WorkspaceMember> {
2489
- return await this.requestJson<WorkspaceMember>(
2490
- "POST",
2491
- `/v1/workspaces/${workspaceId}/members`,
2492
- request,
2944
+ browserSessionId: string,
2945
+ downloadId: string,
2946
+ options: OpenGeniRequestOptions = {},
2947
+ ): Promise<BrowserDownload> {
2948
+ return await this.requestJson<BrowserDownload>(
2949
+ "GET",
2950
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/downloads/${encodeURIComponent(downloadId)}`,
2951
+ undefined,
2952
+ {},
2953
+ options,
2493
2954
  );
2494
2955
  }
2495
2956
 
2496
- async updateWorkspaceMember(
2957
+ async saveBrowserDownload(
2497
2958
  workspaceId: string,
2498
- subjectId: string,
2499
- request: UpdateWorkspaceMemberRequest,
2500
- ): Promise<WorkspaceMember> {
2501
- return await this.requestJson<WorkspaceMember>(
2502
- "PATCH",
2503
- `/v1/workspaces/${workspaceId}/members/${encodeURIComponent(subjectId)}`,
2959
+ browserSessionId: string,
2960
+ downloadId: string,
2961
+ request: BrowserDownloadSaveRequest,
2962
+ options: OpenGeniRequestOptions = {},
2963
+ ): Promise<BrowserDownloadSaveResponse> {
2964
+ return await this.requestJson<BrowserDownloadSaveResponse>(
2965
+ "POST",
2966
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/downloads/${encodeURIComponent(downloadId)}/save`,
2504
2967
  request,
2968
+ {},
2969
+ options,
2505
2970
  );
2506
2971
  }
2507
2972
 
2508
- /**
2509
- * Remove a member. Refused (409) for your own membership and for the last
2510
- * member who can still manage the workspace.
2511
- */
2512
- async removeWorkspaceMember(workspaceId: string, subjectId: string): Promise<void> {
2513
- await this.requestVoid(
2514
- "DELETE",
2515
- `/v1/workspaces/${workspaceId}/members/${encodeURIComponent(subjectId)}`,
2973
+ async createBrowserSession(
2974
+ workspaceId: string,
2975
+ request: CreateBrowserSessionRequest,
2976
+ options: OpenGeniRequestOptions = {},
2977
+ ): Promise<BrowserSessionMutationResponse> {
2978
+ return await this.requestJson<BrowserSessionMutationResponse>(
2979
+ "POST",
2980
+ `/v1/workspaces/${workspaceId}/browser-sessions`,
2981
+ request,
2982
+ {},
2983
+ options,
2516
2984
  );
2517
2985
  }
2518
2986
 
2519
- // --- Scheduled tasks (write + runs) -------------------------------------------
2987
+ async listBrowserTargets(
2988
+ workspaceId: string,
2989
+ browserSessionId: string,
2990
+ options: OpenGeniRequestOptions = {},
2991
+ ): Promise<BrowserTargetListResponse> {
2992
+ return await this.requestJson<BrowserTargetListResponse>(
2993
+ "GET",
2994
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/targets`,
2995
+ undefined,
2996
+ {},
2997
+ options,
2998
+ );
2999
+ }
2520
3000
 
2521
- async createScheduledTask(
3001
+ async openBrowserTarget(
2522
3002
  workspaceId: string,
2523
- request: CreateScheduledTaskRequest,
2524
- ): Promise<ScheduledTask> {
2525
- return await this.requestJson<ScheduledTask>(
3003
+ browserSessionId: string,
3004
+ request: BrowserOpenTargetRequest = {},
3005
+ options: OpenGeniRequestOptions = {},
3006
+ ): Promise<BrowserObservation> {
3007
+ return await this.requestJson<BrowserObservation>(
2526
3008
  "POST",
2527
- `/v1/workspaces/${workspaceId}/scheduled-tasks`,
3009
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/targets`,
2528
3010
  request,
3011
+ {},
3012
+ options,
2529
3013
  );
2530
3014
  }
2531
3015
 
2532
- async updateScheduledTask(
3016
+ async selectBrowserTarget(
2533
3017
  workspaceId: string,
2534
- taskId: string,
2535
- request: UpdateScheduledTaskRequest,
2536
- ): Promise<ScheduledTask> {
2537
- return await this.requestJson<ScheduledTask>(
2538
- "PATCH",
2539
- `/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}`,
2540
- request,
3018
+ browserSessionId: string,
3019
+ targetId: string,
3020
+ options: OpenGeniRequestOptions = {},
3021
+ ): Promise<BrowserObservation> {
3022
+ return await this.requestJson<BrowserObservation>(
3023
+ "POST",
3024
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/targets/${encodeURIComponent(targetId)}/select`,
3025
+ {},
3026
+ {},
3027
+ options,
2541
3028
  );
2542
3029
  }
2543
3030
 
2544
- async pauseScheduledTask(workspaceId: string, taskId: string): Promise<ScheduledTask> {
2545
- return await this.requestJson<ScheduledTask>(
2546
- "POST",
2547
- `/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}/pause`,
3031
+ async closeBrowserTarget(
3032
+ workspaceId: string,
3033
+ browserSessionId: string,
3034
+ targetId: string,
3035
+ options: OpenGeniRequestOptions = {},
3036
+ ): Promise<BrowserTargetListResponse> {
3037
+ return await this.requestJson<BrowserTargetListResponse>(
3038
+ "DELETE",
3039
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/targets/${encodeURIComponent(targetId)}`,
3040
+ undefined,
3041
+ {},
3042
+ options,
2548
3043
  );
2549
3044
  }
2550
3045
 
2551
- async resumeScheduledTask(workspaceId: string, taskId: string): Promise<ScheduledTask> {
2552
- return await this.requestJson<ScheduledTask>(
2553
- "POST",
2554
- `/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}/resume`,
3046
+ async observeBrowserTarget(
3047
+ workspaceId: string,
3048
+ browserSessionId: string,
3049
+ targetId: string,
3050
+ options: OpenGeniRequestOptions = {},
3051
+ ): Promise<BrowserObservation> {
3052
+ return await this.requestJson<BrowserObservation>(
3053
+ "GET",
3054
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/targets/${encodeURIComponent(targetId)}/observation`,
3055
+ undefined,
3056
+ {},
3057
+ options,
2555
3058
  );
2556
3059
  }
2557
3060
 
2558
- /**
2559
- * Fire the task immediately (manual trigger), independent of its schedule.
2560
- * Pass a stable `triggerId` to make a retried trigger idempotent — the same
2561
- * token charges once and starts one run. Omit it and each call is distinct.
2562
- */
2563
- async triggerScheduledTask(
3061
+ async actInBrowser(
2564
3062
  workspaceId: string,
2565
- taskId: string,
2566
- options: { triggerId?: string } = {},
2567
- ): Promise<ScheduledTask> {
2568
- return await this.requestJson<ScheduledTask>(
3063
+ browserSessionId: string,
3064
+ request: BrowserActionRequest,
3065
+ options: OpenGeniRequestOptions = {},
3066
+ ): Promise<BrowserActionReceipt> {
3067
+ return await this.requestJson<BrowserActionReceipt>(
2569
3068
  "POST",
2570
- `/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}/trigger`,
2571
- options.triggerId ? { triggerId: options.triggerId } : undefined,
3069
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/actions`,
3070
+ request,
3071
+ {},
3072
+ options,
2572
3073
  );
2573
3074
  }
2574
3075
 
2575
- async deleteScheduledTask(workspaceId: string, taskId: string): Promise<void> {
2576
- await this.requestJson<unknown>(
2577
- "DELETE",
2578
- `/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}`,
3076
+ async getBrowserActionReceipt(
3077
+ workspaceId: string,
3078
+ browserSessionId: string,
3079
+ operationId: string,
3080
+ options: OpenGeniRequestOptions = {},
3081
+ ): Promise<BrowserActionReceipt> {
3082
+ return await this.requestJson<BrowserActionReceipt>(
3083
+ "GET",
3084
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/operations/${encodeURIComponent(operationId)}`,
3085
+ undefined,
3086
+ {},
3087
+ options,
2579
3088
  );
2580
3089
  }
2581
3090
 
2582
- async listScheduledTaskRuns(
3091
+ async listBrowserDiagnostics(
2583
3092
  workspaceId: string,
2584
- taskId: string,
2585
- options: { limit?: number } = {},
2586
- ): Promise<ScheduledTaskRun[]> {
2587
- return await this.requestJson<ScheduledTaskRun[]>(
3093
+ browserSessionId: string,
3094
+ targetId: string,
3095
+ options: BrowserDiagnosticsOptions = {},
3096
+ ): Promise<BrowserDiagnosticBatch> {
3097
+ return await this.requestJson<BrowserDiagnosticBatch>(
2588
3098
  "GET",
2589
- `/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}/runs`,
3099
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/targets/${encodeURIComponent(targetId)}/diagnostics`,
2590
3100
  undefined,
2591
3101
  {
3102
+ ...(options.kinds?.length ? { kinds: options.kinds.join(",") } : {}),
3103
+ ...(options.after !== undefined ? { after: String(options.after) } : {}),
2592
3104
  ...(options.limit !== undefined ? { limit: String(options.limit) } : {}),
2593
3105
  },
3106
+ options.signal ? { signal: options.signal } : {},
2594
3107
  );
2595
3108
  }
2596
3109
 
2597
- // --- VariableSets --------------------------------------------------------------
2598
- // Generic reads return name/version metadata only. Plaintext uses one
2599
- // dedicated permissioned endpoint.
2600
-
2601
- async listVariableSets(workspaceId: string): Promise<VariableSet[]> {
2602
- return await this.requestJson<VariableSet[]>(
2603
- "GET",
2604
- `/v1/workspaces/${workspaceId}/variable-sets`,
2605
- );
2606
- }
2607
-
2608
- async createVariableSet(
3110
+ async attachBrowserSession(
2609
3111
  workspaceId: string,
2610
- request: CreateVariableSetRequest,
2611
- ): Promise<VariableSet> {
2612
- return await this.requestJson<VariableSet>(
3112
+ browserSessionId: string,
3113
+ request: BrowserSessionAttachmentRequest,
3114
+ options: OpenGeniRequestOptions = {},
3115
+ ): Promise<BrowserSessionAttachment> {
3116
+ return await this.requestJson<BrowserSessionAttachment>(
2613
3117
  "POST",
2614
- `/v1/workspaces/${workspaceId}/variable-sets`,
3118
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/attachments`,
2615
3119
  request,
3120
+ {},
3121
+ options,
2616
3122
  );
2617
3123
  }
2618
3124
 
2619
- async getVariableSet(workspaceId: string, variableSetId: string): Promise<VariableSet> {
2620
- return await this.requestJson<VariableSet>(
2621
- "GET",
2622
- `/v1/workspaces/${workspaceId}/variable-sets/${variableSetId}`,
3125
+ async heartbeatBrowserSession(
3126
+ workspaceId: string,
3127
+ browserSessionId: string,
3128
+ options: OpenGeniRequestOptions = {},
3129
+ ): Promise<BrowserSessionHeartbeatResponse> {
3130
+ return await this.requestJson<BrowserSessionHeartbeatResponse>(
3131
+ "POST",
3132
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/heartbeat`,
3133
+ {},
3134
+ {},
3135
+ options,
2623
3136
  );
2624
3137
  }
2625
3138
 
2626
- async getVariableSetVariable(
3139
+ async publishBrowserRevision(
2627
3140
  workspaceId: string,
2628
- variableSetId: string,
2629
- name: string,
2630
- ): Promise<VariableSetSecret> {
2631
- return await this.requestJson<VariableSetSecret>(
2632
- "GET",
2633
- `/v1/workspaces/${workspaceId}/variable-sets/${variableSetId}/variables/${encodeURIComponent(name)}`,
3141
+ browserSessionId: string,
3142
+ request: PublishBrowserRevisionRequest,
3143
+ options: OpenGeniRequestOptions = {},
3144
+ ): Promise<PublishBrowserRevisionResponse> {
3145
+ return await this.requestJson<PublishBrowserRevisionResponse>(
3146
+ "POST",
3147
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/revisions`,
3148
+ request,
3149
+ {},
3150
+ options,
2634
3151
  );
2635
3152
  }
2636
3153
 
2637
- async updateVariableSet(
3154
+ async suspendBrowserSession(
2638
3155
  workspaceId: string,
2639
- variableSetId: string,
2640
- request: UpdateVariableSetRequest,
2641
- ): Promise<VariableSet> {
2642
- return await this.requestJson<VariableSet>(
2643
- "PATCH",
2644
- `/v1/workspaces/${workspaceId}/variable-sets/${variableSetId}`,
3156
+ browserSessionId: string,
3157
+ request: BrowserSessionLifecycleRequest,
3158
+ options: OpenGeniRequestOptions = {},
3159
+ ): Promise<BrowserSessionMutationResponse> {
3160
+ return await this.requestJson<BrowserSessionMutationResponse>(
3161
+ "POST",
3162
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/suspend`,
2645
3163
  request,
3164
+ {},
3165
+ options,
2646
3166
  );
2647
3167
  }
2648
3168
 
2649
- async deleteVariableSet(workspaceId: string, variableSetId: string): Promise<void> {
2650
- await this.requestJson<unknown>(
2651
- "DELETE",
2652
- `/v1/workspaces/${workspaceId}/variable-sets/${variableSetId}`,
3169
+ async resumeBrowserSession(
3170
+ workspaceId: string,
3171
+ browserSessionId: string,
3172
+ request: BrowserSessionLifecycleRequest,
3173
+ options: OpenGeniRequestOptions = {},
3174
+ ): Promise<BrowserSessionMutationResponse> {
3175
+ return await this.requestJson<BrowserSessionMutationResponse>(
3176
+ "POST",
3177
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/resume`,
3178
+ request,
3179
+ {},
3180
+ options,
2653
3181
  );
2654
3182
  }
2655
3183
 
2656
- /** Create or rotate a variable. Generic reads never return its value. */
2657
- async setVariableSetVariable(
3184
+ async endBrowserSession(
2658
3185
  workspaceId: string,
2659
- variableSetId: string,
2660
- name: string,
2661
- value: string,
2662
- ): Promise<VariableSetVariableMetadata> {
2663
- return await this.requestJson<VariableSetVariableMetadata>(
2664
- "PUT",
2665
- `/v1/workspaces/${workspaceId}/variable-sets/${variableSetId}/variables/${encodeURIComponent(name)}`,
2666
- { value },
3186
+ browserSessionId: string,
3187
+ request: BrowserSessionLifecycleRequest,
3188
+ options: OpenGeniRequestOptions = {},
3189
+ ): Promise<BrowserSessionMutationResponse> {
3190
+ return await this.requestJson<BrowserSessionMutationResponse>(
3191
+ "POST",
3192
+ `/v1/workspaces/${workspaceId}/browser-sessions/${encodeURIComponent(browserSessionId)}/end`,
3193
+ request,
3194
+ {},
3195
+ options,
2667
3196
  );
2668
3197
  }
2669
3198
 
2670
- async deleteVariableSetVariable(
3199
+ /** Workspace-wide ComputerSession inventory. Associations express
3200
+ * relevance, not access; peer sessions intentionally remain discoverable. */
3201
+ async listComputerSessions(
2671
3202
  workspaceId: string,
2672
- variableSetId: string,
2673
- name: string,
2674
- ): Promise<void> {
2675
- await this.requestJson<unknown>(
2676
- "DELETE",
2677
- `/v1/workspaces/${workspaceId}/variable-sets/${variableSetId}/variables/${encodeURIComponent(name)}`,
3203
+ options: OpenGeniRequestOptions = {},
3204
+ ): Promise<ComputerSessionListResponse> {
3205
+ return await this.requestJson<ComputerSessionListResponse>(
3206
+ "GET",
3207
+ `/v1/workspaces/${workspaceId}/computer-sessions`,
3208
+ undefined,
3209
+ {},
3210
+ options,
2678
3211
  );
2679
3212
  }
2680
3213
 
2681
- // --- Rigs ------------------------------------------------------------------
2682
- // Workspace-scoped, versioned sandbox machine definitions. rigs:use gates read
2683
- // + proposeRigChange; rigs:manage gates create / update / delete / activate.
2684
-
2685
- async listRigs(workspaceId: string): Promise<Rig[]> {
2686
- return await this.requestJson<Rig[]>("GET", `/v1/workspaces/${workspaceId}/rigs`);
2687
- }
2688
-
2689
- async createRig(workspaceId: string, request: CreateRigRequest): Promise<Rig> {
2690
- return await this.requestJson<Rig>("POST", `/v1/workspaces/${workspaceId}/rigs`, request);
3214
+ async getComputerSession(
3215
+ workspaceId: string,
3216
+ computerSessionId: string,
3217
+ options: OpenGeniRequestOptions = {},
3218
+ ): Promise<ComputerSession> {
3219
+ return await this.requestJson<ComputerSession>(
3220
+ "GET",
3221
+ `/v1/workspaces/${workspaceId}/computer-sessions/${encodeURIComponent(computerSessionId)}`,
3222
+ undefined,
3223
+ {},
3224
+ options,
3225
+ );
2691
3226
  }
2692
3227
 
2693
- async getRig(workspaceId: string, rigId: string): Promise<Rig> {
2694
- return await this.requestJson<Rig>("GET", `/v1/workspaces/${workspaceId}/rigs/${rigId}`);
3228
+ async readComputerClipboard(
3229
+ workspaceId: string,
3230
+ computerSessionId: string,
3231
+ options: OpenGeniRequestOptions = {},
3232
+ ): Promise<ComputerClipboard> {
3233
+ return await this.requestJson<ComputerClipboard>(
3234
+ "GET",
3235
+ `/v1/workspaces/${workspaceId}/computer-sessions/${encodeURIComponent(computerSessionId)}/clipboard`,
3236
+ undefined,
3237
+ {},
3238
+ options,
3239
+ );
2695
3240
  }
2696
3241
 
2697
- async updateRig(workspaceId: string, rigId: string, request: UpdateRigRequest): Promise<Rig> {
2698
- return await this.requestJson<Rig>(
2699
- "PATCH",
2700
- `/v1/workspaces/${workspaceId}/rigs/${rigId}`,
3242
+ async createComputerSession(
3243
+ workspaceId: string,
3244
+ request: CreateComputerSessionRequest,
3245
+ options: OpenGeniRequestOptions = {},
3246
+ ): Promise<ComputerSessionMutationResponse> {
3247
+ return await this.requestJson<ComputerSessionMutationResponse>(
3248
+ "POST",
3249
+ `/v1/workspaces/${workspaceId}/computer-sessions`,
2701
3250
  request,
3251
+ {},
3252
+ options,
2702
3253
  );
2703
3254
  }
2704
3255
 
2705
- async deleteRig(workspaceId: string, rigId: string): Promise<void> {
2706
- await this.requestJson<unknown>("DELETE", `/v1/workspaces/${workspaceId}/rigs/${rigId}`);
3256
+ async listComputerTargets(
3257
+ workspaceId: string,
3258
+ computerSessionId: string,
3259
+ options: OpenGeniRequestOptions = {},
3260
+ ): Promise<ComputerTargetListResponse> {
3261
+ return await this.requestJson<ComputerTargetListResponse>(
3262
+ "GET",
3263
+ `/v1/workspaces/${workspaceId}/computer-sessions/${encodeURIComponent(computerSessionId)}/targets`,
3264
+ undefined,
3265
+ {},
3266
+ options,
3267
+ );
2707
3268
  }
2708
3269
 
2709
- async listRigVersions(workspaceId: string, rigId: string): Promise<RigVersion[]> {
2710
- return await this.requestJson<RigVersion[]>(
3270
+ async observeComputerTarget(
3271
+ workspaceId: string,
3272
+ computerSessionId: string,
3273
+ targetId: string,
3274
+ options: OpenGeniRequestOptions = {},
3275
+ ): Promise<ComputerObservation> {
3276
+ return await this.requestJson<ComputerObservation>(
2711
3277
  "GET",
2712
- `/v1/workspaces/${workspaceId}/rigs/${rigId}/versions`,
3278
+ `/v1/workspaces/${workspaceId}/computer-sessions/${encodeURIComponent(computerSessionId)}/targets/${encodeURIComponent(targetId)}/observation`,
3279
+ undefined,
3280
+ {},
3281
+ options,
2713
3282
  );
2714
3283
  }
2715
3284
 
2716
- /** Roll the active version to an existing one (rollback / promote-activate). */
2717
- async activateRigVersion(
3285
+ async actInComputer(
2718
3286
  workspaceId: string,
2719
- rigId: string,
2720
- versionId: string,
2721
- ): Promise<RigVersion> {
2722
- return await this.requestJson<RigVersion>(
3287
+ computerSessionId: string,
3288
+ request: ComputerActionRequest,
3289
+ options: OpenGeniRequestOptions = {},
3290
+ ): Promise<ComputerActionReceipt> {
3291
+ return await this.requestJson<ComputerActionReceipt>(
2723
3292
  "POST",
2724
- `/v1/workspaces/${workspaceId}/rigs/${rigId}/versions/${versionId}/activate`,
3293
+ `/v1/workspaces/${workspaceId}/computer-sessions/${encodeURIComponent(computerSessionId)}/actions`,
3294
+ request,
3295
+ {},
3296
+ options,
2725
3297
  );
2726
3298
  }
2727
3299
 
2728
- async listRigChanges(workspaceId: string, rigId: string): Promise<RigChange[]> {
2729
- return await this.requestJson<RigChange[]>(
3300
+ async getComputerActionReceipt(
3301
+ workspaceId: string,
3302
+ computerSessionId: string,
3303
+ operationId: string,
3304
+ options: OpenGeniRequestOptions = {},
3305
+ ): Promise<ComputerActionReceipt> {
3306
+ return await this.requestJson<ComputerActionReceipt>(
2730
3307
  "GET",
2731
- `/v1/workspaces/${workspaceId}/rigs/${rigId}/changes`,
3308
+ `/v1/workspaces/${workspaceId}/computer-sessions/${encodeURIComponent(computerSessionId)}/operations/${encodeURIComponent(operationId)}`,
3309
+ undefined,
3310
+ {},
3311
+ options,
2732
3312
  );
2733
3313
  }
2734
3314
 
2735
- /** Propose a change against the rig's active version (rigs:use). */
2736
- async proposeRigChange(
3315
+ async attachComputerSession(
2737
3316
  workspaceId: string,
2738
- rigId: string,
2739
- request: ProposeRigChangeRequest,
2740
- ): Promise<RigChange> {
2741
- return await this.requestJson<RigChange>(
3317
+ computerSessionId: string,
3318
+ request: ComputerSessionAttachmentRequest,
3319
+ options: OpenGeniRequestOptions = {},
3320
+ ): Promise<ComputerSessionAttachment> {
3321
+ return await this.requestJson<ComputerSessionAttachment>(
2742
3322
  "POST",
2743
- `/v1/workspaces/${workspaceId}/rigs/${rigId}/changes`,
3323
+ `/v1/workspaces/${workspaceId}/computer-sessions/${encodeURIComponent(computerSessionId)}/attachments`,
2744
3324
  request,
3325
+ {},
3326
+ options,
2745
3327
  );
2746
3328
  }
2747
3329
 
2748
- async getRigChange(workspaceId: string, rigId: string, changeId: string): Promise<RigChange> {
2749
- return await this.requestJson<RigChange>(
2750
- "GET",
2751
- `/v1/workspaces/${workspaceId}/rigs/${rigId}/changes/${changeId}`,
3330
+ async heartbeatComputerSession(
3331
+ workspaceId: string,
3332
+ computerSessionId: string,
3333
+ options: OpenGeniRequestOptions = {},
3334
+ ): Promise<ComputerSessionHeartbeatResponse> {
3335
+ return await this.requestJson<ComputerSessionHeartbeatResponse>(
3336
+ "POST",
3337
+ `/v1/workspaces/${workspaceId}/computer-sessions/${encodeURIComponent(computerSessionId)}/heartbeat`,
3338
+ {},
3339
+ {},
3340
+ options,
2752
3341
  );
2753
3342
  }
2754
3343
 
2755
- /**
2756
- * Re-run verification for a change (rigs:use). Verification is asynchronous:
2757
- * this returns the change immediately with status `verifying`; poll
2758
- * `getRigChange`/`listRigChanges` for the terminal outcome + logs.
2759
- */
2760
- async verifyRigChange(workspaceId: string, rigId: string, changeId: string): Promise<RigChange> {
2761
- return await this.requestJson<RigChange>(
3344
+ async endComputerSession(
3345
+ workspaceId: string,
3346
+ computerSessionId: string,
3347
+ request: ComputerSessionLifecycleRequest,
3348
+ options: OpenGeniRequestOptions = {},
3349
+ ): Promise<ComputerSessionMutationResponse> {
3350
+ return await this.requestJson<ComputerSessionMutationResponse>(
2762
3351
  "POST",
2763
- `/v1/workspaces/${workspaceId}/rigs/${rigId}/changes/${changeId}/verify`,
3352
+ `/v1/workspaces/${workspaceId}/computer-sessions/${encodeURIComponent(computerSessionId)}/end`,
3353
+ request,
3354
+ {},
3355
+ options,
2764
3356
  );
2765
3357
  }
2766
3358
 
3359
+ // --- Access + workspaces -----------------------------------------------------
3360
+
2767
3361
  /**
2768
- * Promote a verified `definition_edit` change into a new active rig version
2769
- * (rigs:manage). Only valid once the change's verification passed; returns the
2770
- * newly minted version.
3362
+ * The deployment's public client bootstrap config: the host-exposed models
3363
+ * (provider-grouped in `models`, flat in `allowedModels` for back-compat),
3364
+ * reasoning efforts, MCP servers, file-upload limits, and how the client is
3365
+ * expected to authenticate. Drives a composer's model picker without prior
3366
+ * knowledge of the host setup; safe to call before any auth is established.
2771
3367
  */
2772
- async promoteRigChange(
3368
+ async getClientConfig(): Promise<ClientConfig> {
3369
+ const config = await this.requestJson<ClientConfig>("GET", "/v1/config/client");
3370
+ if (config.apiContractRevision !== OPENGENI_API_CONTRACT_REVISION) {
3371
+ throw new OpenGeniApiContractMismatchError(
3372
+ OPENGENI_API_CONTRACT_REVISION,
3373
+ String(config.apiContractRevision || "(missing)"),
3374
+ );
3375
+ }
3376
+ return config;
3377
+ }
3378
+
3379
+ /** Authenticated model definitions plus workspace-specific selectability. */
3380
+ async getWorkspaceModelCatalog(workspaceId: string): Promise<WorkspaceModelCatalogResponse> {
3381
+ return await this.requestJson<WorkspaceModelCatalogResponse>(
3382
+ "GET",
3383
+ `/v1/workspaces/${workspaceId}/model-catalog`,
3384
+ );
3385
+ }
3386
+
3387
+ /** Authenticated realtime voice models and credential readiness. */
3388
+ async getWorkspaceRealtimeModelCatalog(
2773
3389
  workspaceId: string,
2774
- rigId: string,
2775
- changeId: string,
2776
- ): Promise<RigVersion> {
2777
- return await this.requestJson<RigVersion>(
2778
- "POST",
2779
- `/v1/workspaces/${workspaceId}/rigs/${rigId}/changes/${changeId}/promote`,
3390
+ ): Promise<WorkspaceRealtimeModelCatalogResponse> {
3391
+ return await this.requestJson<WorkspaceRealtimeModelCatalogResponse>(
3392
+ "GET",
3393
+ `/v1/workspaces/${workspaceId}/realtime-model-catalog`,
2780
3394
  );
2781
3395
  }
2782
3396
 
2783
- /**
2784
- * Re-run the active version's checks in a clean throwaway sandbox (rigs:use).
2785
- * Asynchronous returns the version id being verified; the outcome lands on
2786
- * the version's audit trail.
2787
- */
2788
- async verifyRig(workspaceId: string, rigId: string): Promise<{ ok: boolean; versionId: string }> {
2789
- return await this.requestJson<{ ok: boolean; versionId: string }>(
2790
- "POST",
2791
- `/v1/workspaces/${workspaceId}/rigs/${rigId}/verify`,
3397
+ /** The caller's access context: subject, account + workspace grants, defaults. */
3398
+ async getAccessContext(): Promise<AccessContext> {
3399
+ return await this.requestJson<AccessContext>("GET", "/v1/access/me");
3400
+ }
3401
+
3402
+ /** Active organization memberships proven by the current managed-human session. */
3403
+ async listOrganizationMemberships(): Promise<ListManagedOrganizationMembershipsResponse> {
3404
+ return await this.requestJson<ListManagedOrganizationMembershipsResponse>(
3405
+ "GET",
3406
+ "/v1/organization-memberships",
2792
3407
  );
2793
3408
  }
2794
3409
 
2795
- /** @deprecated use listVariableSets */
2796
- async listEnvironments(workspaceId: string): Promise<VariableSet[]> {
2797
- return await this.listVariableSets(workspaceId);
3410
+ async listWorkspaces(): Promise<Workspace[]> {
3411
+ return await this.requestJson<Workspace[]>("GET", "/v1/workspaces");
2798
3412
  }
2799
3413
 
2800
- /** @deprecated use createVariableSet */
2801
- async createEnvironment(
2802
- workspaceId: string,
2803
- request: CreateVariableSetRequest,
2804
- ): Promise<VariableSet> {
2805
- return await this.createVariableSet(workspaceId, request);
3414
+ async createWorkspace(request: CreateWorkspaceRequest): Promise<Workspace> {
3415
+ return await this.requestJson<Workspace>("POST", "/v1/workspaces", request);
2806
3416
  }
2807
3417
 
2808
- /** @deprecated use getVariableSet */
2809
- async getEnvironment(workspaceId: string, environmentId: string): Promise<VariableSet> {
2810
- return await this.getVariableSet(workspaceId, environmentId);
3418
+ async getWorkspace(workspaceId: string): Promise<Workspace> {
3419
+ return await this.requestJson<Workspace>("GET", `/v1/workspaces/${workspaceId}`);
2811
3420
  }
2812
3421
 
2813
- /** @deprecated use updateVariableSet */
2814
- async updateEnvironment(
3422
+ /** Read-time, secret-safe inventory of policy heads and visible workspace knowledge. */
3423
+ async getWorkspaceState(
2815
3424
  workspaceId: string,
2816
- environmentId: string,
2817
- request: UpdateVariableSetRequest,
2818
- ): Promise<VariableSet> {
2819
- return await this.updateVariableSet(workspaceId, environmentId, request);
3425
+ options: WorkspaceStateGetOptions = {},
3426
+ ): Promise<WorkspaceStateResponse> {
3427
+ const params = new URLSearchParams();
3428
+ if (options.attemptId) params.set("attemptId", options.attemptId);
3429
+ const query = params.size > 0 ? `?${params.toString()}` : "";
3430
+ return await this.requestJson<WorkspaceStateResponse>(
3431
+ "GET",
3432
+ `/v1/workspaces/${workspaceId}/workspace-state${query}`,
3433
+ );
2820
3434
  }
2821
3435
 
2822
- /** @deprecated use deleteVariableSet */
2823
- async deleteEnvironment(workspaceId: string, environmentId: string): Promise<void> {
2824
- await this.deleteVariableSet(workspaceId, environmentId);
3436
+ /** Download the canonical, explicitly sanitized Workspace State export. */
3437
+ async exportWorkspaceState(
3438
+ workspaceId: string,
3439
+ options: WorkspaceStateGetOptions = {},
3440
+ ): Promise<WorkspaceStateExportResponse> {
3441
+ const params = new URLSearchParams();
3442
+ if (options.attemptId) params.set("attemptId", options.attemptId);
3443
+ const query = params.size > 0 ? `?${params.toString()}` : "";
3444
+ return await this.requestJson<WorkspaceStateExportResponse>(
3445
+ "GET",
3446
+ `/v1/workspaces/${workspaceId}/workspace-state/export${query}`,
3447
+ );
2825
3448
  }
2826
3449
 
2827
- /** @deprecated use setVariableSetVariable */
2828
- async setEnvironmentVariable(
3450
+ async updateWorkspace(workspaceId: string, request: UpdateWorkspaceRequest): Promise<Workspace> {
3451
+ return await this.requestJson<Workspace>("PATCH", `/v1/workspaces/${workspaceId}`, request);
3452
+ }
3453
+
3454
+ /** Inspect immutable instruction-policy history, active heads, and activation audit evidence. */
3455
+ async listWorkspaceInstructionPolicies(
2829
3456
  workspaceId: string,
2830
- environmentId: string,
2831
- name: string,
2832
- value: string,
2833
- ): Promise<VariableSetVariableMetadata> {
2834
- return await this.setVariableSetVariable(workspaceId, environmentId, name, value);
3457
+ options: WorkspaceInstructionPolicyListOptions = {},
3458
+ ): Promise<WorkspaceInstructionPolicyListResponse> {
3459
+ const params = new URLSearchParams();
3460
+ if (options.kind !== undefined) params.set("kind", options.kind);
3461
+ if (options.scope !== undefined) params.set("scope", options.scope);
3462
+ if (options.roleKey !== undefined) params.set("roleKey", options.roleKey);
3463
+ if (options.afterRevision !== undefined) {
3464
+ params.set("afterRevision", String(options.afterRevision));
3465
+ }
3466
+ if (options.limit !== undefined) params.set("limit", String(options.limit));
3467
+ const query = params.toString();
3468
+ return await this.requestJson<WorkspaceInstructionPolicyListResponse>(
3469
+ "GET",
3470
+ `/v1/workspaces/${workspaceId}/instruction-policies${query ? `?${query}` : ""}`,
3471
+ );
2835
3472
  }
2836
3473
 
2837
- /** @deprecated use deleteVariableSetVariable */
2838
- async deleteEnvironmentVariable(
3474
+ async getWorkspaceInstructionPolicyRevision(
2839
3475
  workspaceId: string,
2840
- environmentId: string,
2841
- name: string,
2842
- ): Promise<void> {
2843
- await this.deleteVariableSetVariable(workspaceId, environmentId, name);
3476
+ revisionId: string,
3477
+ ): Promise<WorkspaceInstructionPolicyRevision> {
3478
+ return await this.requestJson<WorkspaceInstructionPolicyRevision>(
3479
+ "GET",
3480
+ `/v1/workspaces/${workspaceId}/instruction-policies/${encodeURIComponent(revisionId)}`,
3481
+ );
2844
3482
  }
2845
3483
 
2846
- // --- Files -----------------------------------------------------------------------
3484
+ async createWorkspaceInstructionPolicyDraft(
3485
+ workspaceId: string,
3486
+ request: CreateWorkspaceInstructionPolicyDraftRequest,
3487
+ ): Promise<WorkspaceInstructionPolicyRevision> {
3488
+ return await this.requestJson<WorkspaceInstructionPolicyRevision>(
3489
+ "POST",
3490
+ `/v1/workspaces/${workspaceId}/instruction-policies/drafts`,
3491
+ request,
3492
+ );
3493
+ }
2847
3494
 
2848
- /** Step 1 of the upload flow: returns the pre-signed PUT target. */
2849
- async beginFileUpload(
3495
+ /** List the newest immutable onboarding proposals and their inactive policy drafts. */
3496
+ async listWorkspaceInstructionPolicyOnboardingProposals(
2850
3497
  workspaceId: string,
2851
- request: CreateFileUploadRequest,
2852
- options: OpenGeniRequestOptions = {},
2853
- ): Promise<CreateFileUploadResponse> {
2854
- return await this.requestJson<CreateFileUploadResponse>(
3498
+ options: WorkspaceInstructionPolicyOnboardingProposalListOptions = {},
3499
+ ): Promise<WorkspaceInstructionPolicyOnboardingProposalListResponse> {
3500
+ const params = new URLSearchParams();
3501
+ if (options.limit !== undefined) params.set("limit", String(options.limit));
3502
+ const query = params.toString();
3503
+ return await this.requestJson<WorkspaceInstructionPolicyOnboardingProposalListResponse>(
3504
+ "GET",
3505
+ `/v1/workspaces/${workspaceId}/instruction-policies/onboarding-proposals${query ? `?${query}` : ""}`,
3506
+ );
3507
+ }
3508
+
3509
+ /** Create one draft-only proposal against an exact active-policy baseline. */
3510
+ async createWorkspaceInstructionPolicyOnboardingProposal(
3511
+ workspaceId: string,
3512
+ request: CreateWorkspaceInstructionPolicyOnboardingProposalRequest,
3513
+ ): Promise<WorkspaceInstructionPolicyOnboardingProposal> {
3514
+ return await this.requestJson<WorkspaceInstructionPolicyOnboardingProposal>(
2855
3515
  "POST",
2856
- `/v1/workspaces/${workspaceId}/files/uploads`,
3516
+ `/v1/workspaces/${workspaceId}/instruction-policies/onboarding-proposals`,
2857
3517
  request,
2858
- {},
2859
- options,
2860
3518
  );
2861
3519
  }
2862
3520
 
2863
- /** Step 3 of the upload flow: server verifies the object and marks it ready. */
2864
- async completeFileUpload(
3521
+ /** Import the stored legacy workspace override as an inactive charter draft. */
3522
+ async importLegacyWorkspaceInstructionPolicyDraft(
2865
3523
  workspaceId: string,
2866
- uploadId: string,
2867
- options: OpenGeniRequestOptions = {},
2868
- ): Promise<FileAsset> {
2869
- const response = await this.requestJson<CompleteFileUploadResponse>(
3524
+ request: ImportLegacyWorkspaceInstructionPolicyDraftRequest = {},
3525
+ ): Promise<WorkspaceInstructionPolicyRevision> {
3526
+ return await this.requestJson<WorkspaceInstructionPolicyRevision>(
2870
3527
  "POST",
2871
- `/v1/workspaces/${workspaceId}/files/uploads/${uploadId}/complete`,
2872
- undefined,
2873
- {},
2874
- options,
3528
+ `/v1/workspaces/${workspaceId}/instruction-policies/import-legacy`,
3529
+ request,
2875
3530
  );
2876
- return response.file;
2877
3531
  }
2878
3532
 
2879
- /**
2880
- * The whole upload flow as one call: begin -> PUT the bytes to the signed
2881
- * URL (with its required headers; no API auth is sent to object storage)
2882
- * -> complete. Returns the ready `FileAsset`.
2883
- */
2884
- async uploadFile(workspaceId: string, input: UploadFileInput): Promise<FileAsset> {
2885
- if (
2886
- input.timeoutMs !== undefined &&
2887
- (!Number.isFinite(input.timeoutMs) || input.timeoutMs <= 0)
2888
- ) {
2889
- throw new Error("File upload timeout must be a positive number");
2890
- }
2891
- const withTimeout = async <T>(
2892
- timeoutMs: number,
2893
- operation: (signal: AbortSignal) => Promise<T>,
2894
- ): Promise<T> => {
2895
- const controller = new AbortController();
2896
- let timeout: ReturnType<typeof setTimeout> | undefined;
2897
- const timedOut = new Promise<never>((_resolve, reject) => {
2898
- timeout = setTimeout(() => {
2899
- controller.abort();
2900
- reject(new Error("File upload timed out. Retry the upload."));
2901
- }, timeoutMs);
2902
- });
2903
- try {
2904
- return await Promise.race([operation(controller.signal), timedOut]);
2905
- } finally {
2906
- if (timeout !== undefined) clearTimeout(timeout);
2907
- }
2908
- };
2909
- // Snapshot mutable inputs before hashing so the digest always describes the
2910
- // exact bytes later sent to object storage. Copy Uint8Array views into a
2911
- // Blob so byte offsets/shared buffers can't leak surrounding bytes.
2912
- const body: Blob | ArrayBuffer | string =
2913
- input.data instanceof Uint8Array
2914
- ? new Blob([input.data.slice()])
2915
- : input.data instanceof ArrayBuffer
2916
- ? input.data.slice(0)
2917
- : input.data;
2918
- const sizeBytes =
2919
- typeof body === "string"
2920
- ? new TextEncoder().encode(body).byteLength
2921
- : body instanceof Blob
2922
- ? body.size
2923
- : body.byteLength;
2924
- const sha256 = input.sha256 ?? (await sha256ForUpload(body));
2925
- const upload = await withTimeout(
2926
- 30_000,
2927
- async (signal) =>
2928
- await this.beginFileUpload(
2929
- workspaceId,
2930
- {
2931
- filename: input.filename,
2932
- contentType: input.contentType,
2933
- sizeBytes,
2934
- sha256,
2935
- },
2936
- { signal },
2937
- ),
3533
+ async diffWorkspaceInstructionPolicyRevisions(
3534
+ workspaceId: string,
3535
+ request: WorkspaceInstructionPolicyDiffRequest,
3536
+ ): Promise<WorkspaceInstructionPolicyDiffResponse> {
3537
+ const params = new URLSearchParams({
3538
+ fromRevisionId: request.fromRevisionId,
3539
+ toRevisionId: request.toRevisionId,
3540
+ });
3541
+ return await this.requestJson<WorkspaceInstructionPolicyDiffResponse>(
3542
+ "GET",
3543
+ `/v1/workspaces/${workspaceId}/instruction-policies/diff?${params}`,
2938
3544
  );
2939
- // Give large valid uploads enough time at a conservative 256 KiB/s while
2940
- // still bounding an object-storage request that never settles.
2941
- const transferTimeoutMs =
2942
- input.timeoutMs ?? Math.max(120_000, Math.ceil(sizeBytes / (256 * 1024)) * 1_000);
2943
- const putResponse = await withTimeout(
2944
- transferTimeoutMs,
2945
- async (signal) =>
2946
- await this.fetchImpl(upload.putUrl, {
2947
- method: "PUT",
2948
- // Signed object-storage URLs carry their own short-lived authority.
2949
- // Browser cookies and HTTP auth must never accompany this cross-origin
2950
- // request: credentialed fetches are incompatible with wildcard CORS and
2951
- // can leak ambient credentials to a caller-selected storage endpoint.
2952
- credentials: "omit",
2953
- // The backend's requiredHeaders already carry the canonical lowercase
2954
- // `content-type` for every storage backend (Azure/S3/GCS). Do NOT also set
2955
- // a `Content-Type` key here: WHATWG Headers treats the two casings as the
2956
- // same header and comma-joins their values (e.g. "text/plain, text/plain"),
2957
- // which the object store persists verbatim and COMPLETE then rejects (422),
2958
- // and which breaks S3's presigned-URL signature.
2959
- headers: { ...upload.requiredHeaders },
2960
- body,
2961
- signal,
2962
- }),
3545
+ }
3546
+
3547
+ async activateWorkspaceInstructionPolicyRevision(
3548
+ workspaceId: string,
3549
+ revisionId: string,
3550
+ request: ActivateWorkspaceInstructionPolicyRequest,
3551
+ ): Promise<WorkspaceInstructionPolicyActivationResponse> {
3552
+ return await this.requestJson<WorkspaceInstructionPolicyActivationResponse>(
3553
+ "POST",
3554
+ `/v1/workspaces/${workspaceId}/instruction-policies/${encodeURIComponent(revisionId)}/activate`,
3555
+ request,
2963
3556
  );
2964
- if (!putResponse.ok) {
2965
- throw await apiErrorFromResponse(putResponse, { method: "PUT" });
2966
- }
2967
- return await withTimeout(
2968
- 30_000,
2969
- async (signal) => await this.completeFileUpload(workspaceId, upload.uploadId, { signal }),
3557
+ }
3558
+
3559
+ async rollbackWorkspaceInstructionPolicyRevision(
3560
+ workspaceId: string,
3561
+ request: RollbackWorkspaceInstructionPolicyRequest,
3562
+ ): Promise<WorkspaceInstructionPolicyActivationResponse> {
3563
+ return await this.requestJson<WorkspaceInstructionPolicyActivationResponse>(
3564
+ "POST",
3565
+ `/v1/workspaces/${workspaceId}/instruction-policies/rollback`,
3566
+ request,
2970
3567
  );
2971
3568
  }
2972
3569
 
2973
- async getFile(workspaceId: string, fileId: string): Promise<FileAsset> {
2974
- return await this.requestJson<FileAsset>(
3570
+ /** Read the current organization profile plus immutable revision and activation history. */
3571
+ async listCompanyProfile(
3572
+ workspaceId: string,
3573
+ options: CompanyProfileListOptions = {},
3574
+ ): Promise<CompanyProfileListResponse> {
3575
+ const params = new URLSearchParams();
3576
+ if (options.afterRevision !== undefined)
3577
+ params.set("afterRevision", String(options.afterRevision));
3578
+ if (options.limit !== undefined) params.set("limit", String(options.limit));
3579
+ const query = params.toString();
3580
+ return await this.requestJson<CompanyProfileListResponse>(
2975
3581
  "GET",
2976
- `/v1/workspaces/${workspaceId}/files/${fileId}`,
3582
+ `/v1/workspaces/${workspaceId}/company-profile${query ? `?${query}` : ""}`,
2977
3583
  );
2978
3584
  }
2979
3585
 
2980
- /** Read provider-neutral retained evidence metadata; never returns a storage location. */
2981
- async getRetainedArtifact(
3586
+ async getCompanyProfileRevision(
2982
3587
  workspaceId: string,
2983
- artifactId: string,
2984
- ): Promise<RetainedArtifactMetadata> {
2985
- return await this.requestJson<RetainedArtifactMetadata>(
3588
+ revisionId: string,
3589
+ ): Promise<CompanyProfileRevision> {
3590
+ return await this.requestJson<CompanyProfileRevision>(
2986
3591
  "GET",
2987
- `/v1/workspaces/${workspaceId}/artifacts/${artifactId}`,
3592
+ `/v1/workspaces/${workspaceId}/company-profile/revisions/${encodeURIComponent(revisionId)}`,
2988
3593
  );
2989
3594
  }
2990
3595
 
2991
- /**
2992
- * Read at most one authenticated retained-evidence range from the API. This
2993
- * deliberately does not use the ordinary signed file-download URL.
2994
- */
2995
- async getRetainedArtifactContent(
3596
+ async updateCompanyProfile(
2996
3597
  workspaceId: string,
2997
- artifactId: string,
2998
- options: RetainedArtifactContentOptions = {},
2999
- ): Promise<RetainedArtifactContent> {
3000
- return await this.getRetainedArtifactContentAtPath(
3001
- `/v1/workspaces/${workspaceId}/artifacts/${artifactId}/content`,
3002
- options,
3598
+ request: UpdateCompanyProfileRequest,
3599
+ ): Promise<CompanyProfileMutationResponse> {
3600
+ return await this.requestJson<CompanyProfileMutationResponse>(
3601
+ "PUT",
3602
+ `/v1/workspaces/${workspaceId}/company-profile`,
3603
+ request,
3003
3604
  );
3004
3605
  }
3005
3606
 
3006
- async getSessionRetainedArtifact(
3607
+ async diffCompanyProfileRevisions(
3007
3608
  workspaceId: string,
3008
- sessionId: string,
3009
- artifactId: string,
3010
- ): Promise<RetainedArtifactMetadata> {
3011
- return await this.requestJson<RetainedArtifactMetadata>(
3609
+ request: CompanyProfileDiffRequest,
3610
+ ): Promise<CompanyProfileDiffResponse> {
3611
+ const params = new URLSearchParams(request);
3612
+ return await this.requestJson<CompanyProfileDiffResponse>(
3012
3613
  "GET",
3013
- `/v1/workspaces/${workspaceId}/sessions/${sessionId}/artifacts/${artifactId}`,
3614
+ `/v1/workspaces/${workspaceId}/company-profile/diff?${params}`,
3014
3615
  );
3015
3616
  }
3016
3617
 
3017
- async getSessionRetainedArtifactContent(
3618
+ async activateCompanyProfileRevision(
3018
3619
  workspaceId: string,
3019
- sessionId: string,
3020
- artifactId: string,
3021
- options: RetainedArtifactContentOptions = {},
3022
- ): Promise<RetainedArtifactContent> {
3023
- return await this.getRetainedArtifactContentAtPath(
3024
- `/v1/workspaces/${workspaceId}/sessions/${sessionId}/artifacts/${artifactId}/content`,
3025
- options,
3620
+ revisionId: string,
3621
+ request: ActivateCompanyProfileRevisionRequest,
3622
+ ): Promise<CompanyProfileMutationResponse> {
3623
+ return await this.requestJson<CompanyProfileMutationResponse>(
3624
+ "POST",
3625
+ `/v1/workspaces/${workspaceId}/company-profile/revisions/${encodeURIComponent(revisionId)}/activate`,
3626
+ request,
3026
3627
  );
3027
3628
  }
3028
3629
 
3029
- /** Assemble one retained screenshot from bounded authenticated API ranges. */
3030
- async downloadRetainedScreenshot(
3630
+ async rollbackCompanyProfile(
3031
3631
  workspaceId: string,
3032
- sessionId: string,
3033
- artifactId: string,
3034
- options: RetainedScreenshotDownloadOptions = {},
3035
- ): Promise<RetainedScreenshotDownload> {
3036
- const maxRetries = options.maxRetries ?? 2;
3037
- if (!Number.isInteger(maxRetries) || maxRetries < 0 || maxRetries > 3) {
3038
- throw new RangeError("retained screenshot maxRetries must be an integer from 0 to 3");
3039
- }
3040
- const metadata = await this.getSessionRetainedArtifact(workspaceId, sessionId, artifactId);
3041
- if (!metadata.available) return { metadata, bytes: null };
3042
- if (
3043
- metadata.kind !== "computer_screenshot" ||
3044
- metadata.contentType !== "image/png" ||
3045
- !metadata.dimensions ||
3046
- metadata.originalBytes <= 0 ||
3047
- metadata.originalBytes > COMPUTER_SCREENSHOT_MAX_BYTES
3048
- ) {
3049
- throw new OpenGeniApiError(502, "retained screenshot metadata is invalid");
3050
- }
3051
- const bytes = new Uint8Array(metadata.originalBytes);
3052
- const pageBytes = Math.min(metadata.retrieval.maxRangeBytes, RETAINED_OUTPUT_MAX_PAGE_BYTES);
3053
- if (!Number.isSafeInteger(pageBytes) || pageBytes <= 0) {
3054
- throw new OpenGeniApiError(502, "retained screenshot range metadata is invalid");
3055
- }
3056
- for (let start = 0; start < bytes.byteLength; start += pageBytes) {
3057
- options.signal?.throwIfAborted();
3058
- const end = Math.min(start + pageBytes, bytes.byteLength) - 1;
3059
- let page: RetainedArtifactContent | null = null;
3060
- for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
3061
- try {
3062
- page = await this.getSessionRetainedArtifactContent(workspaceId, sessionId, artifactId, {
3063
- range: `bytes=${start}-${end}`,
3064
- ...(options.signal ? { signal: options.signal } : {}),
3065
- });
3066
- break;
3067
- } catch (error) {
3068
- options.signal?.throwIfAborted();
3069
- if (
3070
- attempt >= maxRetries ||
3071
- (error instanceof OpenGeniApiError && error.status >= 400 && error.status < 500)
3072
- ) {
3073
- throw error;
3074
- }
3075
- }
3076
- }
3077
- if (!page) throw new OpenGeniApiError(502, "retained screenshot range retry exhausted");
3078
- const expectedLength = end - start + 1;
3079
- if (
3080
- page.status !== 206 ||
3081
- page.contentType !== metadata.contentType ||
3082
- page.contentLength !== expectedLength ||
3083
- page.contentRange !== `bytes ${start}-${end}/${metadata.originalBytes}`
3084
- ) {
3085
- throw new OpenGeniApiError(502, "retained screenshot range response is invalid");
3086
- }
3087
- bytes.set(page.bytes, start);
3088
- }
3089
- if ((await sha256Hex(bytes)) !== metadata.sha256) {
3090
- throw new OpenGeniApiError(502, "retained screenshot checksum mismatch");
3091
- }
3092
- return { metadata, bytes };
3632
+ request: RollbackCompanyProfileRequest,
3633
+ ): Promise<CompanyProfileMutationResponse> {
3634
+ return await this.requestJson<CompanyProfileMutationResponse>(
3635
+ "POST",
3636
+ `/v1/workspaces/${workspaceId}/company-profile/rollback`,
3637
+ request,
3638
+ );
3639
+ }
3640
+
3641
+ async listPreferenceRegistry(
3642
+ workspaceId: string,
3643
+ options: PreferenceRegistryListOptions = {},
3644
+ ): Promise<PreferenceRegistryListResponse> {
3645
+ const params = new URLSearchParams();
3646
+ if (options.scope) params.set("scope", options.scope);
3647
+ if (options.status) params.set("status", options.status);
3648
+ if (options.limit !== undefined) params.set("limit", String(options.limit));
3649
+ const query = params.toString();
3650
+ return await this.requestJson<PreferenceRegistryListResponse>(
3651
+ "GET",
3652
+ `/v1/workspaces/${workspaceId}/preferences${query ? `?${query}` : ""}`,
3653
+ );
3654
+ }
3655
+
3656
+ async getPreferenceRegistry(
3657
+ workspaceId: string,
3658
+ preferenceId: string,
3659
+ ): Promise<PreferenceRegistryDetailResponse> {
3660
+ return await this.requestJson<PreferenceRegistryDetailResponse>(
3661
+ "GET",
3662
+ `/v1/workspaces/${workspaceId}/preferences/${encodeURIComponent(preferenceId)}`,
3663
+ );
3664
+ }
3665
+
3666
+ async createPreferenceRegistryProposal(
3667
+ workspaceId: string,
3668
+ request: CreatePreferenceRegistryProposalRequest,
3669
+ ): Promise<PreferenceRegistryRecord> {
3670
+ return await this.requestJson<PreferenceRegistryRecord>(
3671
+ "POST",
3672
+ `/v1/workspaces/${workspaceId}/preferences/proposals`,
3673
+ request,
3674
+ );
3675
+ }
3676
+
3677
+ async activatePreferenceRegistryRevision(
3678
+ workspaceId: string,
3679
+ preferenceId: string,
3680
+ request: ActivatePreferenceRegistryRevisionRequest,
3681
+ ): Promise<PreferenceRegistryMutationResponse> {
3682
+ return await this.requestJson<PreferenceRegistryMutationResponse>(
3683
+ "POST",
3684
+ `/v1/workspaces/${workspaceId}/preferences/${encodeURIComponent(preferenceId)}/activate`,
3685
+ request,
3686
+ );
3687
+ }
3688
+
3689
+ async correctPreferenceRegistry(
3690
+ workspaceId: string,
3691
+ preferenceId: string,
3692
+ request: CorrectPreferenceRegistryRequest,
3693
+ ): Promise<PreferenceRegistryMutationResponse> {
3694
+ return await this.requestJson<PreferenceRegistryMutationResponse>(
3695
+ "POST",
3696
+ `/v1/workspaces/${workspaceId}/preferences/${encodeURIComponent(preferenceId)}/correct`,
3697
+ request,
3698
+ );
3699
+ }
3700
+
3701
+ async changePreferenceRegistryScope(
3702
+ workspaceId: string,
3703
+ preferenceId: string,
3704
+ request: ChangePreferenceRegistryScopeRequest,
3705
+ ): Promise<PreferenceRegistryMutationResponse> {
3706
+ return await this.requestJson<PreferenceRegistryMutationResponse>(
3707
+ "POST",
3708
+ `/v1/workspaces/${workspaceId}/preferences/${encodeURIComponent(preferenceId)}/scope`,
3709
+ request,
3710
+ );
3711
+ }
3712
+
3713
+ async deactivatePreferenceRegistry(
3714
+ workspaceId: string,
3715
+ preferenceId: string,
3716
+ request: DeactivatePreferenceRegistryRequest,
3717
+ ): Promise<PreferenceRegistryMutationResponse> {
3718
+ return await this.requestJson<PreferenceRegistryMutationResponse>(
3719
+ "POST",
3720
+ `/v1/workspaces/${workspaceId}/preferences/${encodeURIComponent(preferenceId)}/deactivate`,
3721
+ request,
3722
+ );
3723
+ }
3724
+
3725
+ async supersedePreferenceRegistry(
3726
+ workspaceId: string,
3727
+ preferenceId: string,
3728
+ request: SupersedePreferenceRegistryRequest,
3729
+ ): Promise<PreferenceRegistryMutationResponse> {
3730
+ return await this.requestJson<PreferenceRegistryMutationResponse>(
3731
+ "POST",
3732
+ `/v1/workspaces/${workspaceId}/preferences/${encodeURIComponent(preferenceId)}/supersede`,
3733
+ request,
3734
+ );
3735
+ }
3736
+
3737
+ async rejectPreferenceRegistryProposal(
3738
+ workspaceId: string,
3739
+ preferenceId: string,
3740
+ request: RejectPreferenceRegistryProposalRequest,
3741
+ ): Promise<PreferenceRegistryMutationResponse> {
3742
+ return await this.requestJson<PreferenceRegistryMutationResponse>(
3743
+ "POST",
3744
+ `/v1/workspaces/${workspaceId}/preferences/${encodeURIComponent(preferenceId)}/reject`,
3745
+ request,
3746
+ );
3747
+ }
3748
+
3749
+ async getPreferenceRegistrySummary(workspaceId: string): Promise<PreferenceRegistrySnapshot> {
3750
+ return await this.requestJson<PreferenceRegistrySnapshot>(
3751
+ "GET",
3752
+ `/v1/workspaces/${workspaceId}/preferences/summary`,
3753
+ );
3754
+ }
3755
+
3756
+ async getPreferenceRegistryFullContent(
3757
+ workspaceId: string,
3758
+ retrievalHandle: string,
3759
+ ): Promise<PreferenceRegistryFullContent> {
3760
+ return await this.requestJson<PreferenceRegistryFullContent>(
3761
+ "POST",
3762
+ `/v1/workspaces/${workspaceId}/preferences/full-content`,
3763
+ { retrievalHandle },
3764
+ );
3765
+ }
3766
+
3767
+ /**
3768
+ * Delete a workspace and everything in it. Refused (409) for the account's
3769
+ * only workspace and while it still has a running session. Irreversible.
3770
+ */
3771
+ async deleteWorkspace(workspaceId: string): Promise<void> {
3772
+ await this.requestVoid("DELETE", `/v1/workspaces/${workspaceId}`);
3773
+ }
3774
+
3775
+ // --- Members ("People with access") -------------------------------------------
3776
+
3777
+ /** The workspace's members (user + api_key subjects). */
3778
+ async listWorkspaceMembers(workspaceId: string): Promise<WorkspaceMember[]> {
3779
+ const response = await this.requestJson<ListWorkspaceMembersResponse>(
3780
+ "GET",
3781
+ `/v1/workspaces/${workspaceId}/members`,
3782
+ );
3783
+ return response.members;
3784
+ }
3785
+
3786
+ /**
3787
+ * Add an already-registered user by email. 404s when no user with that email
3788
+ * exists (email invites for unknown users are deferred).
3789
+ */
3790
+ async addWorkspaceMember(
3791
+ workspaceId: string,
3792
+ request: AddWorkspaceMemberRequest,
3793
+ ): Promise<WorkspaceMember> {
3794
+ return await this.requestJson<WorkspaceMember>(
3795
+ "POST",
3796
+ `/v1/workspaces/${workspaceId}/members`,
3797
+ request,
3798
+ );
3799
+ }
3800
+
3801
+ async updateWorkspaceMember(
3802
+ workspaceId: string,
3803
+ subjectId: string,
3804
+ request: UpdateWorkspaceMemberRequest,
3805
+ ): Promise<WorkspaceMember> {
3806
+ return await this.requestJson<WorkspaceMember>(
3807
+ "PATCH",
3808
+ `/v1/workspaces/${workspaceId}/members/${encodeURIComponent(subjectId)}`,
3809
+ request,
3810
+ );
3811
+ }
3812
+
3813
+ /**
3814
+ * Remove a member. Refused (409) for your own membership and for the last
3815
+ * member who can still manage the workspace.
3816
+ */
3817
+ async removeWorkspaceMember(workspaceId: string, subjectId: string): Promise<void> {
3818
+ await this.requestVoid(
3819
+ "DELETE",
3820
+ `/v1/workspaces/${workspaceId}/members/${encodeURIComponent(subjectId)}`,
3821
+ );
3822
+ }
3823
+
3824
+ /** Exchange one signed Slack bearer for durable, token-free continuation state. */
3825
+ async prepareSlackUserLinkAccess(
3826
+ workspaceId: string,
3827
+ request: PrepareSlackUserLinkAccessRequest,
3828
+ ): Promise<SlackUserLinkAccessRequest> {
3829
+ return await this.requestJson<SlackUserLinkAccessRequest>(
3830
+ "POST",
3831
+ `/v1/workspaces/${workspaceId}/integrations/slack/user-link-intents`,
3832
+ request,
3833
+ );
3834
+ }
3835
+
3836
+ async getSlackUserLinkAccess(
3837
+ workspaceId: string,
3838
+ requestId: string,
3839
+ ): Promise<SlackUserLinkAccessRequest> {
3840
+ return await this.requestJson<SlackUserLinkAccessRequest>(
3841
+ "GET",
3842
+ `/v1/workspaces/${workspaceId}/integrations/slack/user-link-intents/${requestId}`,
3843
+ );
3844
+ }
3845
+
3846
+ async requestSlackUserLinkWorkspaceAccess(
3847
+ workspaceId: string,
3848
+ requestId: string,
3849
+ request: SlackUserLinkAccessMutationRequest,
3850
+ ): Promise<SlackUserLinkAccessRequest> {
3851
+ return await this.requestJson<SlackUserLinkAccessRequest>(
3852
+ "POST",
3853
+ `/v1/workspaces/${workspaceId}/integrations/slack/user-link-intents/${requestId}/request-access`,
3854
+ request,
3855
+ );
3856
+ }
3857
+
3858
+ async cancelSlackUserLinkAccess(
3859
+ workspaceId: string,
3860
+ requestId: string,
3861
+ request: SlackUserLinkAccessMutationRequest,
3862
+ ): Promise<SlackUserLinkAccessRequest> {
3863
+ return await this.requestJson<SlackUserLinkAccessRequest>(
3864
+ "POST",
3865
+ `/v1/workspaces/${workspaceId}/integrations/slack/user-link-intents/${requestId}/cancel`,
3866
+ request,
3867
+ );
3868
+ }
3869
+
3870
+ async listSlackUserLinkAccessRequests(
3871
+ workspaceId: string,
3872
+ ): Promise<SlackUserLinkAccessRequest[]> {
3873
+ const response = await this.requestJson<ListSlackUserLinkAccessRequestsResponse>(
3874
+ "GET",
3875
+ `/v1/workspaces/${workspaceId}/members/access-requests/slack`,
3876
+ );
3877
+ return response.requests;
3878
+ }
3879
+
3880
+ async approveSlackUserLinkAccessRequest(
3881
+ workspaceId: string,
3882
+ requestId: string,
3883
+ request: ApproveSlackUserLinkAccessRequest,
3884
+ ): Promise<SlackUserLinkAccessRequest> {
3885
+ return await this.requestJson<SlackUserLinkAccessRequest>(
3886
+ "POST",
3887
+ `/v1/workspaces/${workspaceId}/members/access-requests/slack/${requestId}/approve`,
3888
+ request,
3889
+ );
3890
+ }
3891
+
3892
+ async denySlackUserLinkAccessRequest(
3893
+ workspaceId: string,
3894
+ requestId: string,
3895
+ request: SlackUserLinkAccessMutationRequest,
3896
+ ): Promise<SlackUserLinkAccessRequest> {
3897
+ return await this.requestJson<SlackUserLinkAccessRequest>(
3898
+ "POST",
3899
+ `/v1/workspaces/${workspaceId}/members/access-requests/slack/${requestId}/deny`,
3900
+ request,
3901
+ );
3902
+ }
3903
+
3904
+ // --- Scheduled tasks (write + runs) -------------------------------------------
3905
+
3906
+ async createScheduledTask(
3907
+ workspaceId: string,
3908
+ request: CreateScheduledTaskRequest,
3909
+ ): Promise<ScheduledTask> {
3910
+ return await this.requestJson<ScheduledTask>(
3911
+ "POST",
3912
+ `/v1/workspaces/${workspaceId}/scheduled-tasks`,
3913
+ request,
3914
+ );
3915
+ }
3916
+
3917
+ async updateScheduledTask(
3918
+ workspaceId: string,
3919
+ taskId: string,
3920
+ request: UpdateScheduledTaskRequest,
3921
+ ): Promise<ScheduledTask> {
3922
+ return await this.requestJson<ScheduledTask>(
3923
+ "PATCH",
3924
+ `/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}`,
3925
+ request,
3926
+ );
3927
+ }
3928
+
3929
+ async pauseScheduledTask(workspaceId: string, taskId: string): Promise<ScheduledTask> {
3930
+ return await this.requestJson<ScheduledTask>(
3931
+ "POST",
3932
+ `/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}/pause`,
3933
+ );
3934
+ }
3935
+
3936
+ async resumeScheduledTask(workspaceId: string, taskId: string): Promise<ScheduledTask> {
3937
+ return await this.requestJson<ScheduledTask>(
3938
+ "POST",
3939
+ `/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}/resume`,
3940
+ );
3941
+ }
3942
+
3943
+ /**
3944
+ * Fire the task immediately (manual trigger), independent of its schedule.
3945
+ * Pass a stable `triggerId` to make a retried trigger idempotent — the same
3946
+ * token charges once and starts one run. Omit it and each call is distinct.
3947
+ */
3948
+ async triggerScheduledTask(
3949
+ workspaceId: string,
3950
+ taskId: string,
3951
+ options: { triggerId?: string } = {},
3952
+ ): Promise<ScheduledTask> {
3953
+ return await this.requestJson<ScheduledTask>(
3954
+ "POST",
3955
+ `/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}/trigger`,
3956
+ options.triggerId ? { triggerId: options.triggerId } : undefined,
3957
+ );
3958
+ }
3959
+
3960
+ async deleteScheduledTask(workspaceId: string, taskId: string): Promise<void> {
3961
+ await this.requestJson<unknown>(
3962
+ "DELETE",
3963
+ `/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}`,
3964
+ );
3965
+ }
3966
+
3967
+ async listScheduledTaskRuns(
3968
+ workspaceId: string,
3969
+ taskId: string,
3970
+ options: { limit?: number } = {},
3971
+ ): Promise<ScheduledTaskRun[]> {
3972
+ return await this.requestJson<ScheduledTaskRun[]>(
3973
+ "GET",
3974
+ `/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}/runs`,
3975
+ undefined,
3976
+ {
3977
+ ...(options.limit !== undefined ? { limit: String(options.limit) } : {}),
3978
+ },
3979
+ );
3980
+ }
3981
+
3982
+ // --- VariableSets --------------------------------------------------------------
3983
+ // Generic reads return name/version metadata only. Plaintext uses one
3984
+ // dedicated permissioned endpoint.
3985
+
3986
+ async listVariableSets(workspaceId: string): Promise<VariableSet[]> {
3987
+ return await this.requestJson<VariableSet[]>(
3988
+ "GET",
3989
+ `/v1/workspaces/${workspaceId}/variable-sets`,
3990
+ );
3991
+ }
3992
+
3993
+ async createVariableSet(
3994
+ workspaceId: string,
3995
+ request: CreateVariableSetRequest,
3996
+ ): Promise<VariableSet> {
3997
+ return await this.requestJson<VariableSet>(
3998
+ "POST",
3999
+ `/v1/workspaces/${workspaceId}/variable-sets`,
4000
+ request,
4001
+ );
4002
+ }
4003
+
4004
+ async getVariableSet(workspaceId: string, variableSetId: string): Promise<VariableSet> {
4005
+ return await this.requestJson<VariableSet>(
4006
+ "GET",
4007
+ `/v1/workspaces/${workspaceId}/variable-sets/${variableSetId}`,
4008
+ );
4009
+ }
4010
+
4011
+ async getVariableSetVariable(
4012
+ workspaceId: string,
4013
+ variableSetId: string,
4014
+ name: string,
4015
+ ): Promise<VariableSetSecret> {
4016
+ return await this.requestJson<VariableSetSecret>(
4017
+ "GET",
4018
+ `/v1/workspaces/${workspaceId}/variable-sets/${variableSetId}/variables/${encodeURIComponent(name)}`,
4019
+ );
4020
+ }
4021
+
4022
+ async updateVariableSet(
4023
+ workspaceId: string,
4024
+ variableSetId: string,
4025
+ request: UpdateVariableSetRequest,
4026
+ ): Promise<VariableSet> {
4027
+ return await this.requestJson<VariableSet>(
4028
+ "PATCH",
4029
+ `/v1/workspaces/${workspaceId}/variable-sets/${variableSetId}`,
4030
+ request,
4031
+ );
4032
+ }
4033
+
4034
+ async deleteVariableSet(workspaceId: string, variableSetId: string): Promise<void> {
4035
+ await this.requestJson<unknown>(
4036
+ "DELETE",
4037
+ `/v1/workspaces/${workspaceId}/variable-sets/${variableSetId}`,
4038
+ );
4039
+ }
4040
+
4041
+ /** Create or rotate a variable. Generic reads never return its value. */
4042
+ async setVariableSetVariable(
4043
+ workspaceId: string,
4044
+ variableSetId: string,
4045
+ name: string,
4046
+ value: string,
4047
+ ): Promise<VariableSetVariableMetadata> {
4048
+ return await this.requestJson<VariableSetVariableMetadata>(
4049
+ "PUT",
4050
+ `/v1/workspaces/${workspaceId}/variable-sets/${variableSetId}/variables/${encodeURIComponent(name)}`,
4051
+ { value },
4052
+ );
4053
+ }
4054
+
4055
+ async deleteVariableSetVariable(
4056
+ workspaceId: string,
4057
+ variableSetId: string,
4058
+ name: string,
4059
+ ): Promise<void> {
4060
+ await this.requestJson<unknown>(
4061
+ "DELETE",
4062
+ `/v1/workspaces/${workspaceId}/variable-sets/${variableSetId}/variables/${encodeURIComponent(name)}`,
4063
+ );
4064
+ }
4065
+
4066
+ // --- Channels --------------------------------------------------------------
4067
+ // Workspace-shared rail organization for root sessions. sessions:read gates
4068
+ // list; sessions:create gates create / update / delete; sessions:control
4069
+ // gates re-filing a session.
4070
+
4071
+ async listChannels(workspaceId: string): Promise<Channel[]> {
4072
+ return await this.requestJson<Channel[]>("GET", `/v1/workspaces/${workspaceId}/channels`);
4073
+ }
4074
+
4075
+ async createChannel(workspaceId: string, request: CreateChannelRequest): Promise<Channel> {
4076
+ return await this.requestJson<Channel>(
4077
+ "POST",
4078
+ `/v1/workspaces/${workspaceId}/channels`,
4079
+ request,
4080
+ );
4081
+ }
4082
+
4083
+ async updateChannel(
4084
+ workspaceId: string,
4085
+ channelId: string,
4086
+ request: UpdateChannelRequest,
4087
+ ): Promise<Channel> {
4088
+ return await this.requestJson<Channel>(
4089
+ "PATCH",
4090
+ `/v1/workspaces/${workspaceId}/channels/${channelId}`,
4091
+ request,
4092
+ );
4093
+ }
4094
+
4095
+ async deleteChannel(workspaceId: string, channelId: string): Promise<void> {
4096
+ await this.requestJson<unknown>(
4097
+ "DELETE",
4098
+ `/v1/workspaces/${workspaceId}/channels/${channelId}`,
4099
+ );
4100
+ }
4101
+
4102
+ /** Re-file a session into a channel (null = back to the unfiled inbox). */
4103
+ async updateSessionChannel(
4104
+ workspaceId: string,
4105
+ sessionId: string,
4106
+ request: UpdateSessionChannelRequest,
4107
+ ): Promise<Session> {
4108
+ return await this.requestJson<Session>(
4109
+ "PUT",
4110
+ `/v1/workspaces/${workspaceId}/sessions/${sessionId}/channel`,
4111
+ request,
4112
+ );
4113
+ }
4114
+
4115
+ // --- Rigs ------------------------------------------------------------------
4116
+ // Workspace-scoped, versioned sandbox machine definitions. rigs:use gates read
4117
+ // + proposeRigChange; rigs:manage gates create / update / delete / activate.
4118
+
4119
+ async listRigs(workspaceId: string): Promise<Rig[]> {
4120
+ return await this.requestJson<Rig[]>("GET", `/v1/workspaces/${workspaceId}/rigs`);
4121
+ }
4122
+
4123
+ async createRig(workspaceId: string, request: CreateRigRequest): Promise<Rig> {
4124
+ return await this.requestJson<Rig>("POST", `/v1/workspaces/${workspaceId}/rigs`, request);
4125
+ }
4126
+
4127
+ async getRig(workspaceId: string, rigId: string): Promise<Rig> {
4128
+ return await this.requestJson<Rig>("GET", `/v1/workspaces/${workspaceId}/rigs/${rigId}`);
4129
+ }
4130
+
4131
+ async updateRig(workspaceId: string, rigId: string, request: UpdateRigRequest): Promise<Rig> {
4132
+ return await this.requestJson<Rig>(
4133
+ "PATCH",
4134
+ `/v1/workspaces/${workspaceId}/rigs/${rigId}`,
4135
+ request,
4136
+ );
4137
+ }
4138
+
4139
+ async deleteRig(workspaceId: string, rigId: string): Promise<void> {
4140
+ await this.requestJson<unknown>("DELETE", `/v1/workspaces/${workspaceId}/rigs/${rigId}`);
4141
+ }
4142
+
4143
+ async listRigVersions(workspaceId: string, rigId: string): Promise<RigVersion[]> {
4144
+ return await this.requestJson<RigVersion[]>(
4145
+ "GET",
4146
+ `/v1/workspaces/${workspaceId}/rigs/${rigId}/versions`,
4147
+ );
4148
+ }
4149
+
4150
+ /** Roll the active version to an existing one (rollback / promote-activate). */
4151
+ async activateRigVersion(
4152
+ workspaceId: string,
4153
+ rigId: string,
4154
+ versionId: string,
4155
+ ): Promise<RigVersion> {
4156
+ return await this.requestJson<RigVersion>(
4157
+ "POST",
4158
+ `/v1/workspaces/${workspaceId}/rigs/${rigId}/versions/${versionId}/activate`,
4159
+ );
4160
+ }
4161
+
4162
+ async listRigChanges(workspaceId: string, rigId: string): Promise<RigChange[]> {
4163
+ return await this.requestJson<RigChange[]>(
4164
+ "GET",
4165
+ `/v1/workspaces/${workspaceId}/rigs/${rigId}/changes`,
4166
+ );
4167
+ }
4168
+
4169
+ /** Propose a change against the rig's active version (rigs:use). */
4170
+ async proposeRigChange(
4171
+ workspaceId: string,
4172
+ rigId: string,
4173
+ request: ProposeRigChangeRequest,
4174
+ ): Promise<RigChange> {
4175
+ return await this.requestJson<RigChange>(
4176
+ "POST",
4177
+ `/v1/workspaces/${workspaceId}/rigs/${rigId}/changes`,
4178
+ request,
4179
+ );
4180
+ }
4181
+
4182
+ async getRigChange(workspaceId: string, rigId: string, changeId: string): Promise<RigChange> {
4183
+ return await this.requestJson<RigChange>(
4184
+ "GET",
4185
+ `/v1/workspaces/${workspaceId}/rigs/${rigId}/changes/${changeId}`,
4186
+ );
4187
+ }
4188
+
4189
+ /**
4190
+ * Re-run verification for a change (rigs:use). Verification is asynchronous:
4191
+ * this returns the change immediately with status `verifying`; poll
4192
+ * `getRigChange`/`listRigChanges` for the terminal outcome + logs.
4193
+ */
4194
+ async verifyRigChange(workspaceId: string, rigId: string, changeId: string): Promise<RigChange> {
4195
+ return await this.requestJson<RigChange>(
4196
+ "POST",
4197
+ `/v1/workspaces/${workspaceId}/rigs/${rigId}/changes/${changeId}/verify`,
4198
+ );
4199
+ }
4200
+
4201
+ /**
4202
+ * Promote a verified `definition_edit` change into a new active rig version
4203
+ * (rigs:manage). Only valid once the change's verification passed; returns the
4204
+ * newly minted version.
4205
+ */
4206
+ async promoteRigChange(
4207
+ workspaceId: string,
4208
+ rigId: string,
4209
+ changeId: string,
4210
+ ): Promise<RigVersion> {
4211
+ return await this.requestJson<RigVersion>(
4212
+ "POST",
4213
+ `/v1/workspaces/${workspaceId}/rigs/${rigId}/changes/${changeId}/promote`,
4214
+ );
4215
+ }
4216
+
4217
+ /**
4218
+ * Re-run the active version's checks in a clean throwaway sandbox (rigs:use).
4219
+ * Asynchronous — returns the version id being verified; the outcome lands on
4220
+ * the version's audit trail.
4221
+ */
4222
+ async verifyRig(workspaceId: string, rigId: string): Promise<{ ok: boolean; versionId: string }> {
4223
+ return await this.requestJson<{ ok: boolean; versionId: string }>(
4224
+ "POST",
4225
+ `/v1/workspaces/${workspaceId}/rigs/${rigId}/verify`,
4226
+ );
4227
+ }
4228
+
4229
+ /** @deprecated use listVariableSets */
4230
+ async listEnvironments(workspaceId: string): Promise<VariableSet[]> {
4231
+ return await this.listVariableSets(workspaceId);
4232
+ }
4233
+
4234
+ /** @deprecated use createVariableSet */
4235
+ async createEnvironment(
4236
+ workspaceId: string,
4237
+ request: CreateVariableSetRequest,
4238
+ ): Promise<VariableSet> {
4239
+ return await this.createVariableSet(workspaceId, request);
4240
+ }
4241
+
4242
+ /** @deprecated use getVariableSet */
4243
+ async getEnvironment(workspaceId: string, environmentId: string): Promise<VariableSet> {
4244
+ return await this.getVariableSet(workspaceId, environmentId);
4245
+ }
4246
+
4247
+ /** @deprecated use updateVariableSet */
4248
+ async updateEnvironment(
4249
+ workspaceId: string,
4250
+ environmentId: string,
4251
+ request: UpdateVariableSetRequest,
4252
+ ): Promise<VariableSet> {
4253
+ return await this.updateVariableSet(workspaceId, environmentId, request);
4254
+ }
4255
+
4256
+ /** @deprecated use deleteVariableSet */
4257
+ async deleteEnvironment(workspaceId: string, environmentId: string): Promise<void> {
4258
+ await this.deleteVariableSet(workspaceId, environmentId);
4259
+ }
4260
+
4261
+ /** @deprecated use setVariableSetVariable */
4262
+ async setEnvironmentVariable(
4263
+ workspaceId: string,
4264
+ environmentId: string,
4265
+ name: string,
4266
+ value: string,
4267
+ ): Promise<VariableSetVariableMetadata> {
4268
+ return await this.setVariableSetVariable(workspaceId, environmentId, name, value);
4269
+ }
4270
+
4271
+ /** @deprecated use deleteVariableSetVariable */
4272
+ async deleteEnvironmentVariable(
4273
+ workspaceId: string,
4274
+ environmentId: string,
4275
+ name: string,
4276
+ ): Promise<void> {
4277
+ await this.deleteVariableSetVariable(workspaceId, environmentId, name);
4278
+ }
4279
+
4280
+ // --- Files -----------------------------------------------------------------------
4281
+
4282
+ /** Step 1 of the upload flow: returns the pre-signed PUT target. */
4283
+ async beginFileUpload(
4284
+ workspaceId: string,
4285
+ request: CreateFileUploadRequest,
4286
+ options: OpenGeniRequestOptions = {},
4287
+ ): Promise<CreateFileUploadResponse> {
4288
+ return await this.requestJson<CreateFileUploadResponse>(
4289
+ "POST",
4290
+ `/v1/workspaces/${workspaceId}/files/uploads`,
4291
+ request,
4292
+ {},
4293
+ options,
4294
+ );
4295
+ }
4296
+
4297
+ /** Step 3 of the upload flow: server verifies the object and marks it ready. */
4298
+ async completeFileUpload(
4299
+ workspaceId: string,
4300
+ uploadId: string,
4301
+ options: OpenGeniRequestOptions = {},
4302
+ ): Promise<FileAsset> {
4303
+ const response = await this.requestJson<CompleteFileUploadResponse>(
4304
+ "POST",
4305
+ `/v1/workspaces/${workspaceId}/files/uploads/${uploadId}/complete`,
4306
+ undefined,
4307
+ {},
4308
+ options,
4309
+ );
4310
+ return response.file;
4311
+ }
4312
+
4313
+ /**
4314
+ * The whole upload flow as one call: begin -> PUT the bytes to the signed
4315
+ * URL (with its required headers; no API auth is sent to object storage)
4316
+ * -> complete. Returns the ready `FileAsset`.
4317
+ */
4318
+ async uploadFile(workspaceId: string, input: UploadFileInput): Promise<FileAsset> {
4319
+ if (
4320
+ input.timeoutMs !== undefined &&
4321
+ (!Number.isFinite(input.timeoutMs) || input.timeoutMs <= 0)
4322
+ ) {
4323
+ throw new Error("File upload timeout must be a positive number");
4324
+ }
4325
+ const withTimeout = async <T>(
4326
+ timeoutMs: number,
4327
+ operation: (signal: AbortSignal) => Promise<T>,
4328
+ ): Promise<T> => {
4329
+ const controller = new AbortController();
4330
+ let timeout: ReturnType<typeof setTimeout> | undefined;
4331
+ const timedOut = new Promise<never>((_resolve, reject) => {
4332
+ timeout = setTimeout(() => {
4333
+ controller.abort();
4334
+ reject(new Error("File upload timed out. Retry the upload."));
4335
+ }, timeoutMs);
4336
+ });
4337
+ try {
4338
+ return await Promise.race([operation(controller.signal), timedOut]);
4339
+ } finally {
4340
+ if (timeout !== undefined) clearTimeout(timeout);
4341
+ }
4342
+ };
4343
+ // Snapshot mutable inputs before hashing so the digest always describes the
4344
+ // exact bytes later sent to object storage. Copy Uint8Array views into a
4345
+ // Blob so byte offsets/shared buffers can't leak surrounding bytes.
4346
+ const body: Blob | ArrayBuffer | string =
4347
+ input.data instanceof Uint8Array
4348
+ ? new Blob([input.data.slice()])
4349
+ : input.data instanceof ArrayBuffer
4350
+ ? input.data.slice(0)
4351
+ : input.data;
4352
+ const sizeBytes =
4353
+ typeof body === "string"
4354
+ ? new TextEncoder().encode(body).byteLength
4355
+ : body instanceof Blob
4356
+ ? body.size
4357
+ : body.byteLength;
4358
+ const sha256 = input.sha256 ?? (await sha256ForUpload(body));
4359
+ const upload = await withTimeout(
4360
+ 30_000,
4361
+ async (signal) =>
4362
+ await this.beginFileUpload(
4363
+ workspaceId,
4364
+ {
4365
+ filename: input.filename,
4366
+ contentType: input.contentType,
4367
+ sizeBytes,
4368
+ sha256,
4369
+ },
4370
+ { signal },
4371
+ ),
4372
+ );
4373
+ // Give large valid uploads enough time at a conservative 256 KiB/s while
4374
+ // still bounding an object-storage request that never settles.
4375
+ const transferTimeoutMs =
4376
+ input.timeoutMs ?? Math.max(120_000, Math.ceil(sizeBytes / (256 * 1024)) * 1_000);
4377
+ const putResponse = await withTimeout(
4378
+ transferTimeoutMs,
4379
+ async (signal) =>
4380
+ await this.fetchImpl(upload.putUrl, {
4381
+ method: "PUT",
4382
+ // Signed object-storage URLs carry their own short-lived authority.
4383
+ // Browser cookies and HTTP auth must never accompany this cross-origin
4384
+ // request: credentialed fetches are incompatible with wildcard CORS and
4385
+ // can leak ambient credentials to a caller-selected storage endpoint.
4386
+ credentials: "omit",
4387
+ // The backend's requiredHeaders already carry the canonical lowercase
4388
+ // `content-type` for every storage backend (Azure/S3/GCS). Do NOT also set
4389
+ // a `Content-Type` key here: WHATWG Headers treats the two casings as the
4390
+ // same header and comma-joins their values (e.g. "text/plain, text/plain"),
4391
+ // which the object store persists verbatim and COMPLETE then rejects (422),
4392
+ // and which breaks S3's presigned-URL signature.
4393
+ headers: { ...upload.requiredHeaders },
4394
+ body,
4395
+ signal,
4396
+ }),
4397
+ );
4398
+ if (!putResponse.ok) {
4399
+ throw await apiErrorFromResponse(putResponse, { method: "PUT" });
4400
+ }
4401
+ return await withTimeout(
4402
+ 30_000,
4403
+ async (signal) => await this.completeFileUpload(workspaceId, upload.uploadId, { signal }),
4404
+ );
4405
+ }
4406
+
4407
+ async getFile(workspaceId: string, fileId: string): Promise<FileAsset> {
4408
+ return await this.requestJson<FileAsset>(
4409
+ "GET",
4410
+ `/v1/workspaces/${workspaceId}/files/${fileId}`,
4411
+ );
4412
+ }
4413
+
4414
+ /** Read provider-neutral retained evidence metadata; never returns a storage location. */
4415
+ async getRetainedArtifact(
4416
+ workspaceId: string,
4417
+ artifactId: string,
4418
+ ): Promise<RetainedArtifactMetadata> {
4419
+ return await this.requestJson<RetainedArtifactMetadata>(
4420
+ "GET",
4421
+ `/v1/workspaces/${workspaceId}/artifacts/${artifactId}`,
4422
+ );
4423
+ }
4424
+
4425
+ /**
4426
+ * Read at most one authenticated retained-evidence range from the API. This
4427
+ * deliberately does not use the ordinary signed file-download URL.
4428
+ */
4429
+ async getRetainedArtifactContent(
4430
+ workspaceId: string,
4431
+ artifactId: string,
4432
+ options: RetainedArtifactContentOptions = {},
4433
+ ): Promise<RetainedArtifactContent> {
4434
+ return await this.getRetainedArtifactContentAtPath(
4435
+ `/v1/workspaces/${workspaceId}/artifacts/${artifactId}/content`,
4436
+ options,
4437
+ );
4438
+ }
4439
+
4440
+ async getSessionRetainedArtifact(
4441
+ workspaceId: string,
4442
+ sessionId: string,
4443
+ artifactId: string,
4444
+ ): Promise<RetainedArtifactMetadata> {
4445
+ return await this.requestJson<RetainedArtifactMetadata>(
4446
+ "GET",
4447
+ `/v1/workspaces/${workspaceId}/sessions/${sessionId}/artifacts/${artifactId}`,
4448
+ );
4449
+ }
4450
+
4451
+ async getSessionRetainedArtifactContent(
4452
+ workspaceId: string,
4453
+ sessionId: string,
4454
+ artifactId: string,
4455
+ options: RetainedArtifactContentOptions = {},
4456
+ ): Promise<RetainedArtifactContent> {
4457
+ return await this.getRetainedArtifactContentAtPath(
4458
+ `/v1/workspaces/${workspaceId}/sessions/${sessionId}/artifacts/${artifactId}/content`,
4459
+ options,
4460
+ );
4461
+ }
4462
+
4463
+ /** Assemble one permanent generated-image receipt from bounded authenticated ranges. */
4464
+ async downloadRetainedArtifact(
4465
+ workspaceId: string,
4466
+ artifact: RetainedArtifactReference,
4467
+ options: RetainedArtifactDownloadOptions = {},
4468
+ ): Promise<RetainedArtifactDownload> {
4469
+ assertRetainedGeneratedImageReceipt(workspaceId, artifact);
4470
+ const bytes = await this.downloadRetainedArtifactBytes(artifact, options);
4471
+ return { artifact, bytes };
4472
+ }
4473
+
4474
+ /** Mint a short-lived, zero-copy browser source for a validated generated image. */
4475
+ async createRetainedArtifactDownloadUrl(
4476
+ workspaceId: string,
4477
+ artifact: RetainedArtifactReference,
4478
+ options: OpenGeniRequestOptions = {},
4479
+ ): Promise<FileDownloadUrlResponse> {
4480
+ assertRetainedGeneratedImageReceipt(workspaceId, artifact);
4481
+ const download = await this.createFileDownloadUrl(workspaceId, artifact.artifactId, options);
4482
+ assertSafeArtifactDownloadUrl(download);
4483
+ return download;
4484
+ }
4485
+
4486
+ /** Assemble one retained screenshot from bounded authenticated API ranges. */
4487
+ async downloadRetainedScreenshot(
4488
+ workspaceId: string,
4489
+ sessionId: string,
4490
+ artifactId: string,
4491
+ options: RetainedScreenshotDownloadOptions = {},
4492
+ ): Promise<RetainedScreenshotDownload> {
4493
+ const metadata = await this.getSessionRetainedArtifact(workspaceId, sessionId, artifactId);
4494
+ if (!metadata.available) return { metadata, bytes: null };
4495
+ if (
4496
+ metadata.kind !== "computer_screenshot" ||
4497
+ metadata.contentType !== "image/png" ||
4498
+ !metadata.dimensions ||
4499
+ metadata.originalBytes <= 0 ||
4500
+ metadata.originalBytes > COMPUTER_SCREENSHOT_MAX_BYTES
4501
+ ) {
4502
+ throw new OpenGeniApiError(502, "retained screenshot metadata is invalid");
4503
+ }
4504
+ const bytes = await this.downloadRetainedArtifactBytes(metadata, options);
4505
+ return { metadata, bytes };
4506
+ }
4507
+
4508
+ private async downloadRetainedArtifactBytes(
4509
+ artifact: RetainedArtifactReference,
4510
+ options: RetainedArtifactDownloadOptions,
4511
+ ): Promise<Uint8Array> {
4512
+ const maxRetries = options.maxRetries ?? 2;
4513
+ if (!Number.isInteger(maxRetries) || maxRetries < 0 || maxRetries > 3) {
4514
+ throw new RangeError("retained artifact maxRetries must be an integer from 0 to 3");
4515
+ }
4516
+ const bytes = new Uint8Array(artifact.originalBytes);
4517
+ const pageBytes = Math.min(artifact.retrieval.maxRangeBytes, RETAINED_OUTPUT_MAX_PAGE_BYTES);
4518
+ if (!Number.isSafeInteger(pageBytes) || pageBytes <= 0) {
4519
+ throw new OpenGeniApiError(502, "retained artifact range metadata is invalid");
4520
+ }
4521
+ for (let start = 0; start < bytes.byteLength; start += pageBytes) {
4522
+ options.signal?.throwIfAborted();
4523
+ const end = Math.min(start + pageBytes, bytes.byteLength) - 1;
4524
+ let page: RetainedArtifactContent | null = null;
4525
+ for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
4526
+ try {
4527
+ page = await this.getRetainedArtifactContentAtPath(artifact.retrieval.path, {
4528
+ range: `bytes=${start}-${end}`,
4529
+ ...(options.signal ? { signal: options.signal } : {}),
4530
+ });
4531
+ break;
4532
+ } catch (error) {
4533
+ options.signal?.throwIfAborted();
4534
+ if (
4535
+ attempt >= maxRetries ||
4536
+ (error instanceof OpenGeniApiError && error.status >= 400 && error.status < 500)
4537
+ ) {
4538
+ throw error;
4539
+ }
4540
+ }
4541
+ }
4542
+ if (!page) throw new OpenGeniApiError(502, "retained artifact range retry exhausted");
4543
+ const expectedLength = end - start + 1;
4544
+ if (
4545
+ page.status !== 206 ||
4546
+ page.contentType !== artifact.contentType ||
4547
+ page.contentLength !== expectedLength ||
4548
+ page.contentRange !== `bytes ${start}-${end}/${artifact.originalBytes}`
4549
+ ) {
4550
+ throw new OpenGeniApiError(502, "retained artifact range response is invalid");
4551
+ }
4552
+ bytes.set(page.bytes, start);
4553
+ }
4554
+ if ((await sha256Hex(bytes)) !== artifact.sha256) {
4555
+ throw new OpenGeniApiError(502, "retained artifact checksum mismatch");
4556
+ }
4557
+ return bytes;
4558
+ }
4559
+
4560
+ private async getRetainedArtifactContentAtPath(
4561
+ path: string,
4562
+ options: RetainedArtifactContentOptions,
4563
+ ): Promise<RetainedArtifactContent> {
4564
+ if (options.range && (options.range.length > 128 || /[^\x20-\x7e]/.test(options.range))) {
4565
+ throw new RangeError("retained artifact range must be at most 128 printable ASCII bytes");
4566
+ }
4567
+ const correlationId = crypto.randomUUID();
4568
+ const response = await this.fetchImpl(this.url(path), {
4569
+ method: "GET",
4570
+ headers: {
4571
+ ...this.headers(correlationId),
4572
+ Accept: "application/octet-stream",
4573
+ ...(options.range ? { Range: options.range } : {}),
4574
+ },
4575
+ ...(options.signal ? { signal: options.signal } : {}),
4576
+ });
4577
+ try {
4578
+ assertApiContractResponse(response);
4579
+ } catch (error) {
4580
+ await cancelResponseBody(response, "retained artifact API contract mismatch");
4581
+ throw error;
4582
+ }
4583
+ if (!response.ok) {
4584
+ throw await apiErrorFromResponse(response, {
4585
+ method: "GET",
4586
+ correlationId,
4587
+ });
4588
+ }
4589
+ if (response.status !== 200 && response.status !== 206) {
4590
+ await cancelResponseBody(response, "unexpected retained artifact response status");
4591
+ throw new OpenGeniApiError(response.status, "unexpected retained artifact response status");
4592
+ }
4593
+ if (response.headers.get("accept-ranges") !== "bytes") {
4594
+ await cancelResponseBody(response, "retained artifact response omitted byte-range support");
4595
+ throw new OpenGeniApiError(502, "retained artifact response omitted byte-range support");
4596
+ }
4597
+ let declaredLength: number | null;
4598
+ try {
4599
+ declaredLength = parseBoundedContentLength(response.headers.get("content-length"));
4600
+ } catch (error) {
4601
+ await cancelResponseBody(response, "invalid retained artifact content-length");
4602
+ throw error;
4603
+ }
4604
+ const bytes = await readBoundedResponseBytes(
4605
+ response,
4606
+ RETAINED_OUTPUT_MAX_PAGE_BYTES,
4607
+ declaredLength,
4608
+ );
4609
+ return {
4610
+ bytes,
4611
+ status: response.status,
4612
+ contentType: response.headers.get("content-type") ?? "application/octet-stream",
4613
+ contentLength: bytes.byteLength,
4614
+ contentRange: response.headers.get("content-range"),
4615
+ acceptRanges: "bytes",
4616
+ };
4617
+ }
4618
+
4619
+ /** Mint a short-lived signed download URL for a ready file. */
4620
+ async createFileDownloadUrl(
4621
+ workspaceId: string,
4622
+ fileId: string,
4623
+ options: OpenGeniRequestOptions = {},
4624
+ ): Promise<FileDownloadUrlResponse> {
4625
+ return await this.requestJson<FileDownloadUrlResponse>(
4626
+ "POST",
4627
+ `/v1/workspaces/${workspaceId}/files/${fileId}/download-url`,
4628
+ undefined,
4629
+ {},
4630
+ options,
4631
+ );
4632
+ }
4633
+
4634
+ // --- Video generation ---------------------------------------------------------------
4635
+
4636
+ /** Read the effective workspace policy and executable Seedance capabilities. */
4637
+ async getVideoGenerationSettings(
4638
+ workspaceId: string,
4639
+ options: OpenGeniRequestOptions = {},
4640
+ ): Promise<WorkspaceVideoGenerationSettings> {
4641
+ return await this.requestJson<WorkspaceVideoGenerationSettings>(
4642
+ "GET",
4643
+ `/v1/workspaces/${workspaceId}/video-generation`,
4644
+ undefined,
4645
+ {},
4646
+ options,
4647
+ );
4648
+ }
4649
+
4650
+ /** Replace the enabled video models/default under optimistic policy revision control. */
4651
+ async updateVideoGenerationPolicy(
4652
+ workspaceId: string,
4653
+ request: UpdateVideoGenerationPolicyRequest,
4654
+ options: OpenGeniRequestOptions = {},
4655
+ ): Promise<VideoGenerationPolicy> {
4656
+ return await this.requestJson<VideoGenerationPolicy>(
4657
+ "PUT",
4658
+ `/v1/workspaces/${workspaceId}/video-generation/policy`,
4659
+ request,
4660
+ {},
4661
+ options,
4662
+ );
4663
+ }
4664
+
4665
+ /** Read durable progress for one accepted video generation operation. */
4666
+ async getVideoGenerationOperation(
4667
+ workspaceId: string,
4668
+ operationId: string,
4669
+ options: OpenGeniRequestOptions = {},
4670
+ ): Promise<VideoGenerationOperationSummary> {
4671
+ return await this.requestJson<VideoGenerationOperationSummary>(
4672
+ "GET",
4673
+ `/v1/workspaces/${workspaceId}/video-generation/operations/${operationId}`,
4674
+ undefined,
4675
+ {},
4676
+ options,
4677
+ );
4678
+ }
4679
+
4680
+ /** Mint a short-lived zero-copy URL for native Range-based video playback. */
4681
+ async createVideoArtifactPlaybackSource(
4682
+ workspaceId: string,
4683
+ artifactId: string,
4684
+ options: OpenGeniRequestOptions = {},
4685
+ ): Promise<VideoArtifactPlaybackSource> {
4686
+ const source = await this.requestJson<VideoArtifactPlaybackSource>(
4687
+ "POST",
4688
+ `/v1/workspaces/${workspaceId}/artifacts/${artifactId}/playback-source`,
4689
+ undefined,
4690
+ {},
4691
+ options,
4692
+ );
4693
+ assertSafeVideoArtifactPlaybackSource(source, artifactId);
4694
+ return source;
4695
+ }
4696
+
4697
+ // --- Documents ----------------------------------------------------------------------
4698
+
4699
+ async createDocumentBase(
4700
+ workspaceId: string,
4701
+ request: CreateDocumentBaseRequest,
4702
+ ): Promise<DocumentBase> {
4703
+ return await this.requestJson<DocumentBase>(
4704
+ "POST",
4705
+ `/v1/workspaces/${workspaceId}/document-bases`,
4706
+ request,
4707
+ );
4708
+ }
4709
+
4710
+ async listDocumentBases(workspaceId: string): Promise<DocumentBase[]> {
4711
+ return await this.requestJson<DocumentBase[]>(
4712
+ "GET",
4713
+ `/v1/workspaces/${workspaceId}/document-bases`,
4714
+ );
4715
+ }
4716
+
4717
+ async getDocumentBase(workspaceId: string, baseId: string): Promise<DocumentBase> {
4718
+ return await this.requestJson<DocumentBase>(
4719
+ "GET",
4720
+ `/v1/workspaces/${workspaceId}/document-bases/${baseId}`,
4721
+ );
4722
+ }
4723
+
4724
+ /** Index an uploaded file into the base. The file must be `ready`. */
4725
+ async addDocument(
4726
+ workspaceId: string,
4727
+ baseId: string,
4728
+ request: AddDocumentRequest,
4729
+ ): Promise<Document> {
4730
+ return await this.requestJson<Document>(
4731
+ "POST",
4732
+ `/v1/workspaces/${workspaceId}/document-bases/${baseId}/documents`,
4733
+ request,
4734
+ );
4735
+ }
4736
+
4737
+ async listDocuments(workspaceId: string, baseId: string): Promise<Document[]> {
4738
+ return await this.requestJson<Document[]>(
4739
+ "GET",
4740
+ `/v1/workspaces/${workspaceId}/document-bases/${baseId}/documents`,
4741
+ );
4742
+ }
4743
+
4744
+ /**
4745
+ * Drop raw text or an already-uploaded file into the workspace's Default
4746
+ * base. When curation is enabled, it may name, summarize, categorize, and
4747
+ * (confidence permitting) file the document into the best-matching base;
4748
+ * provider=none leaves caller metadata and Default placement unchanged.
4749
+ */
4750
+ async createKnowledgeDrop(
4751
+ workspaceId: string,
4752
+ request: CreateKnowledgeDropRequest,
4753
+ ): Promise<Document> {
4754
+ return await this.requestJson<Document>(
4755
+ "POST",
4756
+ `/v1/workspaces/${workspaceId}/knowledge/drops`,
4757
+ request,
4758
+ );
4759
+ }
4760
+
4761
+ /**
4762
+ * Move a document (and its indexed chunks) to another base. With no
4763
+ * targetBaseId, applies the document's stored curation suggestion.
4764
+ */
4765
+ async moveDocument(
4766
+ workspaceId: string,
4767
+ documentId: string,
4768
+ request: MoveDocumentRequest = {},
4769
+ ): Promise<Document> {
4770
+ return await this.requestJson<Document>(
4771
+ "POST",
4772
+ `/v1/workspaces/${workspaceId}/documents/${documentId}/move`,
4773
+ request,
4774
+ );
4775
+ }
4776
+
4777
+ /** Retry indexing for a failed document. */
4778
+ async reindexDocument(
4779
+ workspaceId: string,
4780
+ baseId: string,
4781
+ documentId: string,
4782
+ ): Promise<Document> {
4783
+ return await this.requestJson<Document>(
4784
+ "POST",
4785
+ `/v1/workspaces/${workspaceId}/document-bases/${baseId}/documents/${documentId}/reindex`,
4786
+ );
4787
+ }
4788
+
4789
+ /**
4790
+ * Delete a document from a base. Removes the document row and its indexed
4791
+ * chunks while leaving the uploaded file asset available for other uses.
4792
+ */
4793
+ async deleteDocument(workspaceId: string, baseId: string, documentId: string): Promise<void> {
4794
+ await this.requestVoid(
4795
+ "DELETE",
4796
+ `/v1/workspaces/${workspaceId}/document-bases/${baseId}/documents/${documentId}`,
4797
+ );
4798
+ }
4799
+
4800
+ async searchDocuments(
4801
+ workspaceId: string,
4802
+ baseId: string,
4803
+ request: Omit<DocumentSearchRequest, "baseIds">,
4804
+ ): Promise<DocumentSearchResponse> {
4805
+ return await this.requestJson<DocumentSearchResponse>(
4806
+ "POST",
4807
+ `/v1/workspaces/${workspaceId}/document-bases/${baseId}/search`,
4808
+ request,
4809
+ );
4810
+ }
4811
+
4812
+ async searchKnowledge(
4813
+ workspaceId: string,
4814
+ request: DocumentSearchRequest,
4815
+ ): Promise<DocumentSearchResponse> {
4816
+ return await this.requestJson<DocumentSearchResponse>(
4817
+ "POST",
4818
+ `/v1/workspaces/${workspaceId}/knowledge/search`,
4819
+ request,
4820
+ );
4821
+ }
4822
+
4823
+ async listKnowledgeMemories(
4824
+ workspaceId: string,
4825
+ request: KnowledgeMemorySearchRequest = {},
4826
+ ): Promise<KnowledgeMemory[]> {
4827
+ const params = new URLSearchParams();
4828
+ if (request.query) params.set("query", request.query);
4829
+ if (request.status) params.set("status", request.status);
4830
+ if (request.kind) params.set("kind", request.kind);
4831
+ if (request.scope) params.set("scope", request.scope);
4832
+ if (request.limit) params.set("limit", String(request.limit));
4833
+ const query = params.toString();
4834
+ return await this.requestJson<KnowledgeMemory[]>(
4835
+ "GET",
4836
+ `/v1/workspaces/${workspaceId}/knowledge/memories${query ? `?${query}` : ""}`,
4837
+ );
4838
+ }
4839
+
4840
+ async getKnowledgeMemory(workspaceId: string, memoryId: string): Promise<KnowledgeMemory> {
4841
+ return await this.requestJson<KnowledgeMemory>(
4842
+ "GET",
4843
+ `/v1/workspaces/${workspaceId}/knowledge/memories/${memoryId}`,
4844
+ );
4845
+ }
4846
+
4847
+ async createKnowledgeMemory(
4848
+ workspaceId: string,
4849
+ request: CreateKnowledgeMemoryRequest,
4850
+ ): Promise<KnowledgeMemory> {
4851
+ return await this.requestJson<KnowledgeMemory>(
4852
+ "POST",
4853
+ `/v1/workspaces/${workspaceId}/knowledge/memories`,
4854
+ request,
4855
+ );
4856
+ }
4857
+
4858
+ async updateKnowledgeMemory(
4859
+ workspaceId: string,
4860
+ memoryId: string,
4861
+ request: UpdateKnowledgeMemoryRequest,
4862
+ ): Promise<KnowledgeMemory> {
4863
+ return await this.requestJson<KnowledgeMemory>(
4864
+ "PATCH",
4865
+ `/v1/workspaces/${workspaceId}/knowledge/memories/${memoryId}`,
4866
+ request,
4867
+ );
4868
+ }
4869
+
4870
+ /** Hybrid (semantic + keyword) search over the workspace's agent-visible memory. */
4871
+ async searchWorkspaceMemories(
4872
+ workspaceId: string,
4873
+ request: WorkspaceMemorySearchRequest,
4874
+ ): Promise<WorkspaceMemorySearchResponse> {
4875
+ return await this.requestJson<WorkspaceMemorySearchResponse>(
4876
+ "POST",
4877
+ `/v1/workspaces/${workspaceId}/knowledge/memories/search`,
4878
+ request,
4879
+ );
4880
+ }
4881
+
4882
+ /** Deep-merge a settings patch into the workspace (preserves unknown keys). */
4883
+ async updateWorkspaceSettings(
4884
+ workspaceId: string,
4885
+ request: UpdateWorkspaceSettingsRequest,
4886
+ ): Promise<Workspace> {
4887
+ return await this.requestJson<Workspace>(
4888
+ "PATCH",
4889
+ `/v1/workspaces/${workspaceId}/settings`,
4890
+ request,
4891
+ );
4892
+ }
4893
+
4894
+ async setWorkspaceDefaultRig(
4895
+ workspaceId: string,
4896
+ request: SetWorkspaceDefaultRigRequest,
4897
+ ): Promise<Workspace> {
4898
+ return await this.requestJson<Workspace>(
4899
+ "PUT",
4900
+ `/v1/workspaces/${workspaceId}/default-rig`,
4901
+ request,
4902
+ );
4903
+ }
4904
+
4905
+ // --- Capability packs ------------------------------------------------------------------
4906
+
4907
+ /** Built-in + registered packs, with the workspace's installations. */
4908
+ async listPacks(workspaceId: string): Promise<ListPacksResponse> {
4909
+ return await this.requestJson<ListPacksResponse>("GET", `/v1/workspaces/${workspaceId}/packs`);
4910
+ }
4911
+
4912
+ /** Register (or replace) a workspace-scoped pack from a manifest. */
4913
+ async registerPack(
4914
+ workspaceId: string,
4915
+ manifest: RegisterCapabilityPackRequest,
4916
+ ): Promise<WorkspaceRegisteredPack> {
4917
+ return await this.requestJson<WorkspaceRegisteredPack>(
4918
+ "POST",
4919
+ `/v1/workspaces/${workspaceId}/packs`,
4920
+ manifest,
4921
+ );
3093
4922
  }
3094
4923
 
3095
- private async getRetainedArtifactContentAtPath(
3096
- path: string,
3097
- options: RetainedArtifactContentOptions,
3098
- ): Promise<RetainedArtifactContent> {
3099
- if (options.range && (options.range.length > 128 || /[^\x20-\x7e]/.test(options.range))) {
3100
- throw new RangeError("retained artifact range must be at most 128 printable ASCII bytes");
3101
- }
3102
- const correlationId = crypto.randomUUID();
3103
- const response = await this.fetchImpl(this.url(path), {
3104
- method: "GET",
3105
- headers: {
3106
- ...this.headers(correlationId),
3107
- Accept: "application/octet-stream",
3108
- ...(options.range ? { Range: options.range } : {}),
3109
- },
3110
- ...(options.signal ? { signal: options.signal } : {}),
3111
- });
3112
- try {
3113
- assertApiContractResponse(response);
3114
- } catch (error) {
3115
- await cancelResponseBody(response, "retained artifact API contract mismatch");
3116
- throw error;
3117
- }
3118
- if (!response.ok) {
3119
- throw await apiErrorFromResponse(response, {
3120
- method: "GET",
3121
- correlationId,
3122
- });
3123
- }
3124
- if (response.status !== 200 && response.status !== 206) {
3125
- await cancelResponseBody(response, "unexpected retained artifact response status");
3126
- throw new OpenGeniApiError(response.status, "unexpected retained artifact response status");
3127
- }
3128
- if (response.headers.get("accept-ranges") !== "bytes") {
3129
- await cancelResponseBody(response, "retained artifact response omitted byte-range support");
3130
- throw new OpenGeniApiError(502, "retained artifact response omitted byte-range support");
3131
- }
3132
- let declaredLength: number | null;
3133
- try {
3134
- declaredLength = parseBoundedContentLength(response.headers.get("content-length"));
3135
- } catch (error) {
3136
- await cancelResponseBody(response, "invalid retained artifact content-length");
3137
- throw error;
3138
- }
3139
- const bytes = await readBoundedResponseBytes(
3140
- response,
3141
- RETAINED_OUTPUT_MAX_PAGE_BYTES,
3142
- declaredLength,
4924
+ async getPack(workspaceId: string, packId: string): Promise<GetPackResponse> {
4925
+ return await this.requestJson<GetPackResponse>(
4926
+ "GET",
4927
+ `/v1/workspaces/${workspaceId}/packs/${encodeURIComponent(packId)}`,
3143
4928
  );
3144
- return {
3145
- bytes,
3146
- status: response.status,
3147
- contentType: response.headers.get("content-type") ?? "application/octet-stream",
3148
- contentLength: bytes.byteLength,
3149
- contentRange: response.headers.get("content-range"),
3150
- acceptRanges: "bytes",
3151
- };
3152
4929
  }
3153
4930
 
3154
- /** Mint a short-lived signed download URL for a ready file. */
3155
- async createFileDownloadUrl(
4931
+ async enablePack(
3156
4932
  workspaceId: string,
3157
- fileId: string,
3158
- ): Promise<FileDownloadUrlResponse> {
3159
- return await this.requestJson<FileDownloadUrlResponse>(
4933
+ packId: string,
4934
+ request: EnablePackRequest = {},
4935
+ ): Promise<PackInstallation> {
4936
+ return await this.requestJson<PackInstallation>(
3160
4937
  "POST",
3161
- `/v1/workspaces/${workspaceId}/files/${fileId}/download-url`,
4938
+ `/v1/workspaces/${workspaceId}/packs/${encodeURIComponent(packId)}/enable`,
4939
+ request,
3162
4940
  );
3163
4941
  }
3164
4942
 
3165
- // --- Documents ----------------------------------------------------------------------
3166
-
3167
- async createDocumentBase(
4943
+ /** Resolve pinned components, Variable Set, and Rig requirements before installation. */
4944
+ async previewPackInstallation(
3168
4945
  workspaceId: string,
3169
- request: CreateDocumentBaseRequest,
3170
- ): Promise<DocumentBase> {
3171
- return await this.requestJson<DocumentBase>(
4946
+ packId: string,
4947
+ request: PreviewPackInstallationRequest = {},
4948
+ ): Promise<PackInstallationPreview> {
4949
+ return await this.requestJson<PackInstallationPreview>(
3172
4950
  "POST",
3173
- `/v1/workspaces/${workspaceId}/document-bases`,
4951
+ `/v1/workspaces/${workspaceId}/packs/${encodeURIComponent(packId)}/installation-preview`,
3174
4952
  request,
3175
4953
  );
3176
4954
  }
3177
4955
 
3178
- async listDocumentBases(workspaceId: string): Promise<DocumentBase[]> {
3179
- return await this.requestJson<DocumentBase[]>(
3180
- "GET",
3181
- `/v1/workspaces/${workspaceId}/document-bases`,
4956
+ /** Install, update, or repair a Pack from an exact previewed manifest. */
4957
+ async installPack(
4958
+ workspaceId: string,
4959
+ packId: string,
4960
+ request: InstallPackRequest,
4961
+ ): Promise<PackInstallation> {
4962
+ return await this.requestJson<PackInstallation>(
4963
+ "POST",
4964
+ `/v1/workspaces/${workspaceId}/packs/${encodeURIComponent(packId)}/install`,
4965
+ request,
3182
4966
  );
3183
4967
  }
3184
4968
 
3185
- async getDocumentBase(workspaceId: string, baseId: string): Promise<DocumentBase> {
3186
- return await this.requestJson<DocumentBase>(
4969
+ /** Preview which Pack-owned components will be retained by other owners. */
4970
+ async previewPackUninstall(workspaceId: string, packId: string): Promise<PackUninstallPreview> {
4971
+ return await this.requestJson<PackUninstallPreview>(
3187
4972
  "GET",
3188
- `/v1/workspaces/${workspaceId}/document-bases/${baseId}`,
4973
+ `/v1/workspaces/${workspaceId}/packs/${encodeURIComponent(packId)}/uninstall-preview`,
3189
4974
  );
3190
4975
  }
3191
4976
 
3192
- /** Index an uploaded file into the base. The file must be `ready`. */
3193
- async addDocument(
4977
+ /** Safely release Pack ownership and disable only now-ownerless components. */
4978
+ async uninstallPack(
3194
4979
  workspaceId: string,
3195
- baseId: string,
3196
- request: AddDocumentRequest,
3197
- ): Promise<Document> {
3198
- return await this.requestJson<Document>(
3199
- "POST",
3200
- `/v1/workspaces/${workspaceId}/document-bases/${baseId}/documents`,
4980
+ packId: string,
4981
+ request: UninstallPackRequest,
4982
+ ): Promise<UninstallPackResult> {
4983
+ return await this.requestJson<UninstallPackResult>(
4984
+ "DELETE",
4985
+ `/v1/workspaces/${workspaceId}/packs/${encodeURIComponent(packId)}/installation`,
3201
4986
  request,
3202
4987
  );
3203
4988
  }
3204
4989
 
3205
- async listDocuments(workspaceId: string, baseId: string): Promise<Document[]> {
3206
- return await this.requestJson<Document[]>(
4990
+ /** Unregister a workspace-scoped pack (built-in packs cannot be deleted). */
4991
+ async deletePack(workspaceId: string, packId: string): Promise<void> {
4992
+ await this.requestVoid(
4993
+ "DELETE",
4994
+ `/v1/workspaces/${workspaceId}/packs/${encodeURIComponent(packId)}`,
4995
+ );
4996
+ }
4997
+
4998
+ async listPackInstallations(workspaceId: string): Promise<PackInstallation[]> {
4999
+ return await this.requestJson<PackInstallation[]>(
3207
5000
  "GET",
3208
- `/v1/workspaces/${workspaceId}/document-bases/${baseId}/documents`,
5001
+ `/v1/workspaces/${workspaceId}/packs/installations`,
3209
5002
  );
3210
5003
  }
3211
5004
 
3212
- /**
3213
- * Drop raw text or an already-uploaded file into the workspace's Default
3214
- * base. When curation is enabled, it may name, summarize, categorize, and
3215
- * (confidence permitting) file the document into the best-matching base;
3216
- * provider=none leaves caller metadata and Default placement unchanged.
3217
- */
3218
- async createKnowledgeDrop(
5005
+ // --- Capabilities -------------------------------------------------------------------------
5006
+
5007
+ async listCapabilities(workspaceId: string): Promise<CapabilityCatalogResponse> {
5008
+ return await this.requestJson<CapabilityCatalogResponse>(
5009
+ "GET",
5010
+ `/v1/workspaces/${workspaceId}/capabilities`,
5011
+ );
5012
+ }
5013
+
5014
+ /** Add a manual capability catalog item (e.g. a remote MCP server). */
5015
+ async createCapability(
3219
5016
  workspaceId: string,
3220
- request: CreateKnowledgeDropRequest,
3221
- ): Promise<Document> {
3222
- return await this.requestJson<Document>(
5017
+ request: CreateCapabilityCatalogItemRequest,
5018
+ ): Promise<CapabilityCatalogItem> {
5019
+ return await this.requestJson<CapabilityCatalogItem>(
3223
5020
  "POST",
3224
- `/v1/workspaces/${workspaceId}/knowledge/drops`,
5021
+ `/v1/workspaces/${workspaceId}/capabilities`,
3225
5022
  request,
3226
5023
  );
3227
5024
  }
3228
5025
 
3229
- /**
3230
- * Move a document (and its indexed chunks) to another base. With no
3231
- * targetBaseId, applies the document's stored curation suggestion.
3232
- */
3233
- async moveDocument(
5026
+ async enableCapability(
3234
5027
  workspaceId: string,
3235
- documentId: string,
3236
- request: MoveDocumentRequest = {},
3237
- ): Promise<Document> {
3238
- return await this.requestJson<Document>(
5028
+ capabilityId: string,
5029
+ request: EnableCapabilityRequest = {},
5030
+ ): Promise<CapabilityInstallation> {
5031
+ return await this.requestJson<CapabilityInstallation>(
3239
5032
  "POST",
3240
- `/v1/workspaces/${workspaceId}/documents/${documentId}/move`,
5033
+ `/v1/workspaces/${workspaceId}/capabilities/${encodeURIComponent(capabilityId)}/enable`,
3241
5034
  request,
3242
5035
  );
3243
5036
  }
3244
5037
 
3245
- /** Retry indexing for a failed document. */
3246
- async reindexDocument(
5038
+ async disableCapability(
3247
5039
  workspaceId: string,
3248
- baseId: string,
3249
- documentId: string,
3250
- ): Promise<Document> {
3251
- return await this.requestJson<Document>(
5040
+ capabilityId: string,
5041
+ ): Promise<CapabilityInstallation> {
5042
+ return await this.requestJson<CapabilityInstallation>(
3252
5043
  "POST",
3253
- `/v1/workspaces/${workspaceId}/document-bases/${baseId}/documents/${documentId}/reindex`,
5044
+ `/v1/workspaces/${workspaceId}/capabilities/${encodeURIComponent(capabilityId)}/disable`,
3254
5045
  );
3255
5046
  }
3256
5047
 
3257
- /**
3258
- * Delete a document from a base. Removes the document row and its indexed
3259
- * chunks while leaving the uploaded file asset available for other uses.
3260
- */
3261
- async deleteDocument(workspaceId: string, baseId: string, documentId: string): Promise<void> {
3262
- await this.requestVoid(
3263
- "DELETE",
3264
- `/v1/workspaces/${workspaceId}/document-bases/${baseId}/documents/${documentId}`,
5048
+ /** Search the official MCP registry for installable capabilities. */
5049
+ async discoverMcpCapabilities(
5050
+ workspaceId: string,
5051
+ options: { query?: string; limit?: number } = {},
5052
+ ): Promise<DiscoverMcpCapabilitiesResponse> {
5053
+ return await this.requestJson<DiscoverMcpCapabilitiesResponse>(
5054
+ "GET",
5055
+ `/v1/workspaces/${workspaceId}/capabilities/discovery/mcp-registry`,
5056
+ undefined,
5057
+ {
5058
+ ...(options.query !== undefined ? { query: options.query } : {}),
5059
+ ...(options.limit !== undefined ? { limit: String(options.limit) } : {}),
5060
+ },
3265
5061
  );
3266
5062
  }
3267
5063
 
3268
- async searchDocuments(
5064
+ /** List installed protocol-neutral OpenAPI and GraphQL Integrations. */
5065
+ async listApiIntegrations(workspaceId: string): Promise<ListApiIntegrationsResponse> {
5066
+ return await this.requestJson<ListApiIntegrationsResponse>(
5067
+ "GET",
5068
+ `/v1/workspaces/${workspaceId}/integrations`,
5069
+ );
5070
+ }
5071
+
5072
+ /** List curated provider definitions without exposing deployment OAuth credentials. */
5073
+ async listIntegrationDefinitions(
3269
5074
  workspaceId: string,
3270
- baseId: string,
3271
- request: Omit<DocumentSearchRequest, "baseIds">,
3272
- ): Promise<DocumentSearchResponse> {
3273
- return await this.requestJson<DocumentSearchResponse>(
5075
+ ): Promise<ListIntegrationDefinitionsResponse> {
5076
+ return await this.requestJson<ListIntegrationDefinitionsResponse>(
5077
+ "GET",
5078
+ `/v1/workspaces/${workspaceId}/integrations/definitions`,
5079
+ );
5080
+ }
5081
+
5082
+ /** Detect and compile an Integration without mutating workspace state. */
5083
+ async previewApiIntegration(
5084
+ workspaceId: string,
5085
+ request: PreviewApiIntegrationRequest,
5086
+ ): Promise<ApiIntegrationPreview> {
5087
+ return await this.requestJson<ApiIntegrationPreview>(
3274
5088
  "POST",
3275
- `/v1/workspaces/${workspaceId}/document-bases/${baseId}/search`,
5089
+ `/v1/workspaces/${workspaceId}/integrations/preview`,
3276
5090
  request,
3277
5091
  );
3278
5092
  }
3279
5093
 
3280
- async searchKnowledge(
5094
+ /** Start a signed PKCE OAuth flow for a built-in Google or Microsoft definition. */
5095
+ async startApiIntegrationOAuth(
3281
5096
  workspaceId: string,
3282
- request: DocumentSearchRequest,
3283
- ): Promise<DocumentSearchResponse> {
3284
- return await this.requestJson<DocumentSearchResponse>(
5097
+ request: ApiIntegrationOAuthStartRequest,
5098
+ ): Promise<OAuthStartResponse> {
5099
+ return await this.requestJson<OAuthStartResponse>(
3285
5100
  "POST",
3286
- `/v1/workspaces/${workspaceId}/knowledge/search`,
5101
+ `/v1/workspaces/${workspaceId}/integrations/oauth/start`,
3287
5102
  request,
3288
5103
  );
3289
5104
  }
3290
5105
 
3291
- async listKnowledgeMemories(
5106
+ /** Install only the exact immutable revision and digest accepted in preview. */
5107
+ async installApiIntegration(
3292
5108
  workspaceId: string,
3293
- request: KnowledgeMemorySearchRequest = {},
3294
- ): Promise<KnowledgeMemory[]> {
3295
- const params = new URLSearchParams();
3296
- if (request.query) params.set("query", request.query);
3297
- if (request.status) params.set("status", request.status);
3298
- if (request.kind) params.set("kind", request.kind);
3299
- if (request.scope) params.set("scope", request.scope);
3300
- if (request.limit) params.set("limit", String(request.limit));
3301
- const query = params.toString();
3302
- return await this.requestJson<KnowledgeMemory[]>(
5109
+ request: InstallApiIntegrationRequest,
5110
+ ): Promise<InstalledApiIntegration> {
5111
+ return await this.requestJson<InstalledApiIntegration>(
5112
+ "POST",
5113
+ `/v1/workspaces/${workspaceId}/integrations/install`,
5114
+ request,
5115
+ );
5116
+ }
5117
+
5118
+ async previewApiIntegrationUninstall(
5119
+ workspaceId: string,
5120
+ capabilityId: string,
5121
+ instanceKey: string,
5122
+ ): Promise<ApiIntegrationUninstallPreview> {
5123
+ return await this.requestJson<ApiIntegrationUninstallPreview>(
3303
5124
  "GET",
3304
- `/v1/workspaces/${workspaceId}/knowledge/memories${query ? `?${query}` : ""}`,
5125
+ `/v1/workspaces/${workspaceId}/integrations/${encodeURIComponent(capabilityId)}/instances/${encodeURIComponent(instanceKey)}/uninstall-preview`,
3305
5126
  );
3306
5127
  }
3307
5128
 
3308
- async getKnowledgeMemory(workspaceId: string, memoryId: string): Promise<KnowledgeMemory> {
3309
- return await this.requestJson<KnowledgeMemory>(
5129
+ /** Remove one Integration instance without deleting its Connection or sibling instances. */
5130
+ async uninstallApiIntegration(
5131
+ workspaceId: string,
5132
+ capabilityId: string,
5133
+ instanceKey: string,
5134
+ request: UninstallApiIntegrationRequest,
5135
+ ): Promise<UninstallApiIntegrationResult> {
5136
+ return await this.requestJson<UninstallApiIntegrationResult>(
5137
+ "DELETE",
5138
+ `/v1/workspaces/${workspaceId}/integrations/${encodeURIComponent(capabilityId)}/instances/${encodeURIComponent(instanceKey)}`,
5139
+ request,
5140
+ );
5141
+ }
5142
+
5143
+ /** List immutable provider facets and their exact per-account bindings. */
5144
+ async listIntegrationFacets(
5145
+ workspaceId: string,
5146
+ capabilityId: string,
5147
+ instanceKey: string,
5148
+ ): Promise<IntegrationInstanceFacetsResponse> {
5149
+ return await this.requestJson<IntegrationInstanceFacetsResponse>(
5150
+ "GET",
5151
+ `/v1/workspaces/${workspaceId}/integrations/${encodeURIComponent(capabilityId)}/instances/${encodeURIComponent(instanceKey)}/facets`,
5152
+ );
5153
+ }
5154
+
5155
+ /** Configure or OCC-update one adapter-owned facet on an Integration instance. */
5156
+ async configureIntegrationFacet(
5157
+ workspaceId: string,
5158
+ capabilityId: string,
5159
+ instanceKey: string,
5160
+ facetKey: string,
5161
+ request: UpsertIntegrationFacetRequest,
5162
+ ): Promise<IntegrationFacetMutationResult> {
5163
+ return await this.requestJson<IntegrationFacetMutationResult>(
5164
+ "PUT",
5165
+ `/v1/workspaces/${workspaceId}/integrations/${encodeURIComponent(capabilityId)}/instances/${encodeURIComponent(instanceKey)}/facets/${encodeURIComponent(facetKey)}`,
5166
+ request,
5167
+ );
5168
+ }
5169
+
5170
+ /** Browse source metadata through one exact Google Drive Integration instance. */
5171
+ async browseGoogleDriveFacetSource(
5172
+ workspaceId: string,
5173
+ capabilityId: string,
5174
+ instanceKey: string,
5175
+ facetKey: string,
5176
+ options: {
5177
+ parentId?: string | undefined;
5178
+ pageToken?: string | undefined;
5179
+ } = {},
5180
+ ): Promise<GoogleDriveBrowseResponse> {
5181
+ const query = new URLSearchParams();
5182
+ if (options.parentId) query.set("parentId", options.parentId);
5183
+ if (options.pageToken) query.set("pageToken", options.pageToken);
5184
+ const suffix = query.size > 0 ? `?${query}` : "";
5185
+ return await this.requestJson<GoogleDriveBrowseResponse>(
3310
5186
  "GET",
3311
- `/v1/workspaces/${workspaceId}/knowledge/memories/${memoryId}`,
5187
+ `/v1/workspaces/${workspaceId}/integrations/${encodeURIComponent(capabilityId)}/instances/${encodeURIComponent(instanceKey)}/facets/${encodeURIComponent(facetKey)}/browse${suffix}`,
3312
5188
  );
3313
5189
  }
3314
5190
 
3315
- async createKnowledgeMemory(
5191
+ /** Verify and bind document sources to one exact Google Drive Integration instance. */
5192
+ async saveGoogleDriveFacetSource(
3316
5193
  workspaceId: string,
3317
- request: CreateKnowledgeMemoryRequest,
3318
- ): Promise<KnowledgeMemory> {
3319
- return await this.requestJson<KnowledgeMemory>(
3320
- "POST",
3321
- `/v1/workspaces/${workspaceId}/knowledge/memories`,
5194
+ capabilityId: string,
5195
+ instanceKey: string,
5196
+ facetKey: string,
5197
+ request: SaveGoogleDriveIntegrationSourceRequest,
5198
+ ): Promise<IntegrationFacetMutationResult> {
5199
+ return await this.requestJson<IntegrationFacetMutationResult>(
5200
+ "PUT",
5201
+ `/v1/workspaces/${workspaceId}/integrations/${encodeURIComponent(capabilityId)}/instances/${encodeURIComponent(instanceKey)}/facets/${encodeURIComponent(facetKey)}/source`,
3322
5202
  request,
3323
5203
  );
3324
5204
  }
3325
5205
 
3326
- async updateKnowledgeMemory(
5206
+ async pauseIntegrationFacet(
3327
5207
  workspaceId: string,
3328
- memoryId: string,
3329
- request: UpdateKnowledgeMemoryRequest,
3330
- ): Promise<KnowledgeMemory> {
3331
- return await this.requestJson<KnowledgeMemory>(
3332
- "PATCH",
3333
- `/v1/workspaces/${workspaceId}/knowledge/memories/${memoryId}`,
5208
+ capabilityId: string,
5209
+ instanceKey: string,
5210
+ facetKey: string,
5211
+ request: MutateIntegrationFacetRequest,
5212
+ ): Promise<IntegrationFacetMutationResult> {
5213
+ return await this.mutateIntegrationFacetLifecycle(
5214
+ workspaceId,
5215
+ capabilityId,
5216
+ instanceKey,
5217
+ facetKey,
5218
+ "pause",
3334
5219
  request,
3335
5220
  );
3336
5221
  }
3337
5222
 
3338
- /** Hybrid (semantic + keyword) search over the workspace's agent-visible memory. */
3339
- async searchWorkspaceMemories(
5223
+ async resumeIntegrationFacet(
3340
5224
  workspaceId: string,
3341
- request: WorkspaceMemorySearchRequest,
3342
- ): Promise<WorkspaceMemorySearchResponse> {
3343
- return await this.requestJson<WorkspaceMemorySearchResponse>(
3344
- "POST",
3345
- `/v1/workspaces/${workspaceId}/knowledge/memories/search`,
5225
+ capabilityId: string,
5226
+ instanceKey: string,
5227
+ facetKey: string,
5228
+ request: MutateIntegrationFacetRequest,
5229
+ ): Promise<IntegrationFacetMutationResult> {
5230
+ return await this.mutateIntegrationFacetLifecycle(
5231
+ workspaceId,
5232
+ capabilityId,
5233
+ instanceKey,
5234
+ facetKey,
5235
+ "resume",
3346
5236
  request,
3347
5237
  );
3348
5238
  }
3349
5239
 
3350
- /** Deep-merge a settings patch into the workspace (preserves unknown keys). */
3351
- async updateWorkspaceSettings(
5240
+ async removeIntegrationFacet(
3352
5241
  workspaceId: string,
3353
- request: UpdateWorkspaceSettingsRequest,
3354
- ): Promise<Workspace> {
3355
- return await this.requestJson<Workspace>(
3356
- "PATCH",
3357
- `/v1/workspaces/${workspaceId}/settings`,
5242
+ capabilityId: string,
5243
+ instanceKey: string,
5244
+ facetKey: string,
5245
+ request: MutateIntegrationFacetRequest,
5246
+ ): Promise<IntegrationFacetRemovalResult> {
5247
+ return await this.requestJson<IntegrationFacetRemovalResult>(
5248
+ "DELETE",
5249
+ `/v1/workspaces/${workspaceId}/integrations/${encodeURIComponent(capabilityId)}/instances/${encodeURIComponent(instanceKey)}/facets/${encodeURIComponent(facetKey)}`,
3358
5250
  request,
3359
5251
  );
3360
5252
  }
3361
5253
 
3362
- async setWorkspaceDefaultRig(
5254
+ private async mutateIntegrationFacetLifecycle(
3363
5255
  workspaceId: string,
3364
- request: SetWorkspaceDefaultRigRequest,
3365
- ): Promise<Workspace> {
3366
- return await this.requestJson<Workspace>(
3367
- "PUT",
3368
- `/v1/workspaces/${workspaceId}/default-rig`,
5256
+ capabilityId: string,
5257
+ instanceKey: string,
5258
+ facetKey: string,
5259
+ action: "pause" | "resume",
5260
+ request: MutateIntegrationFacetRequest,
5261
+ ): Promise<IntegrationFacetMutationResult> {
5262
+ return await this.requestJson<IntegrationFacetMutationResult>(
5263
+ "POST",
5264
+ `/v1/workspaces/${workspaceId}/integrations/${encodeURIComponent(capabilityId)}/instances/${encodeURIComponent(instanceKey)}/facets/${encodeURIComponent(facetKey)}/${action}`,
3369
5265
  request,
3370
5266
  );
3371
5267
  }
3372
5268
 
3373
- // --- Capability packs ------------------------------------------------------------------
3374
-
3375
- /** Built-in + registered packs, with the workspace's installations. */
3376
- async listPacks(workspaceId: string): Promise<ListPacksResponse> {
3377
- return await this.requestJson<ListPacksResponse>("GET", `/v1/workspaces/${workspaceId}/packs`);
3378
- }
3379
-
3380
- /** Register (or replace) a workspace-scoped pack from a manifest. */
3381
- async registerPack(
3382
- workspaceId: string,
3383
- manifest: RegisterCapabilityPackRequest,
3384
- ): Promise<WorkspaceRegisteredPack> {
3385
- return await this.requestJson<WorkspaceRegisteredPack>(
5269
+ async previewPlugin(workspaceId: string, request: PreviewPluginRequest): Promise<PluginPreview> {
5270
+ return await this.requestJson<PluginPreview>(
3386
5271
  "POST",
3387
- `/v1/workspaces/${workspaceId}/packs`,
3388
- manifest,
5272
+ `/v1/workspaces/${workspaceId}/plugins/preview`,
5273
+ request,
3389
5274
  );
3390
5275
  }
3391
5276
 
3392
- async getPack(workspaceId: string, packId: string): Promise<GetPackResponse> {
3393
- return await this.requestJson<GetPackResponse>(
5277
+ async listInstalledPlugins(workspaceId: string): Promise<ListInstalledPluginsResponse> {
5278
+ return await this.requestJson<ListInstalledPluginsResponse>(
3394
5279
  "GET",
3395
- `/v1/workspaces/${workspaceId}/packs/${encodeURIComponent(packId)}`,
5280
+ `/v1/workspaces/${workspaceId}/plugins`,
3396
5281
  );
3397
5282
  }
3398
5283
 
3399
- async enablePack(
5284
+ async installPlugin(
3400
5285
  workspaceId: string,
3401
- packId: string,
3402
- request: EnablePackRequest = {},
3403
- ): Promise<PackInstallation> {
3404
- return await this.requestJson<PackInstallation>(
5286
+ request: InstallPluginRequest,
5287
+ ): Promise<InstalledPlugin> {
5288
+ return await this.requestJson<InstalledPlugin>(
3405
5289
  "POST",
3406
- `/v1/workspaces/${workspaceId}/packs/${encodeURIComponent(packId)}/enable`,
5290
+ `/v1/workspaces/${workspaceId}/plugins/install`,
3407
5291
  request,
3408
5292
  );
3409
5293
  }
3410
5294
 
3411
- /** Unregister a workspace-scoped pack (built-in packs cannot be deleted). */
3412
- async deletePack(workspaceId: string, packId: string): Promise<void> {
3413
- await this.requestVoid(
3414
- "DELETE",
3415
- `/v1/workspaces/${workspaceId}/packs/${encodeURIComponent(packId)}`,
5295
+ async previewPluginUninstall(
5296
+ workspaceId: string,
5297
+ pluginKey: string,
5298
+ ): Promise<PluginUninstallPreview> {
5299
+ return await this.requestJson<PluginUninstallPreview>(
5300
+ "GET",
5301
+ `/v1/workspaces/${workspaceId}/plugins/${encodeURIComponent(pluginKey)}/uninstall-preview`,
3416
5302
  );
3417
5303
  }
3418
5304
 
3419
- async listPackInstallations(workspaceId: string): Promise<PackInstallation[]> {
3420
- return await this.requestJson<PackInstallation[]>(
3421
- "GET",
3422
- `/v1/workspaces/${workspaceId}/packs/installations`,
5305
+ async uninstallPlugin(
5306
+ workspaceId: string,
5307
+ pluginKey: string,
5308
+ request: UninstallPluginRequest,
5309
+ ): Promise<UninstallPluginResult> {
5310
+ return await this.requestJson<UninstallPluginResult>(
5311
+ "DELETE",
5312
+ `/v1/workspaces/${workspaceId}/plugins/${encodeURIComponent(pluginKey)}`,
5313
+ request,
3423
5314
  );
3424
5315
  }
3425
5316
 
3426
- // --- Capabilities -------------------------------------------------------------------------
3427
-
3428
- async listCapabilities(workspaceId: string): Promise<CapabilityCatalogResponse> {
3429
- return await this.requestJson<CapabilityCatalogResponse>(
3430
- "GET",
3431
- `/v1/workspaces/${workspaceId}/capabilities`,
5317
+ /** Resolve one public skills.sh or GitHub Skill folder to an immutable review preview. */
5318
+ async previewSkillImport(
5319
+ workspaceId: string,
5320
+ request: PreviewSkillImportRequest,
5321
+ ): Promise<SkillImportPreview> {
5322
+ return await this.requestJson<SkillImportPreview>(
5323
+ "POST",
5324
+ `/v1/workspaces/${workspaceId}/skills/preview`,
5325
+ request,
3432
5326
  );
3433
5327
  }
3434
5328
 
3435
- /** Add a manual capability catalog item (e.g. a remote MCP server). */
3436
- async createCapability(
3437
- workspaceId: string,
3438
- request: CreateCapabilityCatalogItemRequest,
3439
- ): Promise<CapabilityCatalogItem> {
3440
- return await this.requestJson<CapabilityCatalogItem>(
5329
+ /** Install only the exact commit and full-content digest accepted during preview. */
5330
+ async installSkill(workspaceId: string, request: InstallSkillRequest): Promise<InstalledSkill> {
5331
+ return await this.requestJson<InstalledSkill>(
3441
5332
  "POST",
3442
- `/v1/workspaces/${workspaceId}/capabilities`,
5333
+ `/v1/workspaces/${workspaceId}/skills/install`,
3443
5334
  request,
3444
5335
  );
3445
5336
  }
3446
5337
 
3447
- async enableCapability(
5338
+ /** List Skills from the authoritative Plugin/Skill-Facet installation ledger. */
5339
+ async listInstalledSkills(workspaceId: string): Promise<ListInstalledSkillsResponse> {
5340
+ return await this.requestJson<ListInstalledSkillsResponse>(
5341
+ "GET",
5342
+ `/v1/workspaces/${workspaceId}/skills`,
5343
+ );
5344
+ }
5345
+
5346
+ /** Install one exact reviewed curated-library Skill through the Skill domain. */
5347
+ async installLibrarySkill(
3448
5348
  workspaceId: string,
3449
- capabilityId: string,
3450
- request: EnableCapabilityRequest = {},
3451
- ): Promise<CapabilityInstallation> {
3452
- return await this.requestJson<CapabilityInstallation>(
5349
+ libraryId: string,
5350
+ request: InstallLibrarySkillRequest,
5351
+ ): Promise<InstalledSkill> {
5352
+ return await this.requestJson<InstalledSkill>(
3453
5353
  "POST",
3454
- `/v1/workspaces/${workspaceId}/capabilities/${encodeURIComponent(capabilityId)}/enable`,
5354
+ `/v1/workspaces/${workspaceId}/skills/library/${encodeURIComponent(libraryId)}/install`,
3455
5355
  request,
3456
5356
  );
3457
5357
  }
3458
5358
 
3459
- async disableCapability(
5359
+ async previewSkillUninstall(
3460
5360
  workspaceId: string,
3461
5361
  capabilityId: string,
3462
- ): Promise<CapabilityInstallation> {
3463
- return await this.requestJson<CapabilityInstallation>(
3464
- "POST",
3465
- `/v1/workspaces/${workspaceId}/capabilities/${encodeURIComponent(capabilityId)}/disable`,
5362
+ ): Promise<SkillUninstallPreview> {
5363
+ return await this.requestJson<SkillUninstallPreview>(
5364
+ "GET",
5365
+ `/v1/workspaces/${workspaceId}/skills/${encodeURIComponent(capabilityId)}/uninstall-preview`,
3466
5366
  );
3467
5367
  }
3468
5368
 
3469
- /** Search the official MCP registry for installable capabilities. */
3470
- async discoverMcpCapabilities(
5369
+ /** Remove the direct owner under an optimistic installation-version fence. */
5370
+ async uninstallSkill(
3471
5371
  workspaceId: string,
3472
- options: { query?: string; limit?: number } = {},
3473
- ): Promise<DiscoverMcpCapabilitiesResponse> {
3474
- return await this.requestJson<DiscoverMcpCapabilitiesResponse>(
3475
- "GET",
3476
- `/v1/workspaces/${workspaceId}/capabilities/discovery/mcp-registry`,
3477
- undefined,
3478
- {
3479
- ...(options.query !== undefined ? { query: options.query } : {}),
3480
- ...(options.limit !== undefined ? { limit: String(options.limit) } : {}),
3481
- },
5372
+ capabilityId: string,
5373
+ request: UninstallSkillRequest,
5374
+ ): Promise<UninstallSkillResult> {
5375
+ return await this.requestJson<UninstallSkillResult>(
5376
+ "DELETE",
5377
+ `/v1/workspaces/${workspaceId}/skills/${encodeURIComponent(capabilityId)}`,
5378
+ request,
3482
5379
  );
3483
5380
  }
3484
5381
 
@@ -3492,6 +5389,15 @@ export class OpenGeniClient {
3492
5389
  return response.connections;
3493
5390
  }
3494
5391
 
5392
+ /** List the secret-free Slack team -> OpenGeni tenant routing authority. */
5393
+ async listSlackInstallationBindings(workspaceId: string): Promise<SlackInstallationBinding[]> {
5394
+ const response = await this.requestJson<ListSlackInstallationBindingsResponse>(
5395
+ "GET",
5396
+ `/v1/workspaces/${workspaceId}/connections/slack-bot/bindings`,
5397
+ );
5398
+ return response.bindings;
5399
+ }
5400
+
3495
5401
  async createConnection(
3496
5402
  workspaceId: string,
3497
5403
  request: CreateConnectionRequest,
@@ -3504,6 +5410,34 @@ export class OpenGeniClient {
3504
5410
  return response.connection;
3505
5411
  }
3506
5412
 
5413
+ /**
5414
+ * Verify a pasted Fiken personal API token and store it as the
5415
+ * workspace-shared Fiken connection (or rewrite an existing one in place).
5416
+ */
5417
+ async installFikenConnection(
5418
+ workspaceId: string,
5419
+ request: FikenInstallRequest,
5420
+ ): Promise<ConnectionMetadata> {
5421
+ const response = await this.requestJson<ConnectionResponse>(
5422
+ "POST",
5423
+ `/v1/workspaces/${workspaceId}/connections/fiken/install`,
5424
+ request,
5425
+ );
5426
+ return response.connection;
5427
+ }
5428
+
5429
+ /** Start the Fiken OAuth flow for the workspace-shared Fiken connection. */
5430
+ async startFikenOAuth(
5431
+ workspaceId: string,
5432
+ request: FikenOAuthStartRequest = {},
5433
+ ): Promise<FikenOAuthStartResponse> {
5434
+ return await this.requestJson<FikenOAuthStartResponse>(
5435
+ "POST",
5436
+ `/v1/workspaces/${workspaceId}/connections/fiken/oauth/start`,
5437
+ request,
5438
+ );
5439
+ }
5440
+
3507
5441
  /** Start the public Slack installation flow for the workspace-shared OpenGeni bot. */
3508
5442
  async startOpenGeniSlackBotInstall(
3509
5443
  workspaceId: string,
@@ -3634,8 +5568,16 @@ export class OpenGeniClient {
3634
5568
  // --- GitHub ----------------------------------------------------------------------------------
3635
5569
 
3636
5570
  /** GitHub App server configuration plus truthful workspace binding status. */
3637
- async getGitHubApp(workspaceId: string): Promise<GitHubAppInfo> {
3638
- return await this.requestJson<GitHubAppInfo>("GET", `/v1/workspaces/${workspaceId}/github/app`);
5571
+ async getGitHubApp(
5572
+ workspaceId: string,
5573
+ options: { returnPath?: string } = {},
5574
+ ): Promise<GitHubAppInfo> {
5575
+ return await this.requestJson<GitHubAppInfo>(
5576
+ "GET",
5577
+ `/v1/workspaces/${workspaceId}/github/app`,
5578
+ undefined,
5579
+ options.returnPath ? { returnPath: options.returnPath } : undefined,
5580
+ );
3639
5581
  }
3640
5582
 
3641
5583
  /** Build the GitHub owner-consent entry URL for fresh workspace-bound state. */
@@ -3955,7 +5897,99 @@ export class OpenGeniClient {
3955
5897
  );
3956
5898
  }
3957
5899
 
3958
- protected async requestJson<T>(
5900
+ // --- SuperGrok/xAI connected subscriptions ------------------------------------------------------
5901
+
5902
+ async supergrokStatus(workspaceId: string): Promise<SuperGrokConnectionStatus> {
5903
+ return await this.requestJson<SuperGrokConnectionStatus>(
5904
+ "GET",
5905
+ `/v1/workspaces/${workspaceId}/supergrok/status`,
5906
+ );
5907
+ }
5908
+
5909
+ async supergrokConnectStart(
5910
+ workspaceId: string,
5911
+ scope: SuperGrokAccountScope = "workspace",
5912
+ ): Promise<SuperGrokConnectStart> {
5913
+ return await this.requestJson<SuperGrokConnectStart>(
5914
+ "POST",
5915
+ `/v1/workspaces/${workspaceId}/supergrok/connect/start`,
5916
+ { scope },
5917
+ );
5918
+ }
5919
+
5920
+ async supergrokConnectPoll(workspaceId: string, state: string): Promise<SuperGrokConnectPoll> {
5921
+ return await this.requestJson<SuperGrokConnectPoll>(
5922
+ "POST",
5923
+ `/v1/workspaces/${workspaceId}/supergrok/connect/poll`,
5924
+ { state },
5925
+ );
5926
+ }
5927
+
5928
+ async listSuperGrokAccounts(workspaceId: string): Promise<SuperGrokAccountsResponse> {
5929
+ return await this.requestJson<SuperGrokAccountsResponse>(
5930
+ "GET",
5931
+ `/v1/workspaces/${workspaceId}/supergrok/accounts`,
5932
+ );
5933
+ }
5934
+
5935
+ async activateSuperGrokAccount(
5936
+ workspaceId: string,
5937
+ accountId: string,
5938
+ ): Promise<{ activated: boolean; accountId: string }> {
5939
+ return await this.requestJson<{ activated: boolean; accountId: string }>(
5940
+ "POST",
5941
+ `/v1/workspaces/${workspaceId}/supergrok/accounts/${accountId}/activate`,
5942
+ {},
5943
+ );
5944
+ }
5945
+
5946
+ async setSuperGrokRotationSettings(
5947
+ workspaceId: string,
5948
+ patch: { rotationEnabled: boolean },
5949
+ ): Promise<SuperGrokRotationSettings> {
5950
+ return await this.requestJson<SuperGrokRotationSettings>(
5951
+ "PATCH",
5952
+ `/v1/workspaces/${workspaceId}/supergrok/settings`,
5953
+ patch,
5954
+ );
5955
+ }
5956
+
5957
+ async setSuperGrokAccountAllocator(
5958
+ workspaceId: string,
5959
+ accountId: string,
5960
+ input: { enabled: boolean; expectedVersion: number },
5961
+ ): Promise<SuperGrokAllocatorUpdate> {
5962
+ return await this.requestJson<SuperGrokAllocatorUpdate>(
5963
+ "PATCH",
5964
+ `/v1/workspaces/${workspaceId}/supergrok/accounts/${accountId}/allocator`,
5965
+ input,
5966
+ );
5967
+ }
5968
+
5969
+ async renameSuperGrokAccount(
5970
+ workspaceId: string,
5971
+ accountId: string,
5972
+ label: string | null,
5973
+ ): Promise<SuperGrokAccount> {
5974
+ return await this.requestJson<SuperGrokAccount>(
5975
+ "PATCH",
5976
+ `/v1/workspaces/${workspaceId}/supergrok/accounts/${accountId}`,
5977
+ { label },
5978
+ );
5979
+ }
5980
+
5981
+ async disconnectSuperGrokAccount(
5982
+ workspaceId: string,
5983
+ accountId: string,
5984
+ ): Promise<{ disconnected: boolean; newActiveId: string | null }> {
5985
+ return await this.requestJson<{
5986
+ disconnected: boolean;
5987
+ newActiveId: string | null;
5988
+ }>("DELETE", `/v1/workspaces/${workspaceId}/supergrok/accounts/${accountId}`, {});
5989
+ }
5990
+
5991
+ /** Contract-checked JSON transport shared by opt-in typed SDK clients. */
5992
+ async requestJson<T>(
3959
5993
  method: string,
3960
5994
  path: string,
3961
5995
  body?: unknown,
@@ -3996,6 +6030,35 @@ export class OpenGeniClient {
3996
6030
  }
3997
6031
  }
3998
6032
 
6033
+ /** Authenticated, contract-checked response for bounded streaming downloads. */
6034
+ protected async requestResponse(
6035
+ method: string,
6036
+ path: string,
6037
+ query: Record<string, string> = {},
6038
+ options: OpenGeniRequestOptions = {},
6039
+ ): Promise<Response> {
6040
+ const correlationId = crypto.randomUUID();
6041
+ let response: Response;
6042
+ try {
6043
+ response = await this.fetchImpl(this.url(path, query), {
6044
+ method,
6045
+ headers: {
6046
+ ...this.headers(correlationId),
6047
+ Accept: "application/octet-stream",
6048
+ },
6049
+ ...(options.signal ? { signal: options.signal } : {}),
6050
+ });
6051
+ } catch (error) {
6052
+ if (isMutationMethod(method)) throw mutationTransportError(correlationId);
6053
+ throw error;
6054
+ }
6055
+ assertApiContractResponse(response);
6056
+ if (!response.ok) {
6057
+ throw await apiErrorFromResponse(response, { method, correlationId });
6058
+ }
6059
+ return response;
6060
+ }
6061
+
3999
6062
  /** Like `requestJson` for endpoints that respond with no body (204). */
4000
6063
  private async requestVoid(method: string, path: string, body?: unknown): Promise<void> {
4001
6064
  const correlationId = crypto.randomUUID();
@@ -4235,6 +6298,55 @@ async function cancelResponseBody(response: Response, reason: string): Promise<v
4235
6298
  await response.body?.cancel(reason).catch(() => undefined);
4236
6299
  }
4237
6300
 
6301
+ function assertRetainedGeneratedImageReceipt(
6302
+ workspaceId: string,
6303
+ artifact: RetainedArtifactReference,
6304
+ ): void {
6305
+ if (!parseRetainedGeneratedImageReference(artifact, workspaceId)) {
6306
+ throw new OpenGeniApiError(502, "retained generated image receipt is invalid");
6307
+ }
6308
+ }
6309
+
6310
+ function assertSafeArtifactDownloadUrl(value: FileDownloadUrlResponse): void {
6311
+ if (
6312
+ !value ||
6313
+ typeof value.url !== "string" ||
6314
+ typeof value.expiresAt !== "string" ||
6315
+ !Number.isFinite(Date.parse(value.expiresAt))
6316
+ ) {
6317
+ throw new OpenGeniApiError(502, "retained artifact download URL is invalid");
6318
+ }
6319
+ let parsed: URL;
6320
+ try {
6321
+ parsed = new URL(value.url);
6322
+ } catch {
6323
+ throw new OpenGeniApiError(502, "retained artifact download URL is invalid");
6324
+ }
6325
+ if (!["http:", "https:"].includes(parsed.protocol) || parsed.username || parsed.password) {
6326
+ throw new OpenGeniApiError(502, "retained artifact download URL is unsafe");
6327
+ }
6328
+ }
6329
+
6330
+ function assertSafeVideoArtifactPlaybackSource(
6331
+ value: VideoArtifactPlaybackSource,
6332
+ expectedArtifactId: string,
6333
+ ): void {
6334
+ if (
6335
+ !value ||
6336
+ value.schemaVersion !== 1 ||
6337
+ value.artifactId !== expectedArtifactId ||
6338
+ value.contentType !== "video/mp4" ||
6339
+ value.acceptRanges !== "bytes" ||
6340
+ !Number.isSafeInteger(value.sizeBytes) ||
6341
+ value.sizeBytes <= 0 ||
6342
+ value.sizeBytes > GENERATED_VIDEO_MAX_BYTES ||
6343
+ !/^[0-9a-f]{64}$/.test(value.sha256)
6344
+ ) {
6345
+ throw new OpenGeniApiError(502, "generated-video playback source is invalid");
6346
+ }
6347
+ assertSafeArtifactDownloadUrl({ url: value.url, expiresAt: value.expiresAt });
6348
+ }
6349
+
4238
6350
  function parseBoundedContentLength(value: string | null): number | null {
4239
6351
  if (value === null) return null;
4240
6352
  if (!/^\d+$/.test(value)) {