@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/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
- const response = await this.requestJson(
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 (await this.controlSession(workspaceId, sessionId, {
458
- mode: "pause",
459
- ...options
460
- })).event;
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 cancelQueueItem(workspaceId, sessionId, turnId, request) {
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}/cancel`,
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, { mode: "resume", ...options });
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
- /** Cancel a queued turn before it is claimed. Returns the cancelled turn. */
538
- async deleteQueuedTurn(workspaceId, sessionId, turnId) {
820
+ async listWorkspaceControlEvents(workspaceId, options = {}) {
539
821
  return await this.requestJson(
540
- "DELETE",
541
- `/v1/workspaces/${workspaceId}/sessions/${sessionId}/turns/${turnId}`
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
- return await this.requestJson("GET", "/v1/config/client");
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,