@opengeni/sdk 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.ts +543 -80
- package/dist/index.js +753 -184
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
- package/src/client.ts +1242 -341
- package/src/errors.ts +7 -1
- package/src/index.ts +54 -4
- package/src/proxy.ts +1 -1
- package/src/sse.ts +11 -8
- package/src/stream.ts +6 -2
- package/src/types.ts +793 -101
package/src/client.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { OpenGeniApiError } from "./errors";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
streamSessionEvents,
|
|
4
|
+
type SessionEventStreamTransport,
|
|
5
|
+
type StreamSessionEventsOptions,
|
|
6
|
+
} from "./stream";
|
|
3
7
|
import type {
|
|
4
8
|
AccessContext,
|
|
5
9
|
AddWorkspaceMemberRequest,
|
|
@@ -23,11 +27,13 @@ import type {
|
|
|
23
27
|
ClientSessionEventInput,
|
|
24
28
|
CompactSessionContextResult,
|
|
25
29
|
CompleteFileUploadResponse,
|
|
30
|
+
ConnectionMetadata,
|
|
26
31
|
CreateApiKeyRequest,
|
|
27
32
|
CreateApiKeyResponse,
|
|
28
33
|
CreateCapabilityCatalogItemRequest,
|
|
29
34
|
CreateCheckoutRequest,
|
|
30
35
|
CreateCheckoutResponse,
|
|
36
|
+
CreateConnectionRequest,
|
|
31
37
|
CreateDocumentBaseRequest,
|
|
32
38
|
CreateFileUploadRequest,
|
|
33
39
|
CreateFileUploadResponse,
|
|
@@ -36,7 +42,8 @@ import type {
|
|
|
36
42
|
CreateKnowledgeMemoryRequest,
|
|
37
43
|
CreateScheduledTaskRequest,
|
|
38
44
|
CreateSessionRequest,
|
|
39
|
-
|
|
45
|
+
CreateVariableSetRequest,
|
|
46
|
+
CreateRigRequest,
|
|
40
47
|
CreateWorkspaceRequest,
|
|
41
48
|
// Enrollment UX (design 11): the click-Grant approve-page lookup/deny + headless
|
|
42
49
|
// enroll-token mint.
|
|
@@ -62,7 +69,6 @@ import type {
|
|
|
62
69
|
ListPacksResponse,
|
|
63
70
|
// Bring-your-own-compute: the Machines dashboard + per-machine metrics (M10).
|
|
64
71
|
MachinesResponse,
|
|
65
|
-
MachineView,
|
|
66
72
|
MetricSample,
|
|
67
73
|
MachineMetricsSeriesResponse,
|
|
68
74
|
// Bring-your-own-compute: the user-authenticated active-sandbox swap (M7).
|
|
@@ -76,8 +82,16 @@ import type {
|
|
|
76
82
|
ScheduledTask,
|
|
77
83
|
ScheduledTaskRun,
|
|
78
84
|
Session,
|
|
85
|
+
SessionListResponse,
|
|
86
|
+
UpdateSessionPinRequest,
|
|
79
87
|
SessionEvent,
|
|
80
88
|
SessionGoal,
|
|
89
|
+
SessionLineageResponse,
|
|
90
|
+
SessionMcpCredentialUpdateInput,
|
|
91
|
+
SessionQueueSnapshot,
|
|
92
|
+
SessionQueueMutationResponse,
|
|
93
|
+
SessionControlResponse,
|
|
94
|
+
WorkspaceInferenceControlResponse,
|
|
81
95
|
SessionTurn,
|
|
82
96
|
// Stream surfacing (Phase 5): capability negotiation + viewer lifecycle + config.
|
|
83
97
|
SessionCapabilities,
|
|
@@ -108,6 +122,9 @@ import type {
|
|
|
108
122
|
GitLogResponse,
|
|
109
123
|
GitShowRequest,
|
|
110
124
|
GitShowResponse,
|
|
125
|
+
// Workbench v2 turn-end capture reads (M2, dossier §10.3).
|
|
126
|
+
GetWorkspaceCaptureResponse,
|
|
127
|
+
GetWorkspaceCaptureFileResponse,
|
|
111
128
|
TerminalExecRequest,
|
|
112
129
|
TerminalExecResponse,
|
|
113
130
|
PtyOpenRequest,
|
|
@@ -116,20 +133,33 @@ import type {
|
|
|
116
133
|
PtyResizeRequest,
|
|
117
134
|
PtyCloseRequest,
|
|
118
135
|
ToolRef,
|
|
136
|
+
UpdateConnectionRequest,
|
|
119
137
|
UpdateKnowledgeMemoryRequest,
|
|
120
138
|
UpdateScheduledTaskRequest,
|
|
121
139
|
UpdateSessionGoalRequest,
|
|
122
140
|
UpdateSessionRequest,
|
|
123
|
-
|
|
124
|
-
|
|
141
|
+
UpdateVariableSetRequest,
|
|
142
|
+
UpdateRigRequest,
|
|
125
143
|
UpdateWorkspaceMemberRequest,
|
|
126
144
|
UpdateWorkspaceRequest,
|
|
145
|
+
UpdateWorkspaceSettingsRequest,
|
|
146
|
+
SetWorkspaceDefaultRigRequest,
|
|
127
147
|
UploadFileInput,
|
|
128
|
-
|
|
129
|
-
|
|
148
|
+
VariableSet,
|
|
149
|
+
VariableSetVariableMetadata,
|
|
150
|
+
Rig,
|
|
151
|
+
RigVersion,
|
|
152
|
+
RigChange,
|
|
153
|
+
ProposeRigChangeRequest,
|
|
130
154
|
WorkspaceMember,
|
|
155
|
+
WorkspaceMemorySearchRequest,
|
|
156
|
+
WorkspaceMemorySearchResponse,
|
|
131
157
|
WorkspaceRegisteredPack,
|
|
132
158
|
Workspace,
|
|
159
|
+
ListConnectionsResponse,
|
|
160
|
+
ConnectionResponse,
|
|
161
|
+
OAuthStartRequest,
|
|
162
|
+
OAuthStartResponse,
|
|
133
163
|
} from "./types";
|
|
134
164
|
|
|
135
165
|
export type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
@@ -152,19 +182,16 @@ export type SendMessageInput = {
|
|
|
152
182
|
model?: string;
|
|
153
183
|
reasoningEffort?: ReasoningEffort;
|
|
154
184
|
clientEventId?: string;
|
|
185
|
+
expectedControlGeneration?: number;
|
|
186
|
+
expectedWorkspaceInferenceGeneration?: number;
|
|
187
|
+
mcpCredentialUpdates?: SessionMcpCredentialUpdateInput[];
|
|
155
188
|
};
|
|
156
189
|
|
|
157
190
|
export type SteerMessageResult = {
|
|
158
191
|
/** The accepted `user.message` event. */
|
|
159
192
|
accepted: SessionEvent;
|
|
160
|
-
/**
|
|
161
|
-
|
|
162
|
-
* still queued, but already claimed (running/requires_action or even
|
|
163
|
-
* finished) when the worker picked it up mid-call.
|
|
164
|
-
*/
|
|
165
|
-
turn: SessionTurn | null;
|
|
166
|
-
/** True when the running turn was interrupted to make way for the message. */
|
|
167
|
-
interrupted: boolean;
|
|
193
|
+
/** The exact turn created for this message in the same server transaction. */
|
|
194
|
+
turn: SessionTurn;
|
|
168
195
|
};
|
|
169
196
|
|
|
170
197
|
/**
|
|
@@ -180,34 +207,145 @@ export class OpenGeniClient {
|
|
|
180
207
|
constructor(options: OpenGeniClientOptions) {
|
|
181
208
|
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
182
209
|
this.options = options;
|
|
183
|
-
// Bind lazily so
|
|
210
|
+
// Bind lazily so variable sets that polyfill fetch after module load work.
|
|
184
211
|
this.fetchImpl = options.fetch ?? ((input, init) => fetch(input, init));
|
|
185
212
|
}
|
|
186
213
|
|
|
187
214
|
// --- Session lifecycle ---------------------------------------------------
|
|
188
215
|
|
|
189
216
|
async createSession(workspaceId: string, request: CreateSessionRequest): Promise<Session> {
|
|
190
|
-
return await this.requestJson<Session>(
|
|
217
|
+
return await this.requestJson<Session>(
|
|
218
|
+
"POST",
|
|
219
|
+
`/v1/workspaces/${workspaceId}/sessions`,
|
|
220
|
+
request,
|
|
221
|
+
);
|
|
191
222
|
}
|
|
192
223
|
|
|
193
224
|
async getSession(workspaceId: string, sessionId: string): Promise<Session> {
|
|
194
|
-
return await this.requestJson<Session>(
|
|
225
|
+
return await this.requestJson<Session>(
|
|
226
|
+
"GET",
|
|
227
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}`,
|
|
228
|
+
);
|
|
195
229
|
}
|
|
196
230
|
|
|
197
|
-
async updateSession(
|
|
198
|
-
|
|
231
|
+
async updateSession(
|
|
232
|
+
workspaceId: string,
|
|
233
|
+
sessionId: string,
|
|
234
|
+
request: UpdateSessionRequest,
|
|
235
|
+
): Promise<Session> {
|
|
236
|
+
return await this.requestJson<Session>(
|
|
237
|
+
"PATCH",
|
|
238
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}`,
|
|
239
|
+
request,
|
|
240
|
+
);
|
|
199
241
|
}
|
|
200
242
|
|
|
201
|
-
async listSessions(
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
243
|
+
async listSessions(
|
|
244
|
+
workspaceId: string,
|
|
245
|
+
options: {
|
|
246
|
+
limit?: number;
|
|
247
|
+
parentSessionId?: string | null;
|
|
248
|
+
search?: string;
|
|
249
|
+
} = {},
|
|
250
|
+
): Promise<Session[]> {
|
|
251
|
+
return await this.requestJson<Session[]>(
|
|
252
|
+
"GET",
|
|
253
|
+
`/v1/workspaces/${workspaceId}/sessions`,
|
|
254
|
+
undefined,
|
|
255
|
+
{
|
|
256
|
+
...(options.limit !== undefined ? { limit: String(options.limit) } : {}),
|
|
257
|
+
...(options.search?.trim() ? { search: options.search.trim() } : {}),
|
|
258
|
+
...(Object.prototype.hasOwnProperty.call(options, "parentSessionId") &&
|
|
259
|
+
options.parentSessionId !== undefined
|
|
260
|
+
? {
|
|
261
|
+
parentSessionId:
|
|
262
|
+
options.parentSessionId === null ? "null" : String(options.parentSessionId),
|
|
263
|
+
}
|
|
264
|
+
: {}),
|
|
265
|
+
},
|
|
266
|
+
);
|
|
205
267
|
}
|
|
206
268
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
269
|
+
/** Pin-aware ordinary-session page with a stable keyset cursor. */
|
|
270
|
+
async listSessionPage(
|
|
271
|
+
workspaceId: string,
|
|
272
|
+
options: {
|
|
273
|
+
limit?: number;
|
|
274
|
+
parentSessionId?: string | null;
|
|
275
|
+
cursor?: string;
|
|
276
|
+
search?: string;
|
|
277
|
+
} = {},
|
|
278
|
+
): Promise<SessionListResponse> {
|
|
279
|
+
const response = await this.requestJson<SessionListResponse | Session[]>(
|
|
280
|
+
"GET",
|
|
281
|
+
`/v1/workspaces/${workspaceId}/sessions`,
|
|
282
|
+
undefined,
|
|
283
|
+
{
|
|
284
|
+
view: "page",
|
|
285
|
+
...(options.limit !== undefined ? { limit: String(options.limit) } : {}),
|
|
286
|
+
...(options.cursor !== undefined ? { cursor: options.cursor } : {}),
|
|
287
|
+
...(options.search?.trim() ? { search: options.search.trim() } : {}),
|
|
288
|
+
...(Object.prototype.hasOwnProperty.call(options, "parentSessionId") &&
|
|
289
|
+
options.parentSessionId !== undefined
|
|
290
|
+
? {
|
|
291
|
+
parentSessionId:
|
|
292
|
+
options.parentSessionId === null ? "null" : String(options.parentSessionId),
|
|
293
|
+
}
|
|
294
|
+
: {}),
|
|
295
|
+
},
|
|
296
|
+
);
|
|
297
|
+
if (Array.isArray(response)) {
|
|
298
|
+
// Rolling/same-major compatibility: an older API ignores `view=page` and
|
|
299
|
+
// returns the historical array. That is an honest one-page projection;
|
|
300
|
+
// never pretend it honored a cursor supplied directly by a caller.
|
|
301
|
+
if (options.cursor) {
|
|
302
|
+
throw new Error("The connected OpenGeni API does not support stable session-page cursors");
|
|
303
|
+
}
|
|
304
|
+
// Older APIs ignore unknown query parameters. Treating their unfiltered
|
|
305
|
+
// array as a successful search would be worse than an explicit rolling-
|
|
306
|
+
// upgrade error (and client-side filtering cannot recover matches beyond
|
|
307
|
+
// the old endpoint's bounded first page).
|
|
308
|
+
if (options.search?.trim()) {
|
|
309
|
+
throw new Error("The connected OpenGeni API does not support session search");
|
|
310
|
+
}
|
|
311
|
+
return { pinned: [], sessions: response, nextCursor: null };
|
|
312
|
+
}
|
|
313
|
+
return response;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/** Set this authenticated member's personal workspace pin for a session. */
|
|
317
|
+
async updateSessionPin(
|
|
318
|
+
workspaceId: string,
|
|
319
|
+
sessionId: string,
|
|
320
|
+
request: UpdateSessionPinRequest,
|
|
321
|
+
): Promise<Session> {
|
|
322
|
+
return await this.requestJson<Session>(
|
|
323
|
+
"PUT",
|
|
324
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/pin`,
|
|
325
|
+
request,
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
async getSessionLineage(workspaceId: string, sessionId: string): Promise<SessionLineageResponse> {
|
|
330
|
+
return await this.requestJson<SessionLineageResponse>(
|
|
331
|
+
"GET",
|
|
332
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/lineage`,
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
async listTurns(
|
|
337
|
+
workspaceId: string,
|
|
338
|
+
sessionId: string,
|
|
339
|
+
options: { limit?: number } = {},
|
|
340
|
+
): Promise<SessionTurn[]> {
|
|
341
|
+
return await this.requestJson<SessionTurn[]>(
|
|
342
|
+
"GET",
|
|
343
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/turns`,
|
|
344
|
+
undefined,
|
|
345
|
+
{
|
|
346
|
+
...(options.limit !== undefined ? { limit: String(options.limit) } : {}),
|
|
347
|
+
},
|
|
348
|
+
);
|
|
211
349
|
}
|
|
212
350
|
|
|
213
351
|
// --- Bring-your-own-compute: Machines dashboard + metrics (M10) ------------
|
|
@@ -218,10 +356,18 @@ export class OpenGeniClient {
|
|
|
218
356
|
* sharedSessionCount. Pass `sessionId` for an in-session view, which adds the
|
|
219
357
|
* session's synthetic Modal group box + the active-sandbox pointer.
|
|
220
358
|
*/
|
|
221
|
-
async listMachines(
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
359
|
+
async listMachines(
|
|
360
|
+
workspaceId: string,
|
|
361
|
+
options: { sessionId?: string } = {},
|
|
362
|
+
): Promise<MachinesResponse> {
|
|
363
|
+
return await this.requestJson<MachinesResponse>(
|
|
364
|
+
"GET",
|
|
365
|
+
`/v1/workspaces/${workspaceId}/machines`,
|
|
366
|
+
undefined,
|
|
367
|
+
{
|
|
368
|
+
...(options.sessionId !== undefined ? { sessionId: options.sessionId } : {}),
|
|
369
|
+
},
|
|
370
|
+
);
|
|
225
371
|
}
|
|
226
372
|
|
|
227
373
|
/**
|
|
@@ -254,7 +400,11 @@ export class OpenGeniClient {
|
|
|
254
400
|
* the request.
|
|
255
401
|
*/
|
|
256
402
|
async lookupDeviceEnrollment(userCode: string): Promise<DeviceEnrollmentLookupResponse> {
|
|
257
|
-
return await this.requestJson<DeviceEnrollmentLookupResponse>(
|
|
403
|
+
return await this.requestJson<DeviceEnrollmentLookupResponse>(
|
|
404
|
+
"POST",
|
|
405
|
+
"/v1/enrollments/device/lookup",
|
|
406
|
+
{ userCode },
|
|
407
|
+
);
|
|
258
408
|
}
|
|
259
409
|
|
|
260
410
|
/**
|
|
@@ -324,14 +474,25 @@ export class OpenGeniClient {
|
|
|
324
474
|
|
|
325
475
|
// --- Scheduled tasks -------------------------------------------------------
|
|
326
476
|
|
|
327
|
-
async listScheduledTasks(
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
477
|
+
async listScheduledTasks(
|
|
478
|
+
workspaceId: string,
|
|
479
|
+
options: { limit?: number } = {},
|
|
480
|
+
): Promise<ScheduledTask[]> {
|
|
481
|
+
return await this.requestJson<ScheduledTask[]>(
|
|
482
|
+
"GET",
|
|
483
|
+
`/v1/workspaces/${workspaceId}/scheduled-tasks`,
|
|
484
|
+
undefined,
|
|
485
|
+
{
|
|
486
|
+
...(options.limit !== undefined ? { limit: String(options.limit) } : {}),
|
|
487
|
+
},
|
|
488
|
+
);
|
|
331
489
|
}
|
|
332
490
|
|
|
333
491
|
async getScheduledTask(workspaceId: string, taskId: string): Promise<ScheduledTask> {
|
|
334
|
-
return await this.requestJson<ScheduledTask>(
|
|
492
|
+
return await this.requestJson<ScheduledTask>(
|
|
493
|
+
"GET",
|
|
494
|
+
`/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}`,
|
|
495
|
+
);
|
|
335
496
|
}
|
|
336
497
|
|
|
337
498
|
// --- Events: replay, send, stream ----------------------------------------
|
|
@@ -347,20 +508,37 @@ export class OpenGeniClient {
|
|
|
347
508
|
sessionId: string,
|
|
348
509
|
options: { after?: number; before?: number; limit?: number; compact?: boolean } = {},
|
|
349
510
|
): Promise<SessionEvent[]> {
|
|
350
|
-
return await this.requestJson<SessionEvent[]>(
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
511
|
+
return await this.requestJson<SessionEvent[]>(
|
|
512
|
+
"GET",
|
|
513
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/events`,
|
|
514
|
+
undefined,
|
|
515
|
+
{
|
|
516
|
+
...(options.after !== undefined ? { after: String(options.after) } : {}),
|
|
517
|
+
...(options.before !== undefined ? { before: String(options.before) } : {}),
|
|
518
|
+
...(options.limit !== undefined ? { limit: String(options.limit) } : {}),
|
|
519
|
+
...(options.compact ? { compact: "1" } : {}),
|
|
520
|
+
},
|
|
521
|
+
);
|
|
356
522
|
}
|
|
357
523
|
|
|
358
524
|
/** POST a user/control event to the session. Returns the accepted event. */
|
|
359
|
-
async sendEvent(
|
|
360
|
-
|
|
525
|
+
async sendEvent(
|
|
526
|
+
workspaceId: string,
|
|
527
|
+
sessionId: string,
|
|
528
|
+
event: ClientSessionEventInput,
|
|
529
|
+
): Promise<SessionEvent> {
|
|
530
|
+
return await this.requestJson<SessionEvent>(
|
|
531
|
+
"POST",
|
|
532
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/events`,
|
|
533
|
+
event,
|
|
534
|
+
);
|
|
361
535
|
}
|
|
362
536
|
|
|
363
|
-
async sendMessage(
|
|
537
|
+
async sendMessage(
|
|
538
|
+
workspaceId: string,
|
|
539
|
+
sessionId: string,
|
|
540
|
+
message: string | SendMessageInput,
|
|
541
|
+
): Promise<SessionEvent> {
|
|
364
542
|
const input = typeof message === "string" ? { text: message } : message;
|
|
365
543
|
const { clientEventId, ...payload } = input;
|
|
366
544
|
return await this.sendEvent(workspaceId, sessionId, {
|
|
@@ -370,22 +548,28 @@ export class OpenGeniClient {
|
|
|
370
548
|
});
|
|
371
549
|
}
|
|
372
550
|
|
|
373
|
-
async
|
|
551
|
+
async pauseSession(
|
|
374
552
|
workspaceId: string,
|
|
375
553
|
sessionId: string,
|
|
376
554
|
options: { reason?: string; clientEventId?: string } = {},
|
|
377
555
|
): Promise<SessionEvent> {
|
|
378
|
-
return
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
556
|
+
return (
|
|
557
|
+
await this.controlSession(workspaceId, sessionId, {
|
|
558
|
+
mode: "pause",
|
|
559
|
+
...options,
|
|
560
|
+
})
|
|
561
|
+
).event;
|
|
383
562
|
}
|
|
384
563
|
|
|
385
564
|
async sendApprovalDecision(
|
|
386
565
|
workspaceId: string,
|
|
387
566
|
sessionId: string,
|
|
388
|
-
decision: {
|
|
567
|
+
decision: {
|
|
568
|
+
approvalId: string;
|
|
569
|
+
decision: "approve" | "reject";
|
|
570
|
+
message?: string;
|
|
571
|
+
clientEventId?: string;
|
|
572
|
+
},
|
|
389
573
|
): Promise<SessionEvent> {
|
|
390
574
|
const { clientEventId, ...payload } = decision;
|
|
391
575
|
return await this.sendEvent(workspaceId, sessionId, {
|
|
@@ -411,8 +595,13 @@ export class OpenGeniClient {
|
|
|
411
595
|
/** The transport `streamEvents` runs on; useful for custom streaming layers. */
|
|
412
596
|
eventStreamTransport(workspaceId: string, sessionId: string): SessionEventStreamTransport {
|
|
413
597
|
return {
|
|
414
|
-
openStream: async (after, signal) =>
|
|
415
|
-
|
|
598
|
+
openStream: async (after, signal) =>
|
|
599
|
+
await this.openEventStream(workspaceId, sessionId, {
|
|
600
|
+
after,
|
|
601
|
+
...(signal ? { signal } : {}),
|
|
602
|
+
}),
|
|
603
|
+
listEvents: async (after, limit) =>
|
|
604
|
+
await this.listEvents(workspaceId, sessionId, { after, limit }),
|
|
416
605
|
};
|
|
417
606
|
}
|
|
418
607
|
|
|
@@ -441,34 +630,77 @@ export class OpenGeniClient {
|
|
|
441
630
|
|
|
442
631
|
// --- Turn queue ------------------------------------------------------------
|
|
443
632
|
|
|
444
|
-
|
|
445
|
-
|
|
633
|
+
async getQueue(workspaceId: string, sessionId: string): Promise<SessionQueueSnapshot> {
|
|
634
|
+
return await this.requestJson<SessionQueueSnapshot>(
|
|
635
|
+
"GET",
|
|
636
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/queue`,
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
async cancelQueueItem(
|
|
446
641
|
workspaceId: string,
|
|
447
642
|
sessionId: string,
|
|
448
643
|
turnId: string,
|
|
449
|
-
|
|
450
|
-
): Promise<
|
|
451
|
-
return await this.requestJson<
|
|
452
|
-
"
|
|
453
|
-
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/
|
|
454
|
-
|
|
644
|
+
request: { expectedQueueVersion: number; expectedItemVersion: number; reason?: string },
|
|
645
|
+
): Promise<SessionQueueMutationResponse> {
|
|
646
|
+
return await this.requestJson<SessionQueueMutationResponse>(
|
|
647
|
+
"POST",
|
|
648
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/queue/${turnId}/cancel`,
|
|
649
|
+
request,
|
|
455
650
|
);
|
|
456
651
|
}
|
|
457
652
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
653
|
+
async controlSession(
|
|
654
|
+
workspaceId: string,
|
|
655
|
+
sessionId: string,
|
|
656
|
+
request: {
|
|
657
|
+
mode: "pause" | "resume";
|
|
658
|
+
reason?: string;
|
|
659
|
+
clientEventId?: string;
|
|
660
|
+
expectedControlState?: "active" | "paused";
|
|
661
|
+
expectedControlGeneration?: number;
|
|
662
|
+
expectedWorkspaceInferenceGeneration?: number;
|
|
663
|
+
},
|
|
664
|
+
): Promise<SessionControlResponse> {
|
|
665
|
+
return await this.requestJson<SessionControlResponse>(
|
|
666
|
+
"POST",
|
|
667
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/control`,
|
|
668
|
+
request,
|
|
669
|
+
);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
async resumeSession(
|
|
673
|
+
workspaceId: string,
|
|
674
|
+
sessionId: string,
|
|
675
|
+
options: { reason?: string; clientEventId?: string } = {},
|
|
676
|
+
): Promise<SessionControlResponse> {
|
|
677
|
+
return await this.controlSession(workspaceId, sessionId, { mode: "resume", ...options });
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
async setWorkspaceInferenceState(
|
|
681
|
+
workspaceId: string,
|
|
682
|
+
request: {
|
|
683
|
+
state: "active" | "paused";
|
|
684
|
+
reason: string;
|
|
685
|
+
clientEventId: string;
|
|
686
|
+
expectedState: "active" | "paused";
|
|
687
|
+
expectedGeneration: number;
|
|
688
|
+
exceptSessionIds?: string[];
|
|
689
|
+
},
|
|
690
|
+
): Promise<WorkspaceInferenceControlResponse> {
|
|
691
|
+
return await this.requestJson<WorkspaceInferenceControlResponse>(
|
|
464
692
|
"POST",
|
|
465
|
-
`/v1/workspaces/${workspaceId}/
|
|
466
|
-
|
|
693
|
+
`/v1/workspaces/${workspaceId}/inference-control`,
|
|
694
|
+
request,
|
|
467
695
|
);
|
|
468
696
|
}
|
|
469
697
|
|
|
470
698
|
/** Cancel a queued turn before it is claimed. Returns the cancelled turn. */
|
|
471
|
-
async deleteQueuedTurn(
|
|
699
|
+
async deleteQueuedTurn(
|
|
700
|
+
workspaceId: string,
|
|
701
|
+
sessionId: string,
|
|
702
|
+
turnId: string,
|
|
703
|
+
): Promise<SessionTurn> {
|
|
472
704
|
return await this.requestJson<SessionTurn>(
|
|
473
705
|
"DELETE",
|
|
474
706
|
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/turns/${turnId}`,
|
|
@@ -476,87 +708,54 @@ export class OpenGeniClient {
|
|
|
476
708
|
}
|
|
477
709
|
|
|
478
710
|
/**
|
|
479
|
-
* Steer:
|
|
480
|
-
*
|
|
481
|
-
* running turn so the session picks the steer turn up next. On a session
|
|
482
|
-
* that is not running this degrades gracefully to a plain queued message.
|
|
483
|
-
*
|
|
484
|
-
* The steer turn is located by `triggerEventId` across ALL turns (retried
|
|
485
|
-
* briefly in case the server is still materializing it) — not just the
|
|
486
|
-
* queued ones, because the worker can claim the steer turn before it is
|
|
487
|
-
* ever observed queued, and a claimed steer turn means the message is
|
|
488
|
-
* already being delivered: interrupting then would cancel the very message
|
|
489
|
-
* being steered. If the turn cannot be found while other turns are queued,
|
|
490
|
-
* the interrupt is also skipped — stopping the running turn would otherwise
|
|
491
|
-
* promote someone else's queued work over this message — and the call
|
|
492
|
-
* degrades to a plain queued send (`interrupted: false`).
|
|
711
|
+
* Steer: atomically put this prompt at the head and supersede the current
|
|
712
|
+
* inference. The client performs one request and renders server order.
|
|
493
713
|
*/
|
|
494
714
|
async steerMessage(
|
|
495
715
|
workspaceId: string,
|
|
496
716
|
sessionId: string,
|
|
497
717
|
message: string | SendMessageInput,
|
|
498
718
|
): Promise<SteerMessageResult> {
|
|
499
|
-
const
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
}
|
|
506
|
-
const turns = await this.listTurns(workspaceId, sessionId);
|
|
507
|
-
queued = turns
|
|
508
|
-
.filter((turn) => turn.status === "queued")
|
|
509
|
-
.sort((a, b) => a.position - b.position || a.createdAt.localeCompare(b.createdAt));
|
|
510
|
-
// Match against every turn, whatever its status: a steer turn that is
|
|
511
|
-
// already running/requires_action (or even finished) was claimed before
|
|
512
|
-
// this listing — that is delivery, not grounds for an interrupt.
|
|
513
|
-
steerTurn = turns.find((turn) => turn.triggerEventId === accepted.id) ?? null;
|
|
514
|
-
if (steerTurn) {
|
|
515
|
-
break;
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
const steerTurnQueued = steerTurn?.status === "queued";
|
|
519
|
-
if (steerTurn && steerTurnQueued && queued.length > 1) {
|
|
520
|
-
const front = steerTurn;
|
|
521
|
-
await this.reorderQueuedTurns(workspaceId, sessionId, [
|
|
522
|
-
front.id,
|
|
523
|
-
...queued.filter((turn) => turn.id !== front.id).map((turn) => turn.id),
|
|
524
|
-
]);
|
|
525
|
-
}
|
|
526
|
-
// Interrupting is only safe when the next claim is provably this message:
|
|
527
|
-
// either the steer turn sits queued (now at the front), or no turn
|
|
528
|
-
// materialized yet AND nothing else is queued. A steer turn observed in
|
|
529
|
-
// any non-queued state was already claimed — skip the interrupt.
|
|
530
|
-
const canDeliverNext = steerTurnQueued || (steerTurn === null && queued.length === 0);
|
|
531
|
-
const session = await this.getSession(workspaceId, sessionId);
|
|
532
|
-
// If the previously running turn already finished and the session claimed
|
|
533
|
-
// the steer turn itself, interrupting now would cancel the very message
|
|
534
|
-
// being steered. `activeTurnId` is the claim check; the residual window
|
|
535
|
-
// between this read and the interrupt landing is accepted (an interrupt
|
|
536
|
-
// can never be atomic with a status read over HTTP).
|
|
537
|
-
const steerTurnAlreadyActive = steerTurn !== null && session.activeTurnId === steerTurn.id;
|
|
538
|
-
const interrupted = canDeliverNext
|
|
539
|
-
&& !steerTurnAlreadyActive
|
|
540
|
-
&& (session.status === "running" || session.status === "requires_action");
|
|
541
|
-
if (interrupted) {
|
|
542
|
-
await this.interrupt(workspaceId, sessionId, { reason: "steer" });
|
|
543
|
-
}
|
|
544
|
-
return { accepted, turn: steerTurn, interrupted };
|
|
719
|
+
const input = typeof message === "string" ? { text: message } : message;
|
|
720
|
+
return await this.requestJson<SteerMessageResult>(
|
|
721
|
+
"POST",
|
|
722
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/steer`,
|
|
723
|
+
input,
|
|
724
|
+
);
|
|
545
725
|
}
|
|
546
726
|
|
|
547
727
|
// --- Goals -------------------------------------------------------------------
|
|
548
728
|
|
|
549
729
|
/** The session's goal. 404s when the session never had one. */
|
|
550
730
|
async getGoal(workspaceId: string, sessionId: string): Promise<SessionGoal> {
|
|
551
|
-
return await this.requestJson<SessionGoal>(
|
|
731
|
+
return await this.requestJson<SessionGoal>(
|
|
732
|
+
"GET",
|
|
733
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/goal`,
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
async updateGoal(
|
|
738
|
+
workspaceId: string,
|
|
739
|
+
sessionId: string,
|
|
740
|
+
request: UpdateSessionGoalRequest,
|
|
741
|
+
): Promise<SessionGoal> {
|
|
742
|
+
return await this.requestJson<SessionGoal>(
|
|
743
|
+
"PATCH",
|
|
744
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/goal`,
|
|
745
|
+
request,
|
|
746
|
+
);
|
|
552
747
|
}
|
|
553
748
|
|
|
554
|
-
async
|
|
555
|
-
|
|
749
|
+
async deleteGoal(workspaceId: string, sessionId: string): Promise<void> {
|
|
750
|
+
await this.requestVoid("DELETE", `/v1/workspaces/${workspaceId}/sessions/${sessionId}/goal`);
|
|
556
751
|
}
|
|
557
752
|
|
|
558
753
|
/** Pause the goal loop: the session stops self-continuing until resumed. */
|
|
559
|
-
async pauseGoal(
|
|
754
|
+
async pauseGoal(
|
|
755
|
+
workspaceId: string,
|
|
756
|
+
sessionId: string,
|
|
757
|
+
options: { rationale?: string } = {},
|
|
758
|
+
): Promise<SessionGoal> {
|
|
560
759
|
return await this.updateGoal(workspaceId, sessionId, {
|
|
561
760
|
status: "paused",
|
|
562
761
|
...(options.rationale !== undefined ? { rationale: options.rationale } : {}),
|
|
@@ -578,17 +777,23 @@ export class OpenGeniClient {
|
|
|
578
777
|
* context — the destructive intent is explicit on the wire.
|
|
579
778
|
*/
|
|
580
779
|
async clearSessionContext(workspaceId: string, sessionId: string): Promise<void> {
|
|
581
|
-
await this.requestVoid(
|
|
780
|
+
await this.requestVoid(
|
|
781
|
+
"POST",
|
|
782
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/context/clear`,
|
|
783
|
+
{ confirm: true },
|
|
784
|
+
);
|
|
582
785
|
}
|
|
583
786
|
|
|
584
|
-
/**
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
787
|
+
/** Request one durable portable compaction at the next safe model boundary. */
|
|
788
|
+
async compactSessionContext(
|
|
789
|
+
workspaceId: string,
|
|
790
|
+
sessionId: string,
|
|
791
|
+
): Promise<CompactSessionContextResult> {
|
|
792
|
+
return await this.requestJson<CompactSessionContextResult>(
|
|
793
|
+
"POST",
|
|
794
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/context/compact`,
|
|
795
|
+
{},
|
|
796
|
+
);
|
|
592
797
|
}
|
|
593
798
|
|
|
594
799
|
// --- Channel-A structured services (P4.4) ------------------------------------
|
|
@@ -597,79 +802,232 @@ export class OpenGeniClient {
|
|
|
597
802
|
// notifications + the PTY output stream arrive on the existing event SSE.
|
|
598
803
|
|
|
599
804
|
/** FileSystem: list a directory tree (feeds the Pierre file tree). */
|
|
600
|
-
async fsList(
|
|
601
|
-
|
|
805
|
+
async fsList(
|
|
806
|
+
workspaceId: string,
|
|
807
|
+
sessionId: string,
|
|
808
|
+
request: FsListRequest = {},
|
|
809
|
+
): Promise<FsListResponse> {
|
|
810
|
+
return await this.requestJson<FsListResponse>(
|
|
811
|
+
"POST",
|
|
812
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/fs/list`,
|
|
813
|
+
request,
|
|
814
|
+
);
|
|
602
815
|
}
|
|
603
816
|
|
|
604
817
|
/** FileSystem: read a file (text or base64; binary-safe, size-capped). */
|
|
605
|
-
async fsRead(
|
|
606
|
-
|
|
818
|
+
async fsRead(
|
|
819
|
+
workspaceId: string,
|
|
820
|
+
sessionId: string,
|
|
821
|
+
request: FsReadRequest,
|
|
822
|
+
): Promise<FsReadResponse> {
|
|
823
|
+
return await this.requestJson<FsReadResponse>(
|
|
824
|
+
"POST",
|
|
825
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/fs/read`,
|
|
826
|
+
request,
|
|
827
|
+
);
|
|
607
828
|
}
|
|
608
829
|
|
|
609
830
|
/** FileSystem: write a file (last-writer-wins; emits fs.changed). */
|
|
610
|
-
async fsWrite(
|
|
611
|
-
|
|
831
|
+
async fsWrite(
|
|
832
|
+
workspaceId: string,
|
|
833
|
+
sessionId: string,
|
|
834
|
+
request: FsWriteRequest,
|
|
835
|
+
): Promise<FsWriteResponse> {
|
|
836
|
+
return await this.requestJson<FsWriteResponse>(
|
|
837
|
+
"POST",
|
|
838
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/fs/write`,
|
|
839
|
+
request,
|
|
840
|
+
);
|
|
612
841
|
}
|
|
613
842
|
|
|
614
843
|
/** FileSystem: delete a path (emits fs.changed). */
|
|
615
|
-
async fsDelete(
|
|
616
|
-
|
|
844
|
+
async fsDelete(
|
|
845
|
+
workspaceId: string,
|
|
846
|
+
sessionId: string,
|
|
847
|
+
request: FsDeleteRequest,
|
|
848
|
+
): Promise<FsDeleteResponse> {
|
|
849
|
+
return await this.requestJson<FsDeleteResponse>(
|
|
850
|
+
"POST",
|
|
851
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/fs/delete`,
|
|
852
|
+
request,
|
|
853
|
+
);
|
|
617
854
|
}
|
|
618
855
|
|
|
619
856
|
/** FileSystem: move/rename a path (emits fs.changed; 409 if destination exists and overwrite is false). */
|
|
620
|
-
async fsMove(
|
|
621
|
-
|
|
857
|
+
async fsMove(
|
|
858
|
+
workspaceId: string,
|
|
859
|
+
sessionId: string,
|
|
860
|
+
request: FsMoveRequest,
|
|
861
|
+
): Promise<FsMoveResponse> {
|
|
862
|
+
return await this.requestJson<FsMoveResponse>(
|
|
863
|
+
"POST",
|
|
864
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/fs/move`,
|
|
865
|
+
request,
|
|
866
|
+
);
|
|
622
867
|
}
|
|
623
868
|
|
|
624
869
|
/** FileSystem: create a directory (emits fs.changed; recursive defaults to true). */
|
|
625
|
-
async fsMkdir(
|
|
626
|
-
|
|
870
|
+
async fsMkdir(
|
|
871
|
+
workspaceId: string,
|
|
872
|
+
sessionId: string,
|
|
873
|
+
request: FsMkdirRequest,
|
|
874
|
+
): Promise<FsMkdirResponse> {
|
|
875
|
+
return await this.requestJson<FsMkdirResponse>(
|
|
876
|
+
"POST",
|
|
877
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/fs/mkdir`,
|
|
878
|
+
request,
|
|
879
|
+
);
|
|
627
880
|
}
|
|
628
881
|
|
|
629
882
|
/** Git: working-tree/index status (the Pierre file-status feed). */
|
|
630
|
-
async gitStatus(
|
|
631
|
-
|
|
883
|
+
async gitStatus(
|
|
884
|
+
workspaceId: string,
|
|
885
|
+
sessionId: string,
|
|
886
|
+
request: GitStatusRequest = {},
|
|
887
|
+
): Promise<GitStatusResponse> {
|
|
888
|
+
return await this.requestJson<GitStatusResponse>(
|
|
889
|
+
"POST",
|
|
890
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/git/status`,
|
|
891
|
+
request,
|
|
892
|
+
);
|
|
632
893
|
}
|
|
633
894
|
|
|
634
895
|
/** Git: structured diff hunks (the Pierre diff feed). */
|
|
635
|
-
async gitDiff(
|
|
636
|
-
|
|
896
|
+
async gitDiff(
|
|
897
|
+
workspaceId: string,
|
|
898
|
+
sessionId: string,
|
|
899
|
+
request: GitDiffRequest = {},
|
|
900
|
+
): Promise<GitDiffResponse> {
|
|
901
|
+
return await this.requestJson<GitDiffResponse>(
|
|
902
|
+
"POST",
|
|
903
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/git/diff`,
|
|
904
|
+
request,
|
|
905
|
+
);
|
|
637
906
|
}
|
|
638
907
|
|
|
639
908
|
/** Git: commit log. */
|
|
640
|
-
async gitLog(
|
|
641
|
-
|
|
909
|
+
async gitLog(
|
|
910
|
+
workspaceId: string,
|
|
911
|
+
sessionId: string,
|
|
912
|
+
request: GitLogRequest = {},
|
|
913
|
+
): Promise<GitLogResponse> {
|
|
914
|
+
return await this.requestJson<GitLogResponse>(
|
|
915
|
+
"POST",
|
|
916
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/git/log`,
|
|
917
|
+
request,
|
|
918
|
+
);
|
|
642
919
|
}
|
|
643
920
|
|
|
644
921
|
/** Git: show a commit (diff vs first parent) or fetch a raw blob at a ref. */
|
|
645
|
-
async gitShow(
|
|
646
|
-
|
|
922
|
+
async gitShow(
|
|
923
|
+
workspaceId: string,
|
|
924
|
+
sessionId: string,
|
|
925
|
+
request: GitShowRequest,
|
|
926
|
+
): Promise<GitShowResponse> {
|
|
927
|
+
return await this.requestJson<GitShowResponse>(
|
|
928
|
+
"POST",
|
|
929
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/git/show`,
|
|
930
|
+
request,
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/** Workspace capture: the latest turn-end snapshot of the session's workspace
|
|
935
|
+
* (tree + per-repo diff + file after-image refs), served from durable storage
|
|
936
|
+
* WITHOUT warming a machine — the workbench cold-paint source. Returns
|
|
937
|
+
* `{available:false}` when no capture exists yet (fall back to the live path). */
|
|
938
|
+
async getWorkspaceCapture(
|
|
939
|
+
workspaceId: string,
|
|
940
|
+
sessionId: string,
|
|
941
|
+
): Promise<GetWorkspaceCaptureResponse> {
|
|
942
|
+
return await this.requestJson<GetWorkspaceCaptureResponse>(
|
|
943
|
+
"GET",
|
|
944
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/workspace/capture`,
|
|
945
|
+
);
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
/** Workspace capture: a single file's after-image from the capture (revision
|
|
949
|
+
* pins a specific one; omitted → latest). Content is inline for small files,
|
|
950
|
+
* else a short-TTL signed URL; a tooLarge file returns metadata only. */
|
|
951
|
+
async getWorkspaceCaptureFile(
|
|
952
|
+
workspaceId: string,
|
|
953
|
+
sessionId: string,
|
|
954
|
+
path: string,
|
|
955
|
+
revision?: number,
|
|
956
|
+
): Promise<GetWorkspaceCaptureFileResponse> {
|
|
957
|
+
const query: Record<string, string> = { path };
|
|
958
|
+
if (revision !== undefined) query.revision = String(revision);
|
|
959
|
+
return await this.requestJson<GetWorkspaceCaptureFileResponse>(
|
|
960
|
+
"GET",
|
|
961
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/workspace/capture/file`,
|
|
962
|
+
undefined,
|
|
963
|
+
query,
|
|
964
|
+
);
|
|
647
965
|
}
|
|
648
966
|
|
|
649
967
|
/** Terminal: run a bounded command, returning buffered stdout/stderr inline. */
|
|
650
|
-
async terminalExec(
|
|
651
|
-
|
|
968
|
+
async terminalExec(
|
|
969
|
+
workspaceId: string,
|
|
970
|
+
sessionId: string,
|
|
971
|
+
request: TerminalExecRequest,
|
|
972
|
+
): Promise<TerminalExecResponse> {
|
|
973
|
+
return await this.requestJson<TerminalExecResponse>(
|
|
974
|
+
"POST",
|
|
975
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/terminal/exec`,
|
|
976
|
+
request,
|
|
977
|
+
);
|
|
652
978
|
}
|
|
653
979
|
|
|
654
980
|
/** Terminal: open an interactive PTY. Output streams on the event SSE as
|
|
655
981
|
* terminal.pty.output.delta; drive it with terminalPtyWrite. */
|
|
656
|
-
async terminalPtyOpen(
|
|
657
|
-
|
|
982
|
+
async terminalPtyOpen(
|
|
983
|
+
workspaceId: string,
|
|
984
|
+
sessionId: string,
|
|
985
|
+
request: PtyOpenRequest = {},
|
|
986
|
+
): Promise<PtyOpenResponse> {
|
|
987
|
+
return await this.requestJson<PtyOpenResponse>(
|
|
988
|
+
"POST",
|
|
989
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/terminal/pty`,
|
|
990
|
+
request,
|
|
991
|
+
);
|
|
658
992
|
}
|
|
659
993
|
|
|
660
994
|
/** Terminal: send stdin to an open PTY (output rides A1). */
|
|
661
|
-
async terminalPtyWrite(
|
|
662
|
-
|
|
995
|
+
async terminalPtyWrite(
|
|
996
|
+
workspaceId: string,
|
|
997
|
+
sessionId: string,
|
|
998
|
+
request: PtyWriteRequest,
|
|
999
|
+
): Promise<void> {
|
|
1000
|
+
await this.requestVoid(
|
|
1001
|
+
"POST",
|
|
1002
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/terminal/pty/write`,
|
|
1003
|
+
request,
|
|
1004
|
+
);
|
|
663
1005
|
}
|
|
664
1006
|
|
|
665
1007
|
/** Terminal: resize an open PTY. */
|
|
666
|
-
async terminalPtyResize(
|
|
667
|
-
|
|
1008
|
+
async terminalPtyResize(
|
|
1009
|
+
workspaceId: string,
|
|
1010
|
+
sessionId: string,
|
|
1011
|
+
request: PtyResizeRequest,
|
|
1012
|
+
): Promise<void> {
|
|
1013
|
+
await this.requestVoid(
|
|
1014
|
+
"POST",
|
|
1015
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/terminal/pty/resize`,
|
|
1016
|
+
request,
|
|
1017
|
+
);
|
|
668
1018
|
}
|
|
669
1019
|
|
|
670
1020
|
/** Terminal: close an open PTY (idempotent). */
|
|
671
|
-
async terminalPtyClose(
|
|
672
|
-
|
|
1021
|
+
async terminalPtyClose(
|
|
1022
|
+
workspaceId: string,
|
|
1023
|
+
sessionId: string,
|
|
1024
|
+
request: PtyCloseRequest,
|
|
1025
|
+
): Promise<void> {
|
|
1026
|
+
await this.requestVoid(
|
|
1027
|
+
"POST",
|
|
1028
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/terminal/pty/close`,
|
|
1029
|
+
request,
|
|
1030
|
+
);
|
|
673
1031
|
}
|
|
674
1032
|
|
|
675
1033
|
// --- Stream surfacing: capability negotiation + viewer lifecycle (Phase 5) ---
|
|
@@ -684,19 +1042,29 @@ export class OpenGeniClient {
|
|
|
684
1042
|
* liveness the client polls on while `cold`/`warming`. The desktop URL/token
|
|
685
1043
|
* are minted in-process only when the box is warm AND the principal has
|
|
686
1044
|
* acknowledged the un-redacted plane. */
|
|
687
|
-
async getStreamCapabilities(
|
|
1045
|
+
async getStreamCapabilities(
|
|
1046
|
+
workspaceId: string,
|
|
1047
|
+
sessionId: string,
|
|
1048
|
+
): Promise<SessionCapabilities> {
|
|
688
1049
|
return await this.requestJson<SessionCapabilities>(
|
|
689
|
-
"GET",
|
|
1050
|
+
"GET",
|
|
1051
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/stream-capabilities`,
|
|
1052
|
+
);
|
|
690
1053
|
}
|
|
691
1054
|
|
|
692
1055
|
/** Record the calling principal's acknowledgment of the un-redacted desktop
|
|
693
1056
|
* pixel plane (and, when the box is shared, the shared-exposure disclosure).
|
|
694
1057
|
* The desktop viewer-attach path returns 409 until this is recorded. */
|
|
695
1058
|
async acknowledgeStream(
|
|
696
|
-
workspaceId: string,
|
|
1059
|
+
workspaceId: string,
|
|
1060
|
+
sessionId: string,
|
|
1061
|
+
request: AcknowledgeStreamRequest = {},
|
|
697
1062
|
): Promise<AcknowledgeStreamResponse> {
|
|
698
1063
|
return await this.requestJson<AcknowledgeStreamResponse>(
|
|
699
|
-
"POST",
|
|
1064
|
+
"POST",
|
|
1065
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/stream-capabilities/acknowledge`,
|
|
1066
|
+
request,
|
|
1067
|
+
);
|
|
700
1068
|
}
|
|
701
1069
|
|
|
702
1070
|
/** Attach a viewer holder (refcounted liveness — keeps the box warm while
|
|
@@ -708,25 +1076,39 @@ export class OpenGeniClient {
|
|
|
708
1076
|
* (`desktop` omitted/false) warms the box + mints the pty-ws terminal cell with
|
|
709
1077
|
* NO consent gate. An omitted `viewerId` mints a fresh one. */
|
|
710
1078
|
async attachViewer(
|
|
711
|
-
workspaceId: string,
|
|
1079
|
+
workspaceId: string,
|
|
1080
|
+
sessionId: string,
|
|
1081
|
+
request: AttachViewerRequest = {},
|
|
712
1082
|
): Promise<AttachViewerResponse> {
|
|
713
1083
|
return await this.requestJson<AttachViewerResponse>(
|
|
714
|
-
"POST",
|
|
1084
|
+
"POST",
|
|
1085
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/viewers`,
|
|
1086
|
+
request,
|
|
1087
|
+
);
|
|
715
1088
|
}
|
|
716
1089
|
|
|
717
1090
|
/** Heartbeat a viewer holder (Channel-A app-level liveness). A closed laptop
|
|
718
1091
|
* stops sending these → the reaper drops the holder within ~90s. Echoes
|
|
719
1092
|
* `leaseEpoch` so a superseded epoch is rejected (`alive:false` → re-attach). */
|
|
720
1093
|
async heartbeatViewer(
|
|
721
|
-
workspaceId: string,
|
|
1094
|
+
workspaceId: string,
|
|
1095
|
+
sessionId: string,
|
|
1096
|
+
viewerId: string,
|
|
1097
|
+
request: ViewerHeartbeatRequest,
|
|
722
1098
|
): Promise<ViewerHeartbeatResponse> {
|
|
723
1099
|
return await this.requestJson<ViewerHeartbeatResponse>(
|
|
724
|
-
"POST",
|
|
1100
|
+
"POST",
|
|
1101
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/viewers/${viewerId}/heartbeat`,
|
|
1102
|
+
request,
|
|
1103
|
+
);
|
|
725
1104
|
}
|
|
726
1105
|
|
|
727
1106
|
/** Detach a viewer (delete this holder; idempotent delete-my-row). */
|
|
728
1107
|
async detachViewer(workspaceId: string, sessionId: string, viewerId: string): Promise<void> {
|
|
729
|
-
await this.requestVoid(
|
|
1108
|
+
await this.requestVoid(
|
|
1109
|
+
"DELETE",
|
|
1110
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/viewers/${viewerId}`,
|
|
1111
|
+
);
|
|
730
1112
|
}
|
|
731
1113
|
|
|
732
1114
|
// --- Access + workspaces -----------------------------------------------------
|
|
@@ -759,155 +1141,392 @@ export class OpenGeniClient {
|
|
|
759
1141
|
return await this.requestJson<Workspace>("GET", `/v1/workspaces/${workspaceId}`);
|
|
760
1142
|
}
|
|
761
1143
|
|
|
762
|
-
async updateWorkspace(workspaceId: string, request: UpdateWorkspaceRequest): Promise<Workspace> {
|
|
763
|
-
return await this.requestJson<Workspace>("PATCH", `/v1/workspaces/${workspaceId}`, request);
|
|
1144
|
+
async updateWorkspace(workspaceId: string, request: UpdateWorkspaceRequest): Promise<Workspace> {
|
|
1145
|
+
return await this.requestJson<Workspace>("PATCH", `/v1/workspaces/${workspaceId}`, request);
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
/**
|
|
1149
|
+
* Delete a workspace and everything in it. Refused (409) for the account's
|
|
1150
|
+
* only workspace and while it still has a running session. Irreversible.
|
|
1151
|
+
*/
|
|
1152
|
+
async deleteWorkspace(workspaceId: string): Promise<void> {
|
|
1153
|
+
await this.requestVoid("DELETE", `/v1/workspaces/${workspaceId}`);
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
// --- Members ("People with access") -------------------------------------------
|
|
1157
|
+
|
|
1158
|
+
/** The workspace's members (user + api_key subjects). */
|
|
1159
|
+
async listWorkspaceMembers(workspaceId: string): Promise<WorkspaceMember[]> {
|
|
1160
|
+
const response = await this.requestJson<ListWorkspaceMembersResponse>(
|
|
1161
|
+
"GET",
|
|
1162
|
+
`/v1/workspaces/${workspaceId}/members`,
|
|
1163
|
+
);
|
|
1164
|
+
return response.members;
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
/**
|
|
1168
|
+
* Add an already-registered user by email. 404s when no user with that email
|
|
1169
|
+
* exists (email invites for unknown users are deferred).
|
|
1170
|
+
*/
|
|
1171
|
+
async addWorkspaceMember(
|
|
1172
|
+
workspaceId: string,
|
|
1173
|
+
request: AddWorkspaceMemberRequest,
|
|
1174
|
+
): Promise<WorkspaceMember> {
|
|
1175
|
+
return await this.requestJson<WorkspaceMember>(
|
|
1176
|
+
"POST",
|
|
1177
|
+
`/v1/workspaces/${workspaceId}/members`,
|
|
1178
|
+
request,
|
|
1179
|
+
);
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
async updateWorkspaceMember(
|
|
1183
|
+
workspaceId: string,
|
|
1184
|
+
subjectId: string,
|
|
1185
|
+
request: UpdateWorkspaceMemberRequest,
|
|
1186
|
+
): Promise<WorkspaceMember> {
|
|
1187
|
+
return await this.requestJson<WorkspaceMember>(
|
|
1188
|
+
"PATCH",
|
|
1189
|
+
`/v1/workspaces/${workspaceId}/members/${encodeURIComponent(subjectId)}`,
|
|
1190
|
+
request,
|
|
1191
|
+
);
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
/**
|
|
1195
|
+
* Remove a member. Refused (409) for your own membership and for the last
|
|
1196
|
+
* member who can still manage the workspace.
|
|
1197
|
+
*/
|
|
1198
|
+
async removeWorkspaceMember(workspaceId: string, subjectId: string): Promise<void> {
|
|
1199
|
+
await this.requestVoid(
|
|
1200
|
+
"DELETE",
|
|
1201
|
+
`/v1/workspaces/${workspaceId}/members/${encodeURIComponent(subjectId)}`,
|
|
1202
|
+
);
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
// --- Scheduled tasks (write + runs) -------------------------------------------
|
|
1206
|
+
|
|
1207
|
+
async createScheduledTask(
|
|
1208
|
+
workspaceId: string,
|
|
1209
|
+
request: CreateScheduledTaskRequest,
|
|
1210
|
+
): Promise<ScheduledTask> {
|
|
1211
|
+
return await this.requestJson<ScheduledTask>(
|
|
1212
|
+
"POST",
|
|
1213
|
+
`/v1/workspaces/${workspaceId}/scheduled-tasks`,
|
|
1214
|
+
request,
|
|
1215
|
+
);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
async updateScheduledTask(
|
|
1219
|
+
workspaceId: string,
|
|
1220
|
+
taskId: string,
|
|
1221
|
+
request: UpdateScheduledTaskRequest,
|
|
1222
|
+
): Promise<ScheduledTask> {
|
|
1223
|
+
return await this.requestJson<ScheduledTask>(
|
|
1224
|
+
"PATCH",
|
|
1225
|
+
`/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}`,
|
|
1226
|
+
request,
|
|
1227
|
+
);
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
async pauseScheduledTask(workspaceId: string, taskId: string): Promise<ScheduledTask> {
|
|
1231
|
+
return await this.requestJson<ScheduledTask>(
|
|
1232
|
+
"POST",
|
|
1233
|
+
`/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}/pause`,
|
|
1234
|
+
);
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
async resumeScheduledTask(workspaceId: string, taskId: string): Promise<ScheduledTask> {
|
|
1238
|
+
return await this.requestJson<ScheduledTask>(
|
|
1239
|
+
"POST",
|
|
1240
|
+
`/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}/resume`,
|
|
1241
|
+
);
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
/**
|
|
1245
|
+
* Fire the task immediately (manual trigger), independent of its schedule.
|
|
1246
|
+
* Pass a stable `triggerId` to make a retried trigger idempotent — the same
|
|
1247
|
+
* token charges once and starts one run. Omit it and each call is distinct.
|
|
1248
|
+
*/
|
|
1249
|
+
async triggerScheduledTask(
|
|
1250
|
+
workspaceId: string,
|
|
1251
|
+
taskId: string,
|
|
1252
|
+
options: { triggerId?: string } = {},
|
|
1253
|
+
): Promise<ScheduledTask> {
|
|
1254
|
+
return await this.requestJson<ScheduledTask>(
|
|
1255
|
+
"POST",
|
|
1256
|
+
`/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}/trigger`,
|
|
1257
|
+
options.triggerId ? { triggerId: options.triggerId } : undefined,
|
|
1258
|
+
);
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
async deleteScheduledTask(workspaceId: string, taskId: string): Promise<void> {
|
|
1262
|
+
await this.requestJson<unknown>(
|
|
1263
|
+
"DELETE",
|
|
1264
|
+
`/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}`,
|
|
1265
|
+
);
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
async listScheduledTaskRuns(
|
|
1269
|
+
workspaceId: string,
|
|
1270
|
+
taskId: string,
|
|
1271
|
+
options: { limit?: number } = {},
|
|
1272
|
+
): Promise<ScheduledTaskRun[]> {
|
|
1273
|
+
return await this.requestJson<ScheduledTaskRun[]>(
|
|
1274
|
+
"GET",
|
|
1275
|
+
`/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}/runs`,
|
|
1276
|
+
undefined,
|
|
1277
|
+
{ ...(options.limit !== undefined ? { limit: String(options.limit) } : {}) },
|
|
1278
|
+
);
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
// --- VariableSets --------------------------------------------------------------
|
|
1282
|
+
// Variable values are write-only: reads return name/version metadata only.
|
|
1283
|
+
|
|
1284
|
+
async listVariableSets(workspaceId: string): Promise<VariableSet[]> {
|
|
1285
|
+
return await this.requestJson<VariableSet[]>(
|
|
1286
|
+
"GET",
|
|
1287
|
+
`/v1/workspaces/${workspaceId}/variable-sets`,
|
|
1288
|
+
);
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
async createVariableSet(
|
|
1292
|
+
workspaceId: string,
|
|
1293
|
+
request: CreateVariableSetRequest,
|
|
1294
|
+
): Promise<VariableSet> {
|
|
1295
|
+
return await this.requestJson<VariableSet>(
|
|
1296
|
+
"POST",
|
|
1297
|
+
`/v1/workspaces/${workspaceId}/variable-sets`,
|
|
1298
|
+
request,
|
|
1299
|
+
);
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
async getVariableSet(workspaceId: string, variableSetId: string): Promise<VariableSet> {
|
|
1303
|
+
return await this.requestJson<VariableSet>(
|
|
1304
|
+
"GET",
|
|
1305
|
+
`/v1/workspaces/${workspaceId}/variable-sets/${variableSetId}`,
|
|
1306
|
+
);
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
async updateVariableSet(
|
|
1310
|
+
workspaceId: string,
|
|
1311
|
+
variableSetId: string,
|
|
1312
|
+
request: UpdateVariableSetRequest,
|
|
1313
|
+
): Promise<VariableSet> {
|
|
1314
|
+
return await this.requestJson<VariableSet>(
|
|
1315
|
+
"PATCH",
|
|
1316
|
+
`/v1/workspaces/${workspaceId}/variable-sets/${variableSetId}`,
|
|
1317
|
+
request,
|
|
1318
|
+
);
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
async deleteVariableSet(workspaceId: string, variableSetId: string): Promise<void> {
|
|
1322
|
+
await this.requestJson<unknown>(
|
|
1323
|
+
"DELETE",
|
|
1324
|
+
`/v1/workspaces/${workspaceId}/variable-sets/${variableSetId}`,
|
|
1325
|
+
);
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
/** Create or rotate a variable. The value never comes back on any read. */
|
|
1329
|
+
async setVariableSetVariable(
|
|
1330
|
+
workspaceId: string,
|
|
1331
|
+
variableSetId: string,
|
|
1332
|
+
name: string,
|
|
1333
|
+
value: string,
|
|
1334
|
+
): Promise<VariableSetVariableMetadata> {
|
|
1335
|
+
return await this.requestJson<VariableSetVariableMetadata>(
|
|
1336
|
+
"PUT",
|
|
1337
|
+
`/v1/workspaces/${workspaceId}/variable-sets/${variableSetId}/variables/${encodeURIComponent(name)}`,
|
|
1338
|
+
{ value },
|
|
1339
|
+
);
|
|
764
1340
|
}
|
|
765
1341
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
await this.
|
|
1342
|
+
async deleteVariableSetVariable(
|
|
1343
|
+
workspaceId: string,
|
|
1344
|
+
variableSetId: string,
|
|
1345
|
+
name: string,
|
|
1346
|
+
): Promise<void> {
|
|
1347
|
+
await this.requestJson<unknown>(
|
|
1348
|
+
"DELETE",
|
|
1349
|
+
`/v1/workspaces/${workspaceId}/variable-sets/${variableSetId}/variables/${encodeURIComponent(name)}`,
|
|
1350
|
+
);
|
|
772
1351
|
}
|
|
773
1352
|
|
|
774
|
-
// ---
|
|
1353
|
+
// --- Rigs ------------------------------------------------------------------
|
|
1354
|
+
// Workspace-scoped, versioned sandbox machine definitions. rigs:use gates read
|
|
1355
|
+
// + proposeRigChange; rigs:manage gates create / update / delete / activate.
|
|
775
1356
|
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
const response = await this.requestJson<ListWorkspaceMembersResponse>("GET", `/v1/workspaces/${workspaceId}/members`);
|
|
779
|
-
return response.members;
|
|
1357
|
+
async listRigs(workspaceId: string): Promise<Rig[]> {
|
|
1358
|
+
return await this.requestJson<Rig[]>("GET", `/v1/workspaces/${workspaceId}/rigs`);
|
|
780
1359
|
}
|
|
781
1360
|
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
* exists (email invites for unknown users are deferred).
|
|
785
|
-
*/
|
|
786
|
-
async addWorkspaceMember(workspaceId: string, request: AddWorkspaceMemberRequest): Promise<WorkspaceMember> {
|
|
787
|
-
return await this.requestJson<WorkspaceMember>("POST", `/v1/workspaces/${workspaceId}/members`, request);
|
|
1361
|
+
async createRig(workspaceId: string, request: CreateRigRequest): Promise<Rig> {
|
|
1362
|
+
return await this.requestJson<Rig>("POST", `/v1/workspaces/${workspaceId}/rigs`, request);
|
|
788
1363
|
}
|
|
789
1364
|
|
|
790
|
-
async
|
|
791
|
-
return await this.requestJson<
|
|
1365
|
+
async getRig(workspaceId: string, rigId: string): Promise<Rig> {
|
|
1366
|
+
return await this.requestJson<Rig>("GET", `/v1/workspaces/${workspaceId}/rigs/${rigId}`);
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
async updateRig(workspaceId: string, rigId: string, request: UpdateRigRequest): Promise<Rig> {
|
|
1370
|
+
return await this.requestJson<Rig>(
|
|
792
1371
|
"PATCH",
|
|
793
|
-
`/v1/workspaces/${workspaceId}/
|
|
1372
|
+
`/v1/workspaces/${workspaceId}/rigs/${rigId}`,
|
|
794
1373
|
request,
|
|
795
1374
|
);
|
|
796
1375
|
}
|
|
797
1376
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
* member who can still manage the workspace.
|
|
801
|
-
*/
|
|
802
|
-
async removeWorkspaceMember(workspaceId: string, subjectId: string): Promise<void> {
|
|
803
|
-
await this.requestVoid("DELETE", `/v1/workspaces/${workspaceId}/members/${encodeURIComponent(subjectId)}`);
|
|
1377
|
+
async deleteRig(workspaceId: string, rigId: string): Promise<void> {
|
|
1378
|
+
await this.requestJson<unknown>("DELETE", `/v1/workspaces/${workspaceId}/rigs/${rigId}`);
|
|
804
1379
|
}
|
|
805
1380
|
|
|
806
|
-
|
|
1381
|
+
async listRigVersions(workspaceId: string, rigId: string): Promise<RigVersion[]> {
|
|
1382
|
+
return await this.requestJson<RigVersion[]>(
|
|
1383
|
+
"GET",
|
|
1384
|
+
`/v1/workspaces/${workspaceId}/rigs/${rigId}/versions`,
|
|
1385
|
+
);
|
|
1386
|
+
}
|
|
807
1387
|
|
|
808
|
-
|
|
809
|
-
|
|
1388
|
+
/** Roll the active version to an existing one (rollback / promote-activate). */
|
|
1389
|
+
async activateRigVersion(
|
|
1390
|
+
workspaceId: string,
|
|
1391
|
+
rigId: string,
|
|
1392
|
+
versionId: string,
|
|
1393
|
+
): Promise<RigVersion> {
|
|
1394
|
+
return await this.requestJson<RigVersion>(
|
|
1395
|
+
"POST",
|
|
1396
|
+
`/v1/workspaces/${workspaceId}/rigs/${rigId}/versions/${versionId}/activate`,
|
|
1397
|
+
);
|
|
810
1398
|
}
|
|
811
1399
|
|
|
812
|
-
async
|
|
813
|
-
return await this.requestJson<
|
|
1400
|
+
async listRigChanges(workspaceId: string, rigId: string): Promise<RigChange[]> {
|
|
1401
|
+
return await this.requestJson<RigChange[]>(
|
|
1402
|
+
"GET",
|
|
1403
|
+
`/v1/workspaces/${workspaceId}/rigs/${rigId}/changes`,
|
|
1404
|
+
);
|
|
814
1405
|
}
|
|
815
1406
|
|
|
816
|
-
|
|
817
|
-
|
|
1407
|
+
/** Propose a change against the rig's active version (rigs:use). */
|
|
1408
|
+
async proposeRigChange(
|
|
1409
|
+
workspaceId: string,
|
|
1410
|
+
rigId: string,
|
|
1411
|
+
request: ProposeRigChangeRequest,
|
|
1412
|
+
): Promise<RigChange> {
|
|
1413
|
+
return await this.requestJson<RigChange>(
|
|
1414
|
+
"POST",
|
|
1415
|
+
`/v1/workspaces/${workspaceId}/rigs/${rigId}/changes`,
|
|
1416
|
+
request,
|
|
1417
|
+
);
|
|
818
1418
|
}
|
|
819
1419
|
|
|
820
|
-
async
|
|
821
|
-
return await this.requestJson<
|
|
1420
|
+
async getRigChange(workspaceId: string, rigId: string, changeId: string): Promise<RigChange> {
|
|
1421
|
+
return await this.requestJson<RigChange>(
|
|
1422
|
+
"GET",
|
|
1423
|
+
`/v1/workspaces/${workspaceId}/rigs/${rigId}/changes/${changeId}`,
|
|
1424
|
+
);
|
|
822
1425
|
}
|
|
823
1426
|
|
|
824
1427
|
/**
|
|
825
|
-
*
|
|
826
|
-
*
|
|
827
|
-
*
|
|
1428
|
+
* Re-run verification for a change (rigs:use). Verification is asynchronous:
|
|
1429
|
+
* this returns the change immediately with status `verifying`; poll
|
|
1430
|
+
* `getRigChange`/`listRigChanges` for the terminal outcome + logs.
|
|
828
1431
|
*/
|
|
829
|
-
async
|
|
830
|
-
return await this.requestJson<
|
|
1432
|
+
async verifyRigChange(workspaceId: string, rigId: string, changeId: string): Promise<RigChange> {
|
|
1433
|
+
return await this.requestJson<RigChange>(
|
|
831
1434
|
"POST",
|
|
832
|
-
`/v1/workspaces/${workspaceId}/
|
|
833
|
-
options.triggerId ? { triggerId: options.triggerId } : undefined,
|
|
1435
|
+
`/v1/workspaces/${workspaceId}/rigs/${rigId}/changes/${changeId}/verify`,
|
|
834
1436
|
);
|
|
835
1437
|
}
|
|
836
1438
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
1439
|
+
/**
|
|
1440
|
+
* Promote a verified `definition_edit` change into a new active rig version
|
|
1441
|
+
* (rigs:manage). Only valid once the change's verification passed; returns the
|
|
1442
|
+
* newly minted version.
|
|
1443
|
+
*/
|
|
1444
|
+
async promoteRigChange(
|
|
842
1445
|
workspaceId: string,
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
): Promise<
|
|
846
|
-
return await this.requestJson<
|
|
847
|
-
"
|
|
848
|
-
`/v1/workspaces/${workspaceId}/
|
|
849
|
-
undefined,
|
|
850
|
-
{ ...(options.limit !== undefined ? { limit: String(options.limit) } : {}) },
|
|
1446
|
+
rigId: string,
|
|
1447
|
+
changeId: string,
|
|
1448
|
+
): Promise<RigVersion> {
|
|
1449
|
+
return await this.requestJson<RigVersion>(
|
|
1450
|
+
"POST",
|
|
1451
|
+
`/v1/workspaces/${workspaceId}/rigs/${rigId}/changes/${changeId}/promote`,
|
|
851
1452
|
);
|
|
852
1453
|
}
|
|
853
1454
|
|
|
854
|
-
|
|
855
|
-
|
|
1455
|
+
/**
|
|
1456
|
+
* Re-run the active version's checks in a clean throwaway sandbox (rigs:use).
|
|
1457
|
+
* Asynchronous — returns the version id being verified; the outcome lands on
|
|
1458
|
+
* the version's audit trail.
|
|
1459
|
+
*/
|
|
1460
|
+
async verifyRig(workspaceId: string, rigId: string): Promise<{ ok: boolean; versionId: string }> {
|
|
1461
|
+
return await this.requestJson<{ ok: boolean; versionId: string }>(
|
|
1462
|
+
"POST",
|
|
1463
|
+
`/v1/workspaces/${workspaceId}/rigs/${rigId}/verify`,
|
|
1464
|
+
);
|
|
1465
|
+
}
|
|
856
1466
|
|
|
857
|
-
|
|
858
|
-
|
|
1467
|
+
/** @deprecated use listVariableSets */
|
|
1468
|
+
async listEnvironments(workspaceId: string): Promise<VariableSet[]> {
|
|
1469
|
+
return await this.listVariableSets(workspaceId);
|
|
859
1470
|
}
|
|
860
1471
|
|
|
861
|
-
|
|
862
|
-
|
|
1472
|
+
/** @deprecated use createVariableSet */
|
|
1473
|
+
async createEnvironment(
|
|
1474
|
+
workspaceId: string,
|
|
1475
|
+
request: CreateVariableSetRequest,
|
|
1476
|
+
): Promise<VariableSet> {
|
|
1477
|
+
return await this.createVariableSet(workspaceId, request);
|
|
863
1478
|
}
|
|
864
1479
|
|
|
865
|
-
|
|
866
|
-
|
|
1480
|
+
/** @deprecated use getVariableSet */
|
|
1481
|
+
async getEnvironment(workspaceId: string, environmentId: string): Promise<VariableSet> {
|
|
1482
|
+
return await this.getVariableSet(workspaceId, environmentId);
|
|
867
1483
|
}
|
|
868
1484
|
|
|
1485
|
+
/** @deprecated use updateVariableSet */
|
|
869
1486
|
async updateEnvironment(
|
|
870
1487
|
workspaceId: string,
|
|
871
1488
|
environmentId: string,
|
|
872
|
-
request:
|
|
873
|
-
): Promise<
|
|
874
|
-
return await this.
|
|
875
|
-
"PATCH",
|
|
876
|
-
`/v1/workspaces/${workspaceId}/environments/${environmentId}`,
|
|
877
|
-
request,
|
|
878
|
-
);
|
|
1489
|
+
request: UpdateVariableSetRequest,
|
|
1490
|
+
): Promise<VariableSet> {
|
|
1491
|
+
return await this.updateVariableSet(workspaceId, environmentId, request);
|
|
879
1492
|
}
|
|
880
1493
|
|
|
1494
|
+
/** @deprecated use deleteVariableSet */
|
|
881
1495
|
async deleteEnvironment(workspaceId: string, environmentId: string): Promise<void> {
|
|
882
|
-
await this.
|
|
1496
|
+
await this.deleteVariableSet(workspaceId, environmentId);
|
|
883
1497
|
}
|
|
884
1498
|
|
|
885
|
-
/**
|
|
1499
|
+
/** @deprecated use setVariableSetVariable */
|
|
886
1500
|
async setEnvironmentVariable(
|
|
887
1501
|
workspaceId: string,
|
|
888
1502
|
environmentId: string,
|
|
889
1503
|
name: string,
|
|
890
1504
|
value: string,
|
|
891
|
-
): Promise<
|
|
892
|
-
return await this.
|
|
893
|
-
"PUT",
|
|
894
|
-
`/v1/workspaces/${workspaceId}/environments/${environmentId}/variables/${encodeURIComponent(name)}`,
|
|
895
|
-
{ value },
|
|
896
|
-
);
|
|
1505
|
+
): Promise<VariableSetVariableMetadata> {
|
|
1506
|
+
return await this.setVariableSetVariable(workspaceId, environmentId, name, value);
|
|
897
1507
|
}
|
|
898
1508
|
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
1509
|
+
/** @deprecated use deleteVariableSetVariable */
|
|
1510
|
+
async deleteEnvironmentVariable(
|
|
1511
|
+
workspaceId: string,
|
|
1512
|
+
environmentId: string,
|
|
1513
|
+
name: string,
|
|
1514
|
+
): Promise<void> {
|
|
1515
|
+
await this.deleteVariableSetVariable(workspaceId, environmentId, name);
|
|
904
1516
|
}
|
|
905
1517
|
|
|
906
1518
|
// --- Files -----------------------------------------------------------------------
|
|
907
1519
|
|
|
908
1520
|
/** Step 1 of the upload flow: returns the pre-signed PUT target. */
|
|
909
|
-
async beginFileUpload(
|
|
910
|
-
|
|
1521
|
+
async beginFileUpload(
|
|
1522
|
+
workspaceId: string,
|
|
1523
|
+
request: CreateFileUploadRequest,
|
|
1524
|
+
): Promise<CreateFileUploadResponse> {
|
|
1525
|
+
return await this.requestJson<CreateFileUploadResponse>(
|
|
1526
|
+
"POST",
|
|
1527
|
+
`/v1/workspaces/${workspaceId}/files/uploads`,
|
|
1528
|
+
request,
|
|
1529
|
+
);
|
|
911
1530
|
}
|
|
912
1531
|
|
|
913
1532
|
/** Step 3 of the upload flow: server verifies the object and marks it ready. */
|
|
@@ -927,12 +1546,14 @@ export class OpenGeniClient {
|
|
|
927
1546
|
async uploadFile(workspaceId: string, input: UploadFileInput): Promise<FileAsset> {
|
|
928
1547
|
// Copy Uint8Array views into a Blob so byte offsets/shared buffers can't
|
|
929
1548
|
// leak surrounding bytes into the PUT body.
|
|
930
|
-
const body: Blob | ArrayBuffer | string =
|
|
931
|
-
? new Blob([input.data.slice()])
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
1549
|
+
const body: Blob | ArrayBuffer | string =
|
|
1550
|
+
input.data instanceof Uint8Array ? new Blob([input.data.slice()]) : input.data;
|
|
1551
|
+
const sizeBytes =
|
|
1552
|
+
typeof body === "string"
|
|
1553
|
+
? new TextEncoder().encode(body).byteLength
|
|
1554
|
+
: body instanceof Blob
|
|
1555
|
+
? body.size
|
|
1556
|
+
: body.byteLength;
|
|
936
1557
|
const upload = await this.beginFileUpload(workspaceId, {
|
|
937
1558
|
filename: input.filename,
|
|
938
1559
|
contentType: input.contentType,
|
|
@@ -957,39 +1578,76 @@ export class OpenGeniClient {
|
|
|
957
1578
|
}
|
|
958
1579
|
|
|
959
1580
|
async getFile(workspaceId: string, fileId: string): Promise<FileAsset> {
|
|
960
|
-
return await this.requestJson<FileAsset>(
|
|
1581
|
+
return await this.requestJson<FileAsset>(
|
|
1582
|
+
"GET",
|
|
1583
|
+
`/v1/workspaces/${workspaceId}/files/${fileId}`,
|
|
1584
|
+
);
|
|
961
1585
|
}
|
|
962
1586
|
|
|
963
1587
|
/** Mint a short-lived signed download URL for a ready file. */
|
|
964
|
-
async createFileDownloadUrl(
|
|
965
|
-
|
|
1588
|
+
async createFileDownloadUrl(
|
|
1589
|
+
workspaceId: string,
|
|
1590
|
+
fileId: string,
|
|
1591
|
+
): Promise<FileDownloadUrlResponse> {
|
|
1592
|
+
return await this.requestJson<FileDownloadUrlResponse>(
|
|
1593
|
+
"POST",
|
|
1594
|
+
`/v1/workspaces/${workspaceId}/files/${fileId}/download-url`,
|
|
1595
|
+
);
|
|
966
1596
|
}
|
|
967
1597
|
|
|
968
1598
|
// --- Documents ----------------------------------------------------------------------
|
|
969
1599
|
|
|
970
|
-
async createDocumentBase(
|
|
971
|
-
|
|
1600
|
+
async createDocumentBase(
|
|
1601
|
+
workspaceId: string,
|
|
1602
|
+
request: CreateDocumentBaseRequest,
|
|
1603
|
+
): Promise<DocumentBase> {
|
|
1604
|
+
return await this.requestJson<DocumentBase>(
|
|
1605
|
+
"POST",
|
|
1606
|
+
`/v1/workspaces/${workspaceId}/document-bases`,
|
|
1607
|
+
request,
|
|
1608
|
+
);
|
|
972
1609
|
}
|
|
973
1610
|
|
|
974
1611
|
async listDocumentBases(workspaceId: string): Promise<DocumentBase[]> {
|
|
975
|
-
return await this.requestJson<DocumentBase[]>(
|
|
1612
|
+
return await this.requestJson<DocumentBase[]>(
|
|
1613
|
+
"GET",
|
|
1614
|
+
`/v1/workspaces/${workspaceId}/document-bases`,
|
|
1615
|
+
);
|
|
976
1616
|
}
|
|
977
1617
|
|
|
978
1618
|
async getDocumentBase(workspaceId: string, baseId: string): Promise<DocumentBase> {
|
|
979
|
-
return await this.requestJson<DocumentBase>(
|
|
1619
|
+
return await this.requestJson<DocumentBase>(
|
|
1620
|
+
"GET",
|
|
1621
|
+
`/v1/workspaces/${workspaceId}/document-bases/${baseId}`,
|
|
1622
|
+
);
|
|
980
1623
|
}
|
|
981
1624
|
|
|
982
1625
|
/** Index an uploaded file into the base. The file must be `ready`. */
|
|
983
|
-
async addDocument(
|
|
984
|
-
|
|
1626
|
+
async addDocument(
|
|
1627
|
+
workspaceId: string,
|
|
1628
|
+
baseId: string,
|
|
1629
|
+
request: AddDocumentRequest,
|
|
1630
|
+
): Promise<Document> {
|
|
1631
|
+
return await this.requestJson<Document>(
|
|
1632
|
+
"POST",
|
|
1633
|
+
`/v1/workspaces/${workspaceId}/document-bases/${baseId}/documents`,
|
|
1634
|
+
request,
|
|
1635
|
+
);
|
|
985
1636
|
}
|
|
986
1637
|
|
|
987
1638
|
async listDocuments(workspaceId: string, baseId: string): Promise<Document[]> {
|
|
988
|
-
return await this.requestJson<Document[]>(
|
|
1639
|
+
return await this.requestJson<Document[]>(
|
|
1640
|
+
"GET",
|
|
1641
|
+
`/v1/workspaces/${workspaceId}/document-bases/${baseId}/documents`,
|
|
1642
|
+
);
|
|
989
1643
|
}
|
|
990
1644
|
|
|
991
1645
|
/** Retry indexing for a failed document. */
|
|
992
|
-
async reindexDocument(
|
|
1646
|
+
async reindexDocument(
|
|
1647
|
+
workspaceId: string,
|
|
1648
|
+
baseId: string,
|
|
1649
|
+
documentId: string,
|
|
1650
|
+
): Promise<Document> {
|
|
993
1651
|
return await this.requestJson<Document>(
|
|
994
1652
|
"POST",
|
|
995
1653
|
`/v1/workspaces/${workspaceId}/document-bases/${baseId}/documents/${documentId}/reindex`,
|
|
@@ -1023,10 +1681,17 @@ export class OpenGeniClient {
|
|
|
1023
1681
|
workspaceId: string,
|
|
1024
1682
|
request: DocumentSearchRequest,
|
|
1025
1683
|
): Promise<DocumentSearchResponse> {
|
|
1026
|
-
return await this.requestJson<DocumentSearchResponse>(
|
|
1684
|
+
return await this.requestJson<DocumentSearchResponse>(
|
|
1685
|
+
"POST",
|
|
1686
|
+
`/v1/workspaces/${workspaceId}/knowledge/search`,
|
|
1687
|
+
request,
|
|
1688
|
+
);
|
|
1027
1689
|
}
|
|
1028
1690
|
|
|
1029
|
-
async listKnowledgeMemories(
|
|
1691
|
+
async listKnowledgeMemories(
|
|
1692
|
+
workspaceId: string,
|
|
1693
|
+
request: KnowledgeMemorySearchRequest = {},
|
|
1694
|
+
): Promise<KnowledgeMemory[]> {
|
|
1030
1695
|
const params = new URLSearchParams();
|
|
1031
1696
|
if (request.query) params.set("query", request.query);
|
|
1032
1697
|
if (request.status) params.set("status", request.status);
|
|
@@ -1034,19 +1699,75 @@ export class OpenGeniClient {
|
|
|
1034
1699
|
if (request.scope) params.set("scope", request.scope);
|
|
1035
1700
|
if (request.limit) params.set("limit", String(request.limit));
|
|
1036
1701
|
const query = params.toString();
|
|
1037
|
-
return await this.requestJson<KnowledgeMemory[]>(
|
|
1702
|
+
return await this.requestJson<KnowledgeMemory[]>(
|
|
1703
|
+
"GET",
|
|
1704
|
+
`/v1/workspaces/${workspaceId}/knowledge/memories${query ? `?${query}` : ""}`,
|
|
1705
|
+
);
|
|
1038
1706
|
}
|
|
1039
1707
|
|
|
1040
1708
|
async getKnowledgeMemory(workspaceId: string, memoryId: string): Promise<KnowledgeMemory> {
|
|
1041
|
-
return await this.requestJson<KnowledgeMemory>(
|
|
1709
|
+
return await this.requestJson<KnowledgeMemory>(
|
|
1710
|
+
"GET",
|
|
1711
|
+
`/v1/workspaces/${workspaceId}/knowledge/memories/${memoryId}`,
|
|
1712
|
+
);
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
async createKnowledgeMemory(
|
|
1716
|
+
workspaceId: string,
|
|
1717
|
+
request: CreateKnowledgeMemoryRequest,
|
|
1718
|
+
): Promise<KnowledgeMemory> {
|
|
1719
|
+
return await this.requestJson<KnowledgeMemory>(
|
|
1720
|
+
"POST",
|
|
1721
|
+
`/v1/workspaces/${workspaceId}/knowledge/memories`,
|
|
1722
|
+
request,
|
|
1723
|
+
);
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
async updateKnowledgeMemory(
|
|
1727
|
+
workspaceId: string,
|
|
1728
|
+
memoryId: string,
|
|
1729
|
+
request: UpdateKnowledgeMemoryRequest,
|
|
1730
|
+
): Promise<KnowledgeMemory> {
|
|
1731
|
+
return await this.requestJson<KnowledgeMemory>(
|
|
1732
|
+
"PATCH",
|
|
1733
|
+
`/v1/workspaces/${workspaceId}/knowledge/memories/${memoryId}`,
|
|
1734
|
+
request,
|
|
1735
|
+
);
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
/** Hybrid (semantic + keyword) search over the workspace's agent-visible memory. */
|
|
1739
|
+
async searchWorkspaceMemories(
|
|
1740
|
+
workspaceId: string,
|
|
1741
|
+
request: WorkspaceMemorySearchRequest,
|
|
1742
|
+
): Promise<WorkspaceMemorySearchResponse> {
|
|
1743
|
+
return await this.requestJson<WorkspaceMemorySearchResponse>(
|
|
1744
|
+
"POST",
|
|
1745
|
+
`/v1/workspaces/${workspaceId}/knowledge/memories/search`,
|
|
1746
|
+
request,
|
|
1747
|
+
);
|
|
1042
1748
|
}
|
|
1043
1749
|
|
|
1044
|
-
|
|
1045
|
-
|
|
1750
|
+
/** Deep-merge a settings patch into the workspace (preserves unknown keys). */
|
|
1751
|
+
async updateWorkspaceSettings(
|
|
1752
|
+
workspaceId: string,
|
|
1753
|
+
request: UpdateWorkspaceSettingsRequest,
|
|
1754
|
+
): Promise<Workspace> {
|
|
1755
|
+
return await this.requestJson<Workspace>(
|
|
1756
|
+
"PATCH",
|
|
1757
|
+
`/v1/workspaces/${workspaceId}/settings`,
|
|
1758
|
+
request,
|
|
1759
|
+
);
|
|
1046
1760
|
}
|
|
1047
1761
|
|
|
1048
|
-
async
|
|
1049
|
-
|
|
1762
|
+
async setWorkspaceDefaultRig(
|
|
1763
|
+
workspaceId: string,
|
|
1764
|
+
request: SetWorkspaceDefaultRigRequest,
|
|
1765
|
+
): Promise<Workspace> {
|
|
1766
|
+
return await this.requestJson<Workspace>(
|
|
1767
|
+
"PUT",
|
|
1768
|
+
`/v1/workspaces/${workspaceId}/default-rig`,
|
|
1769
|
+
request,
|
|
1770
|
+
);
|
|
1050
1771
|
}
|
|
1051
1772
|
|
|
1052
1773
|
// --- Capability packs ------------------------------------------------------------------
|
|
@@ -1057,15 +1778,29 @@ export class OpenGeniClient {
|
|
|
1057
1778
|
}
|
|
1058
1779
|
|
|
1059
1780
|
/** Register (or replace) a workspace-scoped pack from a manifest. */
|
|
1060
|
-
async registerPack(
|
|
1061
|
-
|
|
1781
|
+
async registerPack(
|
|
1782
|
+
workspaceId: string,
|
|
1783
|
+
manifest: RegisterCapabilityPackRequest,
|
|
1784
|
+
): Promise<WorkspaceRegisteredPack> {
|
|
1785
|
+
return await this.requestJson<WorkspaceRegisteredPack>(
|
|
1786
|
+
"POST",
|
|
1787
|
+
`/v1/workspaces/${workspaceId}/packs`,
|
|
1788
|
+
manifest,
|
|
1789
|
+
);
|
|
1062
1790
|
}
|
|
1063
1791
|
|
|
1064
1792
|
async getPack(workspaceId: string, packId: string): Promise<GetPackResponse> {
|
|
1065
|
-
return await this.requestJson<GetPackResponse>(
|
|
1793
|
+
return await this.requestJson<GetPackResponse>(
|
|
1794
|
+
"GET",
|
|
1795
|
+
`/v1/workspaces/${workspaceId}/packs/${encodeURIComponent(packId)}`,
|
|
1796
|
+
);
|
|
1066
1797
|
}
|
|
1067
1798
|
|
|
1068
|
-
async enablePack(
|
|
1799
|
+
async enablePack(
|
|
1800
|
+
workspaceId: string,
|
|
1801
|
+
packId: string,
|
|
1802
|
+
request: EnablePackRequest = {},
|
|
1803
|
+
): Promise<PackInstallation> {
|
|
1069
1804
|
return await this.requestJson<PackInstallation>(
|
|
1070
1805
|
"POST",
|
|
1071
1806
|
`/v1/workspaces/${workspaceId}/packs/${encodeURIComponent(packId)}/enable`,
|
|
@@ -1075,22 +1810,38 @@ export class OpenGeniClient {
|
|
|
1075
1810
|
|
|
1076
1811
|
/** Unregister a workspace-scoped pack (built-in packs cannot be deleted). */
|
|
1077
1812
|
async deletePack(workspaceId: string, packId: string): Promise<void> {
|
|
1078
|
-
await this.requestVoid(
|
|
1813
|
+
await this.requestVoid(
|
|
1814
|
+
"DELETE",
|
|
1815
|
+
`/v1/workspaces/${workspaceId}/packs/${encodeURIComponent(packId)}`,
|
|
1816
|
+
);
|
|
1079
1817
|
}
|
|
1080
1818
|
|
|
1081
1819
|
async listPackInstallations(workspaceId: string): Promise<PackInstallation[]> {
|
|
1082
|
-
return await this.requestJson<PackInstallation[]>(
|
|
1820
|
+
return await this.requestJson<PackInstallation[]>(
|
|
1821
|
+
"GET",
|
|
1822
|
+
`/v1/workspaces/${workspaceId}/packs/installations`,
|
|
1823
|
+
);
|
|
1083
1824
|
}
|
|
1084
1825
|
|
|
1085
1826
|
// --- Capabilities -------------------------------------------------------------------------
|
|
1086
1827
|
|
|
1087
1828
|
async listCapabilities(workspaceId: string): Promise<CapabilityCatalogResponse> {
|
|
1088
|
-
return await this.requestJson<CapabilityCatalogResponse>(
|
|
1829
|
+
return await this.requestJson<CapabilityCatalogResponse>(
|
|
1830
|
+
"GET",
|
|
1831
|
+
`/v1/workspaces/${workspaceId}/capabilities`,
|
|
1832
|
+
);
|
|
1089
1833
|
}
|
|
1090
1834
|
|
|
1091
1835
|
/** Add a manual capability catalog item (e.g. a remote MCP server). */
|
|
1092
|
-
async createCapability(
|
|
1093
|
-
|
|
1836
|
+
async createCapability(
|
|
1837
|
+
workspaceId: string,
|
|
1838
|
+
request: CreateCapabilityCatalogItemRequest,
|
|
1839
|
+
): Promise<CapabilityCatalogItem> {
|
|
1840
|
+
return await this.requestJson<CapabilityCatalogItem>(
|
|
1841
|
+
"POST",
|
|
1842
|
+
`/v1/workspaces/${workspaceId}/capabilities`,
|
|
1843
|
+
request,
|
|
1844
|
+
);
|
|
1094
1845
|
}
|
|
1095
1846
|
|
|
1096
1847
|
async enableCapability(
|
|
@@ -1105,7 +1856,10 @@ export class OpenGeniClient {
|
|
|
1105
1856
|
);
|
|
1106
1857
|
}
|
|
1107
1858
|
|
|
1108
|
-
async disableCapability(
|
|
1859
|
+
async disableCapability(
|
|
1860
|
+
workspaceId: string,
|
|
1861
|
+
capabilityId: string,
|
|
1862
|
+
): Promise<CapabilityInstallation> {
|
|
1109
1863
|
return await this.requestJson<CapabilityInstallation>(
|
|
1110
1864
|
"POST",
|
|
1111
1865
|
`/v1/workspaces/${workspaceId}/capabilities/${encodeURIComponent(capabilityId)}/disable`,
|
|
@@ -1128,6 +1882,66 @@ export class OpenGeniClient {
|
|
|
1128
1882
|
);
|
|
1129
1883
|
}
|
|
1130
1884
|
|
|
1885
|
+
// --- Connections -------------------------------------------------------------------------------
|
|
1886
|
+
|
|
1887
|
+
async listConnections(workspaceId: string): Promise<ConnectionMetadata[]> {
|
|
1888
|
+
const response = await this.requestJson<ListConnectionsResponse>(
|
|
1889
|
+
"GET",
|
|
1890
|
+
`/v1/workspaces/${workspaceId}/connections`,
|
|
1891
|
+
);
|
|
1892
|
+
return response.connections;
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
async createConnection(
|
|
1896
|
+
workspaceId: string,
|
|
1897
|
+
request: CreateConnectionRequest,
|
|
1898
|
+
): Promise<ConnectionMetadata> {
|
|
1899
|
+
const response = await this.requestJson<ConnectionResponse>(
|
|
1900
|
+
"POST",
|
|
1901
|
+
`/v1/workspaces/${workspaceId}/connections`,
|
|
1902
|
+
request,
|
|
1903
|
+
);
|
|
1904
|
+
return response.connection;
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
async updateConnection(
|
|
1908
|
+
workspaceId: string,
|
|
1909
|
+
connectionId: string,
|
|
1910
|
+
request: UpdateConnectionRequest,
|
|
1911
|
+
): Promise<ConnectionMetadata> {
|
|
1912
|
+
const response = await this.requestJson<ConnectionResponse>(
|
|
1913
|
+
"PATCH",
|
|
1914
|
+
`/v1/workspaces/${workspaceId}/connections/${connectionId}`,
|
|
1915
|
+
request,
|
|
1916
|
+
);
|
|
1917
|
+
return response.connection;
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
async deleteConnection(workspaceId: string, connectionId: string): Promise<ConnectionMetadata> {
|
|
1921
|
+
const response = await this.requestJson<ConnectionResponse>(
|
|
1922
|
+
"DELETE",
|
|
1923
|
+
`/v1/workspaces/${workspaceId}/connections/${connectionId}`,
|
|
1924
|
+
);
|
|
1925
|
+
return response.connection;
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
/** Start an OAuth connection flow; redirect the user to the returned `authorizationUrl`. */
|
|
1929
|
+
async startConnectionOAuth(
|
|
1930
|
+
workspaceId: string,
|
|
1931
|
+
request: OAuthStartRequest,
|
|
1932
|
+
): Promise<OAuthStartResponse> {
|
|
1933
|
+
return await this.requestJson<OAuthStartResponse>(
|
|
1934
|
+
"POST",
|
|
1935
|
+
`/v1/workspaces/${workspaceId}/connections/oauth/start`,
|
|
1936
|
+
request,
|
|
1937
|
+
);
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
/** Public, immutably-cached URL for a catalog item's logo, or null when the item has none. */
|
|
1941
|
+
catalogAssetUrl(logoAssetPath: string | null): string | null {
|
|
1942
|
+
return logoAssetPath ? `${this.baseUrl}/v1/${logoAssetPath}` : null;
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1131
1945
|
// --- GitHub ----------------------------------------------------------------------------------
|
|
1132
1946
|
|
|
1133
1947
|
/** GitHub App configuration status + a signed install URL when configured. */
|
|
@@ -1145,12 +1959,18 @@ export class OpenGeniClient {
|
|
|
1145
1959
|
}
|
|
1146
1960
|
|
|
1147
1961
|
async listGitHubRepositories(workspaceId: string): Promise<GitHubRepositoriesResponse> {
|
|
1148
|
-
return await this.requestJson<GitHubRepositoriesResponse>(
|
|
1962
|
+
return await this.requestJson<GitHubRepositoriesResponse>(
|
|
1963
|
+
"GET",
|
|
1964
|
+
`/v1/workspaces/${workspaceId}/github/repositories`,
|
|
1965
|
+
);
|
|
1149
1966
|
}
|
|
1150
1967
|
|
|
1151
1968
|
/** Re-sync the installation's repository list from GitHub. */
|
|
1152
1969
|
async syncGitHubRepositories(workspaceId: string): Promise<GitHubRepositoriesResponse> {
|
|
1153
|
-
return await this.requestJson<GitHubRepositoriesResponse>(
|
|
1970
|
+
return await this.requestJson<GitHubRepositoriesResponse>(
|
|
1971
|
+
"POST",
|
|
1972
|
+
`/v1/workspaces/${workspaceId}/github/repositories/sync`,
|
|
1973
|
+
);
|
|
1154
1974
|
}
|
|
1155
1975
|
|
|
1156
1976
|
/** Build a GitHub App manifest + the GitHub URL to submit it to. */
|
|
@@ -1168,18 +1988,31 @@ export class OpenGeniClient {
|
|
|
1168
1988
|
// --- API keys ----------------------------------------------------------------------------------
|
|
1169
1989
|
|
|
1170
1990
|
async listApiKeys(workspaceId: string): Promise<ApiKey[]> {
|
|
1171
|
-
const response = await this.requestJson<ListApiKeysResponse>(
|
|
1991
|
+
const response = await this.requestJson<ListApiKeysResponse>(
|
|
1992
|
+
"GET",
|
|
1993
|
+
`/v1/workspaces/${workspaceId}/api-keys`,
|
|
1994
|
+
);
|
|
1172
1995
|
return response.apiKeys;
|
|
1173
1996
|
}
|
|
1174
1997
|
|
|
1175
1998
|
/** The returned `token` is shown once; only its prefix is stored. */
|
|
1176
|
-
async createApiKey(
|
|
1177
|
-
|
|
1999
|
+
async createApiKey(
|
|
2000
|
+
workspaceId: string,
|
|
2001
|
+
request: CreateApiKeyRequest,
|
|
2002
|
+
): Promise<CreateApiKeyResponse> {
|
|
2003
|
+
return await this.requestJson<CreateApiKeyResponse>(
|
|
2004
|
+
"POST",
|
|
2005
|
+
`/v1/workspaces/${workspaceId}/api-keys`,
|
|
2006
|
+
request,
|
|
2007
|
+
);
|
|
1178
2008
|
}
|
|
1179
2009
|
|
|
1180
2010
|
/** Revoke an API key. Returns the revoked key. */
|
|
1181
2011
|
async deleteApiKey(workspaceId: string, apiKeyId: string): Promise<ApiKey> {
|
|
1182
|
-
return await this.requestJson<ApiKey>(
|
|
2012
|
+
return await this.requestJson<ApiKey>(
|
|
2013
|
+
"DELETE",
|
|
2014
|
+
`/v1/workspaces/${workspaceId}/api-keys/${apiKeyId}`,
|
|
2015
|
+
);
|
|
1183
2016
|
}
|
|
1184
2017
|
|
|
1185
2018
|
// --- Billing (account-scoped) --------------------------------------------------------------------
|
|
@@ -1190,17 +2023,26 @@ export class OpenGeniClient {
|
|
|
1190
2023
|
});
|
|
1191
2024
|
}
|
|
1192
2025
|
|
|
1193
|
-
async getBillingUsage(
|
|
2026
|
+
async getBillingUsage(
|
|
2027
|
+
options: { accountId?: string; workspaceId?: string } = {},
|
|
2028
|
+
): Promise<BillingUsageResponse> {
|
|
1194
2029
|
return await this.requestJson<BillingUsageResponse>("GET", "/v1/billing/usage", undefined, {
|
|
1195
2030
|
...(options.accountId !== undefined ? { accountId: options.accountId } : {}),
|
|
1196
2031
|
...(options.workspaceId !== undefined ? { workspaceId: options.workspaceId } : {}),
|
|
1197
2032
|
});
|
|
1198
2033
|
}
|
|
1199
2034
|
|
|
1200
|
-
async getBillingEntitlements(
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
2035
|
+
async getBillingEntitlements(
|
|
2036
|
+
options: { accountId?: string } = {},
|
|
2037
|
+
): Promise<BillingEntitlementsResponse> {
|
|
2038
|
+
return await this.requestJson<BillingEntitlementsResponse>(
|
|
2039
|
+
"GET",
|
|
2040
|
+
"/v1/billing/entitlements",
|
|
2041
|
+
undefined,
|
|
2042
|
+
{
|
|
2043
|
+
...(options.accountId !== undefined ? { accountId: options.accountId } : {}),
|
|
2044
|
+
},
|
|
2045
|
+
);
|
|
1204
2046
|
}
|
|
1205
2047
|
|
|
1206
2048
|
/** Start a Stripe checkout for prepaid credits. */
|
|
@@ -1211,7 +2053,8 @@ export class OpenGeniClient {
|
|
|
1211
2053
|
// --- Internals -------------------------------------------------------------
|
|
1212
2054
|
|
|
1213
2055
|
private headers(): Record<string, string> {
|
|
1214
|
-
const extra =
|
|
2056
|
+
const extra =
|
|
2057
|
+
typeof this.options.headers === "function" ? this.options.headers() : this.options.headers;
|
|
1215
2058
|
return {
|
|
1216
2059
|
...(this.options.apiKey ? { Authorization: `Bearer ${this.options.apiKey}` } : {}),
|
|
1217
2060
|
...extra,
|
|
@@ -1227,17 +2070,27 @@ export class OpenGeniClient {
|
|
|
1227
2070
|
|
|
1228
2071
|
/** Connection state + the codex models the workspace may select (empty until connected). */
|
|
1229
2072
|
async codexStatus(workspaceId: string): Promise<CodexConnectionStatus> {
|
|
1230
|
-
return await this.requestJson<CodexConnectionStatus>(
|
|
2073
|
+
return await this.requestJson<CodexConnectionStatus>(
|
|
2074
|
+
"GET",
|
|
2075
|
+
`/v1/workspaces/${workspaceId}/codex/status`,
|
|
2076
|
+
);
|
|
1231
2077
|
}
|
|
1232
2078
|
|
|
1233
2079
|
/** Begin device-code login: show `userCode` at `verificationUri`, then poll with `state`. */
|
|
1234
2080
|
async codexConnectStart(workspaceId: string): Promise<CodexConnectStart> {
|
|
1235
|
-
return await this.requestJson<CodexConnectStart>(
|
|
2081
|
+
return await this.requestJson<CodexConnectStart>(
|
|
2082
|
+
"POST",
|
|
2083
|
+
`/v1/workspaces/${workspaceId}/codex/connect/start`,
|
|
2084
|
+
);
|
|
1236
2085
|
}
|
|
1237
2086
|
|
|
1238
2087
|
/** Poll device-code authorization with the `state` from {@link codexConnectStart}. */
|
|
1239
2088
|
async codexConnectPoll(workspaceId: string, state: string): Promise<CodexConnectPoll> {
|
|
1240
|
-
return await this.requestJson<CodexConnectPoll>(
|
|
2089
|
+
return await this.requestJson<CodexConnectPoll>(
|
|
2090
|
+
"POST",
|
|
2091
|
+
`/v1/workspaces/${workspaceId}/codex/connect/poll`,
|
|
2092
|
+
{ state },
|
|
2093
|
+
);
|
|
1241
2094
|
}
|
|
1242
2095
|
|
|
1243
2096
|
/** Remaining usage / limits for the connected (ACTIVE) subscription. Back-compat. */
|
|
@@ -1247,53 +2100,105 @@ export class OpenGeniClient {
|
|
|
1247
2100
|
|
|
1248
2101
|
/** Live per-account usage read (refreshes THIS account's bearer; writes the cache). */
|
|
1249
2102
|
async codexAccountUsage(workspaceId: string, accountId: string): Promise<CodexUsage> {
|
|
1250
|
-
return await this.requestJson<CodexUsage>(
|
|
2103
|
+
return await this.requestJson<CodexUsage>(
|
|
2104
|
+
"GET",
|
|
2105
|
+
`/v1/workspaces/${workspaceId}/codex/accounts/${accountId}/usage`,
|
|
2106
|
+
);
|
|
1251
2107
|
}
|
|
1252
2108
|
|
|
1253
2109
|
/** Batched live refresh across every connected account, keyed by credential id. */
|
|
1254
2110
|
async refreshCodexUsage(workspaceId: string): Promise<{ usage: CodexUsageMap }> {
|
|
1255
|
-
return await this.requestJson<{ usage: CodexUsageMap }>(
|
|
2111
|
+
return await this.requestJson<{ usage: CodexUsageMap }>(
|
|
2112
|
+
"POST",
|
|
2113
|
+
`/v1/workspaces/${workspaceId}/codex/usage/refresh`,
|
|
2114
|
+
);
|
|
1256
2115
|
}
|
|
1257
2116
|
|
|
1258
2117
|
/** Disconnect ALL accounts (legacy workspace-wide). Prefer `disconnectCodexAccount`. */
|
|
1259
2118
|
async codexDisconnect(workspaceId: string): Promise<{ disconnected: boolean }> {
|
|
1260
|
-
return await this.requestJson<{ disconnected: boolean }>(
|
|
2119
|
+
return await this.requestJson<{ disconnected: boolean }>(
|
|
2120
|
+
"DELETE",
|
|
2121
|
+
`/v1/workspaces/${workspaceId}/codex`,
|
|
2122
|
+
);
|
|
1261
2123
|
}
|
|
1262
2124
|
|
|
1263
2125
|
/** List every connected Codex account + the workspace active pointer + settings. */
|
|
1264
2126
|
async listCodexAccounts(workspaceId: string): Promise<CodexAccountsResponse> {
|
|
1265
|
-
return await this.requestJson<CodexAccountsResponse>(
|
|
2127
|
+
return await this.requestJson<CodexAccountsResponse>(
|
|
2128
|
+
"GET",
|
|
2129
|
+
`/v1/workspaces/${workspaceId}/codex/accounts`,
|
|
2130
|
+
);
|
|
1266
2131
|
}
|
|
1267
2132
|
|
|
1268
2133
|
/** Switch the workspace ACTIVE Codex account (the one unpinned sessions use). */
|
|
1269
|
-
async activateCodexAccount(
|
|
1270
|
-
|
|
2134
|
+
async activateCodexAccount(
|
|
2135
|
+
workspaceId: string,
|
|
2136
|
+
accountId: string,
|
|
2137
|
+
): Promise<{ activated: boolean; accountId: string }> {
|
|
2138
|
+
return await this.requestJson<{ activated: boolean; accountId: string }>(
|
|
2139
|
+
"POST",
|
|
2140
|
+
`/v1/workspaces/${workspaceId}/codex/accounts/${accountId}/activate`,
|
|
2141
|
+
);
|
|
1271
2142
|
}
|
|
1272
2143
|
|
|
1273
2144
|
/** P3: enable/disable Codex auto-rotation and/or pick the strategy. Returns the effective settings. */
|
|
1274
2145
|
async setCodexRotationSettings(
|
|
1275
2146
|
workspaceId: string,
|
|
1276
|
-
patch: {
|
|
2147
|
+
patch: {
|
|
2148
|
+
rotationEnabled?: boolean;
|
|
2149
|
+
rotationStrategy?: CodexRotationSettings["rotationStrategy"];
|
|
2150
|
+
},
|
|
1277
2151
|
): Promise<CodexRotationSettings> {
|
|
1278
|
-
return await this.requestJson<CodexRotationSettings>(
|
|
2152
|
+
return await this.requestJson<CodexRotationSettings>(
|
|
2153
|
+
"PATCH",
|
|
2154
|
+
`/v1/workspaces/${workspaceId}/codex/settings`,
|
|
2155
|
+
patch,
|
|
2156
|
+
);
|
|
1279
2157
|
}
|
|
1280
2158
|
|
|
1281
2159
|
/** Disconnect ONE Codex account by id (re-picks active when the removed one was active). */
|
|
1282
|
-
async disconnectCodexAccount(
|
|
1283
|
-
|
|
2160
|
+
async disconnectCodexAccount(
|
|
2161
|
+
workspaceId: string,
|
|
2162
|
+
accountId: string,
|
|
2163
|
+
): Promise<{ disconnected: boolean; newActiveId: string | null }> {
|
|
2164
|
+
return await this.requestJson<{ disconnected: boolean; newActiveId: string | null }>(
|
|
2165
|
+
"DELETE",
|
|
2166
|
+
`/v1/workspaces/${workspaceId}/codex/accounts/${accountId}`,
|
|
2167
|
+
);
|
|
1284
2168
|
}
|
|
1285
2169
|
|
|
1286
2170
|
/** Rename a Codex account (label only in P1). */
|
|
1287
|
-
async renameCodexAccount(
|
|
1288
|
-
|
|
2171
|
+
async renameCodexAccount(
|
|
2172
|
+
workspaceId: string,
|
|
2173
|
+
accountId: string,
|
|
2174
|
+
label: string | null,
|
|
2175
|
+
): Promise<CodexAccount> {
|
|
2176
|
+
return await this.requestJson<CodexAccount>(
|
|
2177
|
+
"PATCH",
|
|
2178
|
+
`/v1/workspaces/${workspaceId}/codex/accounts/${accountId}`,
|
|
2179
|
+
{ label },
|
|
2180
|
+
);
|
|
1289
2181
|
}
|
|
1290
2182
|
|
|
1291
2183
|
/** Pin (or unpin via "auto") a session's Codex account. Applies on the next turn. */
|
|
1292
|
-
async pinSessionCodexAccount(
|
|
1293
|
-
|
|
2184
|
+
async pinSessionCodexAccount(
|
|
2185
|
+
workspaceId: string,
|
|
2186
|
+
sessionId: string,
|
|
2187
|
+
target: string,
|
|
2188
|
+
): Promise<{ pinned: string }> {
|
|
2189
|
+
return await this.requestJson<{ pinned: string }>(
|
|
2190
|
+
"POST",
|
|
2191
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/codex-account`,
|
|
2192
|
+
{ target },
|
|
2193
|
+
);
|
|
1294
2194
|
}
|
|
1295
2195
|
|
|
1296
|
-
private async requestJson<T>(
|
|
2196
|
+
private async requestJson<T>(
|
|
2197
|
+
method: string,
|
|
2198
|
+
path: string,
|
|
2199
|
+
body?: unknown,
|
|
2200
|
+
query: Record<string, string> = {},
|
|
2201
|
+
): Promise<T> {
|
|
1297
2202
|
const response = await this.fetchImpl(this.url(path, query), {
|
|
1298
2203
|
method,
|
|
1299
2204
|
headers: {
|
|
@@ -1333,7 +2238,3 @@ async function safeText(response: Response): Promise<string> {
|
|
|
1333
2238
|
return "";
|
|
1334
2239
|
}
|
|
1335
2240
|
}
|
|
1336
|
-
|
|
1337
|
-
function delay(ms: number): Promise<void> {
|
|
1338
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1339
|
-
}
|