@opengeni/sdk 0.13.0 → 0.15.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 +33 -11
- package/dist/index.d.ts +171 -59
- package/dist/index.js +360 -190
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +167 -53
- package/src/errors.ts +13 -0
- package/src/index.ts +26 -2
- package/src/stream.ts +3 -0
- package/src/types.ts +137 -39
- package/src/workspace-control-stream.ts +101 -0
package/dist/index.js
CHANGED
|
@@ -9,6 +9,16 @@ var OpenGeniApiError = class extends Error {
|
|
|
9
9
|
this.body = body;
|
|
10
10
|
}
|
|
11
11
|
};
|
|
12
|
+
var OpenGeniApiContractMismatchError = class extends Error {
|
|
13
|
+
expected;
|
|
14
|
+
actual;
|
|
15
|
+
constructor(expected, actual) {
|
|
16
|
+
super(`OpenGeni API contract mismatch: client expects ${expected}, API serves ${actual}`);
|
|
17
|
+
this.name = "OpenGeniApiContractMismatchError";
|
|
18
|
+
this.expected = expected;
|
|
19
|
+
this.actual = actual;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
12
22
|
var OpenGeniStreamError = class extends Error {
|
|
13
23
|
constructor(message) {
|
|
14
24
|
super(message);
|
|
@@ -114,6 +124,7 @@ async function* streamSessionEvents(transport, options = {}) {
|
|
|
114
124
|
everConnected = true;
|
|
115
125
|
failedAttempts = 0;
|
|
116
126
|
delayMs = baseDelayMs;
|
|
127
|
+
await options.beforeLive?.();
|
|
117
128
|
options.onStateChange?.("live");
|
|
118
129
|
for await (const message of parseSseStream(body)) {
|
|
119
130
|
if (signal?.aborted) {
|
|
@@ -208,6 +219,246 @@ async function sleep(delayMs, signal) {
|
|
|
208
219
|
});
|
|
209
220
|
}
|
|
210
221
|
|
|
222
|
+
// src/workspace-control-stream.ts
|
|
223
|
+
async function* streamWorkspaceControlEvents(transport, options = {}) {
|
|
224
|
+
const signal = options.signal;
|
|
225
|
+
const reconnect = options.reconnect ?? true;
|
|
226
|
+
const baseDelayMs = options.reconnectDelayMs ?? 500;
|
|
227
|
+
const maxDelayMs = options.maxReconnectDelayMs ?? 1e4;
|
|
228
|
+
const maxAttempts = options.maxReconnectAttempts ?? Number.POSITIVE_INFINITY;
|
|
229
|
+
let cursor = options.after ?? 0;
|
|
230
|
+
let failures = 0;
|
|
231
|
+
let delayMs = baseDelayMs;
|
|
232
|
+
let everConnected = false;
|
|
233
|
+
for (; ; ) {
|
|
234
|
+
if (signal?.aborted) return;
|
|
235
|
+
options.onStateChange?.(everConnected || failures > 0 ? "reconnecting" : "connecting");
|
|
236
|
+
const cursorAtOpen = cursor;
|
|
237
|
+
try {
|
|
238
|
+
const body = await transport.openStream(cursor, signal);
|
|
239
|
+
everConnected = true;
|
|
240
|
+
failures = 0;
|
|
241
|
+
delayMs = baseDelayMs;
|
|
242
|
+
await options.beforeLive?.();
|
|
243
|
+
options.onStateChange?.("live");
|
|
244
|
+
for await (const message of parseSseStream(body)) {
|
|
245
|
+
if (signal?.aborted) return;
|
|
246
|
+
const event = parseWorkspaceControlEvent(message.data);
|
|
247
|
+
if (!event || event.sequence <= cursor) continue;
|
|
248
|
+
cursor = event.sequence;
|
|
249
|
+
yield event;
|
|
250
|
+
}
|
|
251
|
+
if (!reconnect) return;
|
|
252
|
+
if (cursor === cursorAtOpen) await sleep2(baseDelayMs, signal);
|
|
253
|
+
continue;
|
|
254
|
+
} catch (error) {
|
|
255
|
+
if (signal?.aborted || isAbortError(error)) return;
|
|
256
|
+
if (!reconnect || !isRetryableStreamError(error)) throw error;
|
|
257
|
+
failures += 1;
|
|
258
|
+
if (failures > maxAttempts) {
|
|
259
|
+
throw new OpenGeniStreamError(
|
|
260
|
+
`workspace control stream gave up after ${maxAttempts} reconnect attempts: ${error instanceof Error ? error.message : String(error)}`
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
await sleep2(delayMs, signal);
|
|
265
|
+
delayMs = Math.min(Math.max(delayMs * 2, baseDelayMs), maxDelayMs);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
function parseWorkspaceControlEvent(data) {
|
|
269
|
+
let value;
|
|
270
|
+
try {
|
|
271
|
+
value = JSON.parse(data);
|
|
272
|
+
} catch {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
if (typeof value !== "object" || value === null || value.type !== "workspace.control.changed" || typeof value.id !== "string" || typeof value.sequence !== "number") {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
return value;
|
|
279
|
+
}
|
|
280
|
+
async function sleep2(delayMs, signal) {
|
|
281
|
+
if (signal?.aborted || delayMs <= 0) return;
|
|
282
|
+
await new Promise((resolve) => {
|
|
283
|
+
const timer = setTimeout(done, delayMs);
|
|
284
|
+
function done() {
|
|
285
|
+
clearTimeout(timer);
|
|
286
|
+
signal?.removeEventListener("abort", done);
|
|
287
|
+
resolve();
|
|
288
|
+
}
|
|
289
|
+
signal?.addEventListener("abort", done, { once: true });
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// src/types.ts
|
|
294
|
+
var SESSION_EVENT_TYPES = [
|
|
295
|
+
"session.created",
|
|
296
|
+
"session.status.changed",
|
|
297
|
+
"session.requiresAction",
|
|
298
|
+
"session.context.compaction.requested",
|
|
299
|
+
"session.context.compacted",
|
|
300
|
+
"session.context.compaction.skipped",
|
|
301
|
+
"session.context.cleared",
|
|
302
|
+
"user.message",
|
|
303
|
+
"user.pause",
|
|
304
|
+
"user.approvalDecision",
|
|
305
|
+
"turn.queued",
|
|
306
|
+
"turn.started",
|
|
307
|
+
"turn.completed",
|
|
308
|
+
"turn.failed",
|
|
309
|
+
"turn.cancelled",
|
|
310
|
+
"turn.superseded",
|
|
311
|
+
"turn.recovery.requested",
|
|
312
|
+
"turn.capacity_waiting",
|
|
313
|
+
"agent.message.delta",
|
|
314
|
+
"agent.message.completed",
|
|
315
|
+
"agent.reasoning.delta",
|
|
316
|
+
"agent.toolCall.created",
|
|
317
|
+
"agent.toolCall.output",
|
|
318
|
+
"agent.model.usage",
|
|
319
|
+
"tool.auth_needed",
|
|
320
|
+
"agent.updated",
|
|
321
|
+
"rig.setup.started",
|
|
322
|
+
"rig.setup.completed",
|
|
323
|
+
"rig.setup.skipped",
|
|
324
|
+
"rig.setup.failed",
|
|
325
|
+
"sandbox.operation.started",
|
|
326
|
+
"sandbox.operation.completed",
|
|
327
|
+
"sandbox.operation.failed",
|
|
328
|
+
"sandbox.command.output.delta",
|
|
329
|
+
"artifact.created",
|
|
330
|
+
"goal.set",
|
|
331
|
+
"goal.updated",
|
|
332
|
+
"goal.completed",
|
|
333
|
+
"goal.paused",
|
|
334
|
+
"goal.resumed",
|
|
335
|
+
"goal.cleared",
|
|
336
|
+
"goal.continuation",
|
|
337
|
+
"system.update.pending",
|
|
338
|
+
"system.update.delivered",
|
|
339
|
+
"session.control.paused",
|
|
340
|
+
"session.control.resumed",
|
|
341
|
+
"session.control.steer_requested",
|
|
342
|
+
"workspace.inference.paused",
|
|
343
|
+
"workspace.inference.resumed",
|
|
344
|
+
"session.queue.changed",
|
|
345
|
+
"session.queue.prompt.cancelled",
|
|
346
|
+
"session.queue.history",
|
|
347
|
+
"turn.event.rejected_late",
|
|
348
|
+
"memory.saved",
|
|
349
|
+
"memory.corrected",
|
|
350
|
+
// Channel-B desktop pixel-plane signals (mirror of contracts SessionEventType;
|
|
351
|
+
// the contract-parity test asserts sorted equality).
|
|
352
|
+
"stream.url.rotated",
|
|
353
|
+
"stream.opened",
|
|
354
|
+
"stream.closed",
|
|
355
|
+
"stream.revoked",
|
|
356
|
+
// Channel-B recording signals (P4.3 — "agent films itself proving the fix").
|
|
357
|
+
"recording.started",
|
|
358
|
+
"recording.available",
|
|
359
|
+
"recording.failed",
|
|
360
|
+
// Channel-A structured-service notifications (P4.4; mirror of contracts
|
|
361
|
+
// SessionEventType — the contract-parity test asserts sorted equality).
|
|
362
|
+
"fs.changed",
|
|
363
|
+
"git.changed",
|
|
364
|
+
"terminal.pty.started",
|
|
365
|
+
"terminal.pty.output.delta",
|
|
366
|
+
"terminal.pty.exited",
|
|
367
|
+
"session.title_set",
|
|
368
|
+
// Multi-account Codex (P1): the session's inference account changed.
|
|
369
|
+
"codex.account.switched",
|
|
370
|
+
// OPE-21 metadata-only per-turn credential selection audit.
|
|
371
|
+
"codex.credential.selected",
|
|
372
|
+
// OPE-21 durable zero-capacity wait lifecycle. These are system/runtime
|
|
373
|
+
// events, never synthetic user messages.
|
|
374
|
+
"codex.capacity.waiting",
|
|
375
|
+
"codex.capacity.resumed",
|
|
376
|
+
"codex.capacity.superseded",
|
|
377
|
+
// Sandbox durability observability (mirror of contracts SessionEventType):
|
|
378
|
+
// box lifecycle + manifest-env drift, attributable from the DB alone.
|
|
379
|
+
"sandbox.box.created",
|
|
380
|
+
"sandbox.box.lost",
|
|
381
|
+
"sandbox.box.terminated",
|
|
382
|
+
"sandbox.box.snapshot",
|
|
383
|
+
"sandbox.env.drift",
|
|
384
|
+
// Active-sandbox pointer reconcile (issue #341; announce-only; mirror of contracts
|
|
385
|
+
// SessionEventType — the contract-parity test asserts sorted equality).
|
|
386
|
+
"session.route.reconciled",
|
|
387
|
+
// Workbench v2 turn-end workspace capture (announce-only; mirror of contracts
|
|
388
|
+
// SessionEventType — the contract-parity test asserts sorted equality).
|
|
389
|
+
"workspace.revision.captured",
|
|
390
|
+
"workspace.revision.degraded",
|
|
391
|
+
// Connected Machine op-outcome observability (announce-only, quiet; mirror of
|
|
392
|
+
// contracts SessionEventType — the contract-parity test asserts sorted equality).
|
|
393
|
+
"machine.op.failed",
|
|
394
|
+
"machine.op.recovered",
|
|
395
|
+
// Connected Machine link-plane observability (announce-only, quiet; mirror of
|
|
396
|
+
// contracts SessionEventType — the contract-parity test asserts sorted equality).
|
|
397
|
+
"machine.link.lost",
|
|
398
|
+
"machine.link.restored",
|
|
399
|
+
"machine.runner.restarted"
|
|
400
|
+
];
|
|
401
|
+
var KNOWN_PERMISSIONS = [
|
|
402
|
+
"account:read",
|
|
403
|
+
"account:admin",
|
|
404
|
+
"members:manage",
|
|
405
|
+
"workspace:create",
|
|
406
|
+
"billing:read",
|
|
407
|
+
"billing:manage",
|
|
408
|
+
"workspace:read",
|
|
409
|
+
"workspace:admin",
|
|
410
|
+
"sessions:create",
|
|
411
|
+
"sessions:read",
|
|
412
|
+
"sessions:control",
|
|
413
|
+
// Sandbox-surfacing (mirror of @opengeni/contracts Permission). stream:view is
|
|
414
|
+
// strictly broader than sessions:read (un-redacted pixels); stream:control is
|
|
415
|
+
// the never-granted-v1 raw-input plane; stream:acknowledge is the secret-leak
|
|
416
|
+
// consent gate.
|
|
417
|
+
"stream:view",
|
|
418
|
+
"stream:control",
|
|
419
|
+
"stream:acknowledge",
|
|
420
|
+
"files:upload",
|
|
421
|
+
"files:read",
|
|
422
|
+
"files:write",
|
|
423
|
+
"terminal:attach",
|
|
424
|
+
"documents:manage",
|
|
425
|
+
"documents:search",
|
|
426
|
+
"scheduled_tasks:manage",
|
|
427
|
+
"scheduled_tasks:run",
|
|
428
|
+
"github:manage",
|
|
429
|
+
"github:use",
|
|
430
|
+
"api_keys:manage",
|
|
431
|
+
"connections:read",
|
|
432
|
+
"connections:write",
|
|
433
|
+
"environments:manage",
|
|
434
|
+
"environments:use",
|
|
435
|
+
"variable-sets:manage",
|
|
436
|
+
"variable-sets:use",
|
|
437
|
+
"mcp_servers:attach",
|
|
438
|
+
"toolspace:call",
|
|
439
|
+
"goals:manage",
|
|
440
|
+
"enrollments:read",
|
|
441
|
+
"enrollments:manage",
|
|
442
|
+
"rigs:use",
|
|
443
|
+
"rigs:manage"
|
|
444
|
+
];
|
|
445
|
+
var OPENGENI_API_CONTRACT_REVISION = "2026-07-session-control-v1";
|
|
446
|
+
var OPENGENI_API_CONTRACT_HEADER = "x-opengeni-api-contract";
|
|
447
|
+
var KNOWN_USAGE_EVENT_TYPES = [
|
|
448
|
+
"agent_run.created",
|
|
449
|
+
"agent_run.completed",
|
|
450
|
+
"model.tokens",
|
|
451
|
+
"model.cost",
|
|
452
|
+
"file.uploaded",
|
|
453
|
+
"file.deleted",
|
|
454
|
+
"document.indexed",
|
|
455
|
+
"scheduled_task.fired",
|
|
456
|
+
"api_key.request",
|
|
457
|
+
// sandbox warm-time metering (P2.1) — mirrors contracts UsageEventType.
|
|
458
|
+
"sandbox.warm_seconds",
|
|
459
|
+
"sandbox.warm_cost"
|
|
460
|
+
];
|
|
461
|
+
|
|
211
462
|
// src/client.ts
|
|
212
463
|
var OpenGeniClient = class {
|
|
213
464
|
baseUrl;
|
|
@@ -255,7 +506,7 @@ var OpenGeniClient = class {
|
|
|
255
506
|
}
|
|
256
507
|
/** Pin-aware ordinary-session page with a stable keyset cursor. */
|
|
257
508
|
async listSessionPage(workspaceId, options = {}) {
|
|
258
|
-
|
|
509
|
+
return await this.requestJson(
|
|
259
510
|
"GET",
|
|
260
511
|
`/v1/workspaces/${workspaceId}/sessions`,
|
|
261
512
|
void 0,
|
|
@@ -269,16 +520,6 @@ var OpenGeniClient = class {
|
|
|
269
520
|
} : {}
|
|
270
521
|
}
|
|
271
522
|
);
|
|
272
|
-
if (Array.isArray(response)) {
|
|
273
|
-
if (options.cursor) {
|
|
274
|
-
throw new Error("The connected OpenGeni API does not support stable session-page cursors");
|
|
275
|
-
}
|
|
276
|
-
if (options.search?.trim()) {
|
|
277
|
-
throw new Error("The connected OpenGeni API does not support session search");
|
|
278
|
-
}
|
|
279
|
-
return { pinned: [], sessions: response, nextCursor: null };
|
|
280
|
-
}
|
|
281
|
-
return response;
|
|
282
523
|
}
|
|
283
524
|
/** Set this authenticated member's personal workspace pin for a session. */
|
|
284
525
|
async updateSessionPin(workspaceId, sessionId, request) {
|
|
@@ -454,10 +695,12 @@ var OpenGeniClient = class {
|
|
|
454
695
|
});
|
|
455
696
|
}
|
|
456
697
|
async pauseSession(workspaceId, sessionId, options = {}) {
|
|
457
|
-
return
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
698
|
+
return await this.controlSession(workspaceId, sessionId, {
|
|
699
|
+
action: "pause",
|
|
700
|
+
clientEventId: options.clientEventId ?? crypto.randomUUID(),
|
|
701
|
+
...options.reason ? { reason: options.reason } : {},
|
|
702
|
+
...options.expectedControlEtag ? { expectedControlEtag: options.expectedControlEtag } : {}
|
|
703
|
+
});
|
|
461
704
|
}
|
|
462
705
|
async sendApprovalDecision(workspaceId, sessionId, decision) {
|
|
463
706
|
const { clientEventId, ...payload } = decision;
|
|
@@ -495,6 +738,7 @@ var OpenGeniClient = class {
|
|
|
495
738
|
headers: { ...this.headers(), Accept: "text/event-stream" },
|
|
496
739
|
...options.signal ? { signal: options.signal } : {}
|
|
497
740
|
});
|
|
741
|
+
assertApiContractResponse(response);
|
|
498
742
|
if (!response.ok) {
|
|
499
743
|
throw new OpenGeniApiError(response.status, await safeText(response));
|
|
500
744
|
}
|
|
@@ -510,10 +754,44 @@ var OpenGeniClient = class {
|
|
|
510
754
|
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/queue`
|
|
511
755
|
);
|
|
512
756
|
}
|
|
513
|
-
async
|
|
757
|
+
async moveQueueItem(workspaceId, sessionId, turnId, request) {
|
|
758
|
+
return await this.requestJson(
|
|
759
|
+
"POST",
|
|
760
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/queue/${turnId}/move`,
|
|
761
|
+
request
|
|
762
|
+
);
|
|
763
|
+
}
|
|
764
|
+
async editQueueItem(workspaceId, sessionId, turnId, request) {
|
|
765
|
+
return await this.requestJson(
|
|
766
|
+
"POST",
|
|
767
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/queue/${turnId}/edit`,
|
|
768
|
+
request
|
|
769
|
+
);
|
|
770
|
+
}
|
|
771
|
+
async steerQueueItem(workspaceId, sessionId, turnId, request) {
|
|
772
|
+
return await this.requestJson(
|
|
773
|
+
"POST",
|
|
774
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/queue/${turnId}/steer`,
|
|
775
|
+
request
|
|
776
|
+
);
|
|
777
|
+
}
|
|
778
|
+
async deleteQueueItem(workspaceId, sessionId, turnId, request) {
|
|
514
779
|
return await this.requestJson(
|
|
515
780
|
"POST",
|
|
516
|
-
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/queue/${turnId}/
|
|
781
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/queue/${turnId}/delete`,
|
|
782
|
+
request
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
async getComposerDraft(workspaceId, sessionId) {
|
|
786
|
+
return await this.requestJson(
|
|
787
|
+
"GET",
|
|
788
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/composer-draft`
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
async saveComposerDraft(workspaceId, sessionId, request) {
|
|
792
|
+
return await this.requestJson(
|
|
793
|
+
"PUT",
|
|
794
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/composer-draft`,
|
|
517
795
|
request
|
|
518
796
|
);
|
|
519
797
|
}
|
|
@@ -525,7 +803,12 @@ var OpenGeniClient = class {
|
|
|
525
803
|
);
|
|
526
804
|
}
|
|
527
805
|
async resumeSession(workspaceId, sessionId, options = {}) {
|
|
528
|
-
return await this.controlSession(workspaceId, sessionId, {
|
|
806
|
+
return await this.controlSession(workspaceId, sessionId, {
|
|
807
|
+
action: "resume",
|
|
808
|
+
clientEventId: options.clientEventId ?? crypto.randomUUID(),
|
|
809
|
+
...options.reason ? { reason: options.reason } : {},
|
|
810
|
+
...options.expectedControlEtag ? { expectedControlEtag: options.expectedControlEtag } : {}
|
|
811
|
+
});
|
|
529
812
|
}
|
|
530
813
|
async setWorkspaceInferenceState(workspaceId, request) {
|
|
531
814
|
return await this.requestJson(
|
|
@@ -534,13 +817,46 @@ var OpenGeniClient = class {
|
|
|
534
817
|
request
|
|
535
818
|
);
|
|
536
819
|
}
|
|
537
|
-
|
|
538
|
-
async deleteQueuedTurn(workspaceId, sessionId, turnId) {
|
|
820
|
+
async listWorkspaceControlEvents(workspaceId, options = {}) {
|
|
539
821
|
return await this.requestJson(
|
|
540
|
-
"
|
|
541
|
-
`/v1/workspaces/${workspaceId}/
|
|
822
|
+
"GET",
|
|
823
|
+
`/v1/workspaces/${workspaceId}/control-events`,
|
|
824
|
+
void 0,
|
|
825
|
+
{
|
|
826
|
+
...options.after !== void 0 ? { after: String(options.after) } : {},
|
|
827
|
+
...options.limit !== void 0 ? { limit: String(options.limit) } : {}
|
|
828
|
+
}
|
|
542
829
|
);
|
|
543
830
|
}
|
|
831
|
+
streamWorkspaceControlEvents(workspaceId, options = {}) {
|
|
832
|
+
return streamWorkspaceControlEvents(this.workspaceControlStreamTransport(workspaceId), options);
|
|
833
|
+
}
|
|
834
|
+
workspaceControlStreamTransport(workspaceId) {
|
|
835
|
+
return {
|
|
836
|
+
openStream: async (after, signal) => await this.openWorkspaceControlEventStream(workspaceId, {
|
|
837
|
+
after,
|
|
838
|
+
...signal ? { signal } : {}
|
|
839
|
+
})
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
async openWorkspaceControlEventStream(workspaceId, options = {}) {
|
|
843
|
+
const response = await this.fetchImpl(
|
|
844
|
+
this.url(`/v1/workspaces/${workspaceId}/control-events/stream`, {
|
|
845
|
+
after: String(options.after ?? 0)
|
|
846
|
+
}),
|
|
847
|
+
{
|
|
848
|
+
method: "GET",
|
|
849
|
+
headers: { ...this.headers(), Accept: "text/event-stream" },
|
|
850
|
+
...options.signal ? { signal: options.signal } : {}
|
|
851
|
+
}
|
|
852
|
+
);
|
|
853
|
+
assertApiContractResponse(response);
|
|
854
|
+
if (!response.ok) throw new OpenGeniApiError(response.status, await safeText(response));
|
|
855
|
+
if (!response.body) {
|
|
856
|
+
throw new OpenGeniApiError(response.status, "SSE response did not include a readable body");
|
|
857
|
+
}
|
|
858
|
+
return response.body;
|
|
859
|
+
}
|
|
544
860
|
/**
|
|
545
861
|
* Steer: atomically put this prompt at the head and supersede the current
|
|
546
862
|
* inference. The client performs one request and renders server order.
|
|
@@ -821,7 +1137,14 @@ var OpenGeniClient = class {
|
|
|
821
1137
|
* knowledge of the host setup; safe to call before any auth is established.
|
|
822
1138
|
*/
|
|
823
1139
|
async getClientConfig() {
|
|
824
|
-
|
|
1140
|
+
const config = await this.requestJson("GET", "/v1/config/client");
|
|
1141
|
+
if (config.apiContractRevision !== OPENGENI_API_CONTRACT_REVISION) {
|
|
1142
|
+
throw new OpenGeniApiContractMismatchError(
|
|
1143
|
+
OPENGENI_API_CONTRACT_REVISION,
|
|
1144
|
+
String(config.apiContractRevision || "(missing)")
|
|
1145
|
+
);
|
|
1146
|
+
}
|
|
1147
|
+
return config;
|
|
825
1148
|
}
|
|
826
1149
|
/** The caller's access context: subject, account + workspace grants, defaults. */
|
|
827
1150
|
async getAccessContext() {
|
|
@@ -1491,7 +1814,8 @@ var OpenGeniClient = class {
|
|
|
1491
1814
|
const extra = typeof this.options.headers === "function" ? this.options.headers() : this.options.headers;
|
|
1492
1815
|
return {
|
|
1493
1816
|
...this.options.apiKey ? { Authorization: `Bearer ${this.options.apiKey}` } : {},
|
|
1494
|
-
...extra
|
|
1817
|
+
...extra,
|
|
1818
|
+
[OPENGENI_API_CONTRACT_HEADER]: OPENGENI_API_CONTRACT_REVISION
|
|
1495
1819
|
};
|
|
1496
1820
|
}
|
|
1497
1821
|
url(path, query = {}) {
|
|
@@ -1601,6 +1925,7 @@ var OpenGeniClient = class {
|
|
|
1601
1925
|
},
|
|
1602
1926
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
1603
1927
|
});
|
|
1928
|
+
assertApiContractResponse(response);
|
|
1604
1929
|
if (!response.ok) {
|
|
1605
1930
|
throw new OpenGeniApiError(response.status, await safeText(response));
|
|
1606
1931
|
}
|
|
@@ -1617,11 +1942,18 @@ var OpenGeniClient = class {
|
|
|
1617
1942
|
},
|
|
1618
1943
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
1619
1944
|
});
|
|
1945
|
+
assertApiContractResponse(response);
|
|
1620
1946
|
if (!response.ok) {
|
|
1621
1947
|
throw new OpenGeniApiError(response.status, await safeText(response));
|
|
1622
1948
|
}
|
|
1623
1949
|
}
|
|
1624
1950
|
};
|
|
1951
|
+
function assertApiContractResponse(response) {
|
|
1952
|
+
const actual = response.headers.get(OPENGENI_API_CONTRACT_HEADER);
|
|
1953
|
+
if (actual && actual !== OPENGENI_API_CONTRACT_REVISION) {
|
|
1954
|
+
throw new OpenGeniApiContractMismatchError(OPENGENI_API_CONTRACT_REVISION, actual);
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1625
1957
|
async function safeText(response) {
|
|
1626
1958
|
try {
|
|
1627
1959
|
return await response.text();
|
|
@@ -1812,175 +2144,12 @@ function ttydInputFrame(data) {
|
|
|
1812
2144
|
function ttydResizeFrame(columns, rows) {
|
|
1813
2145
|
return TtydClientCommand.RESIZE + JSON.stringify({ columns, rows });
|
|
1814
2146
|
}
|
|
1815
|
-
|
|
1816
|
-
// src/types.ts
|
|
1817
|
-
var SESSION_EVENT_TYPES = [
|
|
1818
|
-
"session.created",
|
|
1819
|
-
"session.status.changed",
|
|
1820
|
-
"session.requiresAction",
|
|
1821
|
-
"session.context.compaction.requested",
|
|
1822
|
-
"session.context.compacted",
|
|
1823
|
-
"session.context.compaction.skipped",
|
|
1824
|
-
"session.context.cleared",
|
|
1825
|
-
"user.message",
|
|
1826
|
-
"user.pause",
|
|
1827
|
-
"user.approvalDecision",
|
|
1828
|
-
"turn.queued",
|
|
1829
|
-
"turn.started",
|
|
1830
|
-
"turn.completed",
|
|
1831
|
-
"turn.failed",
|
|
1832
|
-
"turn.cancelled",
|
|
1833
|
-
"turn.superseded",
|
|
1834
|
-
"turn.recovery.requested",
|
|
1835
|
-
"turn.capacity_waiting",
|
|
1836
|
-
"agent.message.delta",
|
|
1837
|
-
"agent.message.completed",
|
|
1838
|
-
"agent.reasoning.delta",
|
|
1839
|
-
"agent.toolCall.created",
|
|
1840
|
-
"agent.toolCall.output",
|
|
1841
|
-
"agent.model.usage",
|
|
1842
|
-
"tool.auth_needed",
|
|
1843
|
-
"agent.updated",
|
|
1844
|
-
"rig.setup.started",
|
|
1845
|
-
"rig.setup.completed",
|
|
1846
|
-
"rig.setup.skipped",
|
|
1847
|
-
"rig.setup.failed",
|
|
1848
|
-
"sandbox.operation.started",
|
|
1849
|
-
"sandbox.operation.completed",
|
|
1850
|
-
"sandbox.operation.failed",
|
|
1851
|
-
"sandbox.command.output.delta",
|
|
1852
|
-
"artifact.created",
|
|
1853
|
-
"goal.set",
|
|
1854
|
-
"goal.updated",
|
|
1855
|
-
"goal.completed",
|
|
1856
|
-
"goal.paused",
|
|
1857
|
-
"goal.resumed",
|
|
1858
|
-
"goal.cleared",
|
|
1859
|
-
"goal.continuation",
|
|
1860
|
-
"system.update.pending",
|
|
1861
|
-
"system.update.delivered",
|
|
1862
|
-
"session.control.paused",
|
|
1863
|
-
"session.control.resumed",
|
|
1864
|
-
"session.control.steer_requested",
|
|
1865
|
-
"workspace.inference.paused",
|
|
1866
|
-
"workspace.inference.resumed",
|
|
1867
|
-
"session.queue.prompt.cancelled",
|
|
1868
|
-
"session.queue.history",
|
|
1869
|
-
"turn.event.rejected_late",
|
|
1870
|
-
"memory.saved",
|
|
1871
|
-
"memory.corrected",
|
|
1872
|
-
// Channel-B desktop pixel-plane signals (mirror of contracts SessionEventType;
|
|
1873
|
-
// the contract-parity test asserts sorted equality).
|
|
1874
|
-
"stream.url.rotated",
|
|
1875
|
-
"stream.opened",
|
|
1876
|
-
"stream.closed",
|
|
1877
|
-
"stream.revoked",
|
|
1878
|
-
// Channel-B recording signals (P4.3 — "agent films itself proving the fix").
|
|
1879
|
-
"recording.started",
|
|
1880
|
-
"recording.available",
|
|
1881
|
-
"recording.failed",
|
|
1882
|
-
// Channel-A structured-service notifications (P4.4; mirror of contracts
|
|
1883
|
-
// SessionEventType — the contract-parity test asserts sorted equality).
|
|
1884
|
-
"fs.changed",
|
|
1885
|
-
"git.changed",
|
|
1886
|
-
"terminal.pty.started",
|
|
1887
|
-
"terminal.pty.output.delta",
|
|
1888
|
-
"terminal.pty.exited",
|
|
1889
|
-
"session.title_set",
|
|
1890
|
-
// Multi-account Codex (P1): the session's inference account changed.
|
|
1891
|
-
"codex.account.switched",
|
|
1892
|
-
// OPE-21 metadata-only per-turn credential selection audit.
|
|
1893
|
-
"codex.credential.selected",
|
|
1894
|
-
// OPE-21 durable zero-capacity wait lifecycle. These are system/runtime
|
|
1895
|
-
// events, never synthetic user messages.
|
|
1896
|
-
"codex.capacity.waiting",
|
|
1897
|
-
"codex.capacity.resumed",
|
|
1898
|
-
"codex.capacity.superseded",
|
|
1899
|
-
// Sandbox durability observability (mirror of contracts SessionEventType):
|
|
1900
|
-
// box lifecycle + manifest-env drift, attributable from the DB alone.
|
|
1901
|
-
"sandbox.box.created",
|
|
1902
|
-
"sandbox.box.lost",
|
|
1903
|
-
"sandbox.box.terminated",
|
|
1904
|
-
"sandbox.box.snapshot",
|
|
1905
|
-
"sandbox.env.drift",
|
|
1906
|
-
// Active-sandbox pointer reconcile (issue #341; announce-only; mirror of contracts
|
|
1907
|
-
// SessionEventType — the contract-parity test asserts sorted equality).
|
|
1908
|
-
"session.route.reconciled",
|
|
1909
|
-
// Workbench v2 turn-end workspace capture (announce-only; mirror of contracts
|
|
1910
|
-
// SessionEventType — the contract-parity test asserts sorted equality).
|
|
1911
|
-
"workspace.revision.captured",
|
|
1912
|
-
"workspace.revision.degraded",
|
|
1913
|
-
// Connected Machine op-outcome observability (announce-only, quiet; mirror of
|
|
1914
|
-
// contracts SessionEventType — the contract-parity test asserts sorted equality).
|
|
1915
|
-
"machine.op.failed",
|
|
1916
|
-
"machine.op.recovered",
|
|
1917
|
-
// Connected Machine link-plane observability (announce-only, quiet; mirror of
|
|
1918
|
-
// contracts SessionEventType — the contract-parity test asserts sorted equality).
|
|
1919
|
-
"machine.link.lost",
|
|
1920
|
-
"machine.link.restored",
|
|
1921
|
-
"machine.runner.restarted"
|
|
1922
|
-
];
|
|
1923
|
-
var KNOWN_PERMISSIONS = [
|
|
1924
|
-
"account:read",
|
|
1925
|
-
"account:admin",
|
|
1926
|
-
"members:manage",
|
|
1927
|
-
"workspace:create",
|
|
1928
|
-
"billing:read",
|
|
1929
|
-
"billing:manage",
|
|
1930
|
-
"workspace:read",
|
|
1931
|
-
"workspace:admin",
|
|
1932
|
-
"sessions:create",
|
|
1933
|
-
"sessions:read",
|
|
1934
|
-
"sessions:control",
|
|
1935
|
-
// Sandbox-surfacing (mirror of @opengeni/contracts Permission). stream:view is
|
|
1936
|
-
// strictly broader than sessions:read (un-redacted pixels); stream:control is
|
|
1937
|
-
// the never-granted-v1 raw-input plane; stream:acknowledge is the secret-leak
|
|
1938
|
-
// consent gate.
|
|
1939
|
-
"stream:view",
|
|
1940
|
-
"stream:control",
|
|
1941
|
-
"stream:acknowledge",
|
|
1942
|
-
"files:upload",
|
|
1943
|
-
"files:read",
|
|
1944
|
-
"files:write",
|
|
1945
|
-
"terminal:attach",
|
|
1946
|
-
"documents:manage",
|
|
1947
|
-
"documents:search",
|
|
1948
|
-
"scheduled_tasks:manage",
|
|
1949
|
-
"scheduled_tasks:run",
|
|
1950
|
-
"github:manage",
|
|
1951
|
-
"github:use",
|
|
1952
|
-
"api_keys:manage",
|
|
1953
|
-
"connections:read",
|
|
1954
|
-
"connections:write",
|
|
1955
|
-
"environments:manage",
|
|
1956
|
-
"environments:use",
|
|
1957
|
-
"variable-sets:manage",
|
|
1958
|
-
"variable-sets:use",
|
|
1959
|
-
"mcp_servers:attach",
|
|
1960
|
-
"toolspace:call",
|
|
1961
|
-
"goals:manage",
|
|
1962
|
-
"enrollments:read",
|
|
1963
|
-
"enrollments:manage",
|
|
1964
|
-
"rigs:use",
|
|
1965
|
-
"rigs:manage"
|
|
1966
|
-
];
|
|
1967
|
-
var KNOWN_USAGE_EVENT_TYPES = [
|
|
1968
|
-
"agent_run.created",
|
|
1969
|
-
"agent_run.completed",
|
|
1970
|
-
"model.tokens",
|
|
1971
|
-
"model.cost",
|
|
1972
|
-
"file.uploaded",
|
|
1973
|
-
"file.deleted",
|
|
1974
|
-
"document.indexed",
|
|
1975
|
-
"scheduled_task.fired",
|
|
1976
|
-
"api_key.request",
|
|
1977
|
-
// sandbox warm-time metering (P2.1) — mirrors contracts UsageEventType.
|
|
1978
|
-
"sandbox.warm_seconds",
|
|
1979
|
-
"sandbox.warm_cost"
|
|
1980
|
-
];
|
|
1981
2147
|
export {
|
|
1982
2148
|
KNOWN_PERMISSIONS,
|
|
1983
2149
|
KNOWN_USAGE_EVENT_TYPES,
|
|
2150
|
+
OPENGENI_API_CONTRACT_HEADER,
|
|
2151
|
+
OPENGENI_API_CONTRACT_REVISION,
|
|
2152
|
+
OpenGeniApiContractMismatchError,
|
|
1984
2153
|
OpenGeniApiError,
|
|
1985
2154
|
OpenGeniClient,
|
|
1986
2155
|
OpenGeniStreamError,
|
|
@@ -1999,6 +2168,7 @@ export {
|
|
|
1999
2168
|
sessionEventsToSseResponse,
|
|
2000
2169
|
sessionEventsToSseStream,
|
|
2001
2170
|
streamSessionEvents,
|
|
2171
|
+
streamWorkspaceControlEvents,
|
|
2002
2172
|
terminalSocketUrl,
|
|
2003
2173
|
ttydAuthFrame,
|
|
2004
2174
|
ttydInputFrame,
|