@opengeni/sdk 0.36.1 → 0.37.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
@@ -1,3 +1,17 @@
1
+ import {
2
+ CODEX_REALTIME_CONTEXT_APPEND_MAX_BYTES,
3
+ CodexRealtimeMicrophoneError,
4
+ acquireCodexRealtimeMicrophone,
5
+ codexRealtimeMicrophoneHealthy,
6
+ contextAppendChunks,
7
+ createCodexRealtimeController,
8
+ createCodexRealtimeV3Bridge,
9
+ encodeCodexRealtimeV3DelegationContextAppend,
10
+ encodeCodexRealtimeV3SessionContextAppend,
11
+ parseCodexRealtimeV3Event,
12
+ projectSessionRealtimeLifecycle,
13
+ startCodexRealtimeWebrtc
14
+ } from "./chunk-OB5PGV6N.js";
1
15
  import {
2
16
  DEFAULT_WORKSPACE_TRANSCRIPTION_POLICY,
3
17
  KNOWN_PERMISSIONS,
@@ -5,23 +19,28 @@ import {
5
19
  OPENGENI_API_CONTRACT_HEADER,
6
20
  OPENGENI_API_CONTRACT_REVISION,
7
21
  OPENGENI_CORRELATION_HEADER,
8
- OpenGeniApiContractMismatchError,
9
- OpenGeniApiError,
10
22
  OpenGeniClient,
11
- OpenGeniSessionListCursorError,
12
- OpenGeniStreamError,
13
23
  RETAINED_OUTPUT_DEFAULT_PAGE_BYTES,
14
24
  RETAINED_OUTPUT_MAX_PAGE_BYTES,
15
25
  SESSION_EVENT_TYPES,
16
26
  authorizeTranscriptionAdapter,
17
27
  createTranscriptionSessionRequest,
18
- isRetryableStreamError,
19
28
  parseSseStream,
20
29
  resolveWorkspaceTranscriptionPolicy,
21
30
  resolveWorkspaceVoiceInputEnabled,
22
31
  streamSessionEvents,
23
32
  streamWorkspaceControlEvents
24
- } from "./chunk-B7E4FPNZ.js";
33
+ } from "./chunk-VOQ235WN.js";
34
+ import {
35
+ OpenGeniApiContractMismatchError,
36
+ OpenGeniApiError,
37
+ OpenGeniSessionListCursorError,
38
+ OpenGeniStreamError,
39
+ isRetryableStreamError
40
+ } from "./chunk-OINSI33U.js";
41
+ import {
42
+ createGatewayRealtimeTransportStarter
43
+ } from "./chunk-DXDL7EEW.js";
25
44
 
26
45
  // src/artifact-client.ts
27
46
  var OpenGeniClient2 = class extends OpenGeniClient {
@@ -385,6 +404,8 @@ function normalizePreferenceRegistryStableKey(value) {
385
404
  return value.normalize("NFKC").trim().toLowerCase().replace(/\s+/gu, "-").replace(/-+/g, "-");
386
405
  }
387
406
  export {
407
+ CODEX_REALTIME_CONTEXT_APPEND_MAX_BYTES,
408
+ CodexRealtimeMicrophoneError,
388
409
  DEFAULT_WORKSPACE_TRANSCRIPTION_POLICY,
389
410
  KNOWN_PERMISSIONS,
390
411
  KNOWN_USAGE_EVENT_TYPES,
@@ -402,23 +423,34 @@ export {
402
423
  TTYD_SUBPROTOCOL,
403
424
  TtydClientCommand,
404
425
  TtydServerCommand,
426
+ acquireCodexRealtimeMicrophone,
405
427
  applyUrlRotation,
406
428
  authorizeTranscriptionAdapter,
429
+ codexRealtimeMicrophoneHealthy,
430
+ contextAppendChunks,
431
+ createCodexRealtimeController,
432
+ createCodexRealtimeV3Bridge,
433
+ createGatewayRealtimeTransportStarter,
407
434
  createTranscriptionSessionRequest,
408
435
  desktopSocketUrl,
436
+ encodeCodexRealtimeV3DelegationContextAppend,
437
+ encodeCodexRealtimeV3SessionContextAppend,
409
438
  formatSseEvent,
410
439
  isRetryableStreamError,
411
440
  nextDesktopState,
412
441
  normalizeMcpOutput,
413
442
  normalizePreferenceRegistryStableKey,
414
443
  normalizeWorkspaceInstructionPolicyRoleKey,
444
+ parseCodexRealtimeV3Event,
415
445
  parseSseStream,
446
+ projectSessionRealtimeLifecycle,
416
447
  proxySessionEventStream,
417
448
  resolveWorkspaceTranscriptionPolicy,
418
449
  resolveWorkspaceVoiceInputEnabled,
419
450
  resumeSequenceFromRequest,
420
451
  sessionEventsToSseResponse,
421
452
  sessionEventsToSseStream,
453
+ startCodexRealtimeWebrtc,
422
454
  streamSessionEvents,
423
455
  streamWorkspaceControlEvents,
424
456
  terminalSocketUrl,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/artifact-client.ts","../src/proxy.ts","../src/mcp-output.ts","../src/desktop.ts","../src/terminal.ts","../src/workspace-instruction-policies.ts","../src/preference-registry.ts"],"sourcesContent":["import { OpenGeniClient as OpenGeniCoreClient } from \"./client\";\nimport type {\n CreateWorkspaceArtifactRequest,\n PublishWorkspaceArtifactVersionRequest,\n RollbackWorkspaceArtifactRequest,\n WorkspaceArtifactContentResponse,\n WorkspaceArtifactDetailResponse,\n WorkspaceArtifactListOptions,\n WorkspaceArtifactListResponse,\n WorkspaceArtifactMutationResponse,\n} from \"./workspace-artifacts\";\n\n/** Public SDK client. Artifact operations stay out of the console's eager core graph. */\nexport class OpenGeniClient extends OpenGeniCoreClient {\n async listWorkspaceArtifacts(\n workspaceId: string,\n options: WorkspaceArtifactListOptions = {},\n ): Promise<WorkspaceArtifactListResponse> {\n const query = new URLSearchParams();\n if (options.limit !== undefined) query.set(\"limit\", String(options.limit));\n if (options.cursor) query.set(\"cursor\", options.cursor);\n const suffix = query.size > 0 ? `?${query.toString()}` : \"\";\n return await this.requestJson<WorkspaceArtifactListResponse>(\n \"GET\",\n `/v1/workspaces/${workspaceId}/published-artifacts${suffix}`,\n );\n }\n\n async getWorkspaceArtifact(\n workspaceId: string,\n artifactId: string,\n ): Promise<WorkspaceArtifactDetailResponse> {\n return await this.requestJson<WorkspaceArtifactDetailResponse>(\n \"GET\",\n `/v1/workspaces/${workspaceId}/published-artifacts/${encodeURIComponent(artifactId)}`,\n );\n }\n\n async getWorkspaceArtifactContent(\n workspaceId: string,\n artifactId: string,\n versionId?: string,\n ): Promise<WorkspaceArtifactContentResponse> {\n const query = versionId ? `?versionId=${encodeURIComponent(versionId)}` : \"\";\n return await this.requestJson<WorkspaceArtifactContentResponse>(\n \"GET\",\n `/v1/workspaces/${workspaceId}/published-artifacts/${encodeURIComponent(artifactId)}/content${query}`,\n );\n }\n\n async createWorkspaceArtifact(\n workspaceId: string,\n request: CreateWorkspaceArtifactRequest,\n ): Promise<WorkspaceArtifactMutationResponse> {\n return await this.requestJson<WorkspaceArtifactMutationResponse>(\n \"POST\",\n `/v1/workspaces/${workspaceId}/published-artifacts`,\n request,\n );\n }\n\n async publishWorkspaceArtifactVersion(\n workspaceId: string,\n artifactId: string,\n request: PublishWorkspaceArtifactVersionRequest,\n ): Promise<WorkspaceArtifactMutationResponse> {\n return await this.requestJson<WorkspaceArtifactMutationResponse>(\n \"POST\",\n `/v1/workspaces/${workspaceId}/published-artifacts/${encodeURIComponent(artifactId)}/versions`,\n request,\n );\n }\n\n async rollbackWorkspaceArtifact(\n workspaceId: string,\n artifactId: string,\n request: RollbackWorkspaceArtifactRequest,\n ): Promise<WorkspaceArtifactMutationResponse> {\n return await this.requestJson<WorkspaceArtifactMutationResponse>(\n \"POST\",\n `/v1/workspaces/${workspaceId}/published-artifacts/${encodeURIComponent(artifactId)}/rollback`,\n request,\n );\n }\n}\n","import type { OpenGeniClient } from \"./client\";\nimport type { StreamSessionEventsOptions } from \"./stream\";\nimport type { SessionEvent } from \"./types\";\n\n/**\n * Proxy-through-your-own-API helpers.\n *\n * The intended pattern: a customer's server consumes the OpenGeni event\n * stream with its own API key (`client.streamEvents(...)`) and re-emits it to\n * its browser clients over its own authenticated endpoint — the OpenGeni key\n * never reaches the browser. The re-emitted wire format is identical to\n * OpenGeni's own SSE stream (`id: <sequence>`, `event: <type>`,\n * `data: <event JSON>`), so the browser side can consume it with this same\n * SDK's streaming core (or a plain `EventSource`), including resume via\n * `?after=` / `Last-Event-ID`.\n */\n\n/** Format one event exactly as OpenGeni's API emits it over SSE. */\nexport function formatSseEvent(event: SessionEvent): string {\n return `id: ${event.sequence}\\nevent: ${event.type}\\ndata: ${JSON.stringify(event)}\\n\\n`;\n}\n\nexport type SseReStreamOptions = {\n /**\n * Emit `: ping` comment lines at this interval, keeping intermediaries from\n * idling the connection out. Disabled when omitted.\n */\n heartbeatMs?: number;\n /**\n * Called when the downstream consumer cancels (e.g. the browser\n * disconnected). Use it to abort the upstream OpenGeni stream — an async\n * iterator that is mid-`await` cannot be interrupted by `return()` alone.\n */\n onCancel?: () => void;\n};\n\n/**\n * Re-emit a stream of session events as an SSE byte stream. Pull-based, so\n * upstream consumption follows downstream demand; cancelling the returned\n * stream fires `onCancel` and ends the upstream iterator.\n */\nexport function sessionEventsToSseStream(\n events: AsyncIterable<SessionEvent>,\n options: SseReStreamOptions = {},\n): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n const iterator = events[Symbol.asyncIterator]();\n let heartbeat: ReturnType<typeof setInterval> | undefined;\n let cancelled = false;\n\n const stopHeartbeat = (): void => {\n if (heartbeat !== undefined) {\n clearInterval(heartbeat);\n heartbeat = undefined;\n }\n };\n\n return new ReadableStream<Uint8Array>({\n start: (controller) => {\n if (options.heartbeatMs !== undefined) {\n heartbeat = setInterval(() => {\n try {\n controller.enqueue(encoder.encode(\": ping\\n\\n\"));\n } catch {\n stopHeartbeat();\n }\n }, options.heartbeatMs);\n }\n },\n pull: async (controller) => {\n let result: IteratorResult<SessionEvent, unknown>;\n try {\n result = await iterator.next();\n } catch (error) {\n stopHeartbeat();\n throw error;\n }\n if (cancelled) {\n return;\n }\n if (result.done) {\n stopHeartbeat();\n controller.close();\n return;\n }\n controller.enqueue(encoder.encode(formatSseEvent(result.value)));\n },\n cancel: () => {\n cancelled = true;\n stopHeartbeat();\n options.onCancel?.();\n // Fire-and-forget: if the iterator is suspended mid-await, return()\n // settles only after onCancel unblocks it; cancel must not hang on it.\n void Promise.resolve(iterator.return?.(undefined)).then(\n () => undefined,\n () => undefined,\n );\n },\n });\n}\n\n/** Wrap an event stream in a ready-to-return SSE `Response`. */\nexport function sessionEventsToSseResponse(\n events: AsyncIterable<SessionEvent>,\n options: SseReStreamOptions = {},\n): Response {\n return new Response(sessionEventsToSseStream(events, options), {\n headers: {\n \"Content-Type\": \"text/event-stream; charset=utf-8\",\n \"Cache-Control\": \"no-cache, no-transform\",\n Connection: \"keep-alive\",\n },\n });\n}\n\n/**\n * Read the resume cursor a reconnecting SSE client sent: the `after` query\n * parameter, or the standard `Last-Event-ID` header (the re-emitted stream\n * sets `id:` to the sequence). Returns 0 (full replay) when absent.\n */\nexport function resumeSequenceFromRequest(request: Request): number {\n const url = new URL(request.url);\n const raw = url.searchParams.get(\"after\") ?? request.headers.get(\"Last-Event-ID\");\n const parsed = raw === null ? 0 : Number(raw);\n return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : 0;\n}\n\nexport type ProxySessionEventStreamOptions = Omit<StreamSessionEventsOptions, \"after\"> & {\n /**\n * Resume cursor. Pass a number, or the incoming browser `Request` to\n * honor its `?after=` / `Last-Event-ID` automatically.\n */\n after?: number | Request;\n /** See {@link SseReStreamOptions.heartbeatMs}. */\n heartbeatMs?: number;\n};\n\n/**\n * One-call proxy: consume the OpenGeni stream server-side and return an SSE\n * `Response` for your own browser clients. Works anywhere WHATWG `Response`\n * is the handler return type (Hono, Next.js route handlers, Bun.serve,\n * Cloudflare Workers, ...).\n *\n * The upstream OpenGeni connection is torn down when the downstream client\n * disconnects, and also when `options.signal` (e.g. the incoming request's\n * signal) aborts.\n */\nexport function proxySessionEventStream(\n client: OpenGeniClient,\n workspaceId: string,\n sessionId: string,\n options: ProxySessionEventStreamOptions = {},\n): Response {\n const { after, heartbeatMs, signal, ...streamOptions } = options;\n const upstream = new AbortController();\n if (signal?.aborted) {\n upstream.abort();\n } else {\n signal?.addEventListener(\"abort\", () => upstream.abort(), { once: true });\n }\n const resolvedAfter = after instanceof Request ? resumeSequenceFromRequest(after) : (after ?? 0);\n const events = client.streamEvents(workspaceId, sessionId, {\n ...streamOptions,\n after: resolvedAfter,\n signal: upstream.signal,\n });\n return sessionEventsToSseResponse(events, {\n ...(heartbeatMs !== undefined ? { heartbeatMs } : {}),\n onCancel: () => upstream.abort(),\n });\n}\n","/**\n * A transport-tolerant MCP tool result.\n *\n * `value` is the canonical machine-readable payload after recognized MCP/JSON\n * envelopes are removed. `text` is the best presentation string without\n * discarding structured data. `raw` always retains the original evidence.\n */\nexport type NormalizedMcpOutput = Readonly<{\n raw: unknown;\n value: unknown;\n text: string;\n isError: boolean;\n}>;\n\nconst MAX_MCP_OUTPUT_DEPTH = 8;\nconst RESULT_ENVELOPE_KEYS = new Set([\"result\", \"isError\", \"jsonrpc\", \"id\", \"_meta\"]);\n\n/** Normalize common direct, JSON, and standard MCP result envelopes without throwing. */\nexport function normalizeMcpOutput(output: unknown): NormalizedMcpOutput {\n const normalized = normalizeValue(output, 0, new Set<object>());\n return {\n raw: output,\n value: normalized.value,\n text: normalized.text,\n isError: normalized.isError,\n };\n}\n\ntype NormalizedValue = Omit<NormalizedMcpOutput, \"raw\">;\n\nfunction normalizeValue(value: unknown, depth: number, ancestors: Set<object>): NormalizedValue {\n if (value === null || value === undefined) {\n return { value, text: \"\", isError: false };\n }\n if (typeof value === \"string\") {\n return normalizeText(value, depth, ancestors);\n }\n if (typeof value !== \"object\") {\n return { value, text: String(value), isError: false };\n }\n if (depth >= MAX_MCP_OUTPUT_DEPTH || ancestors.has(value)) {\n return { value, text: safeStringify(value), isError: false };\n }\n\n ancestors.add(value);\n try {\n if (Array.isArray(value)) {\n return { value, text: safeStringify(value), isError: false };\n }\n\n const record = value as Record<string, unknown>;\n const envelopeError = record.isError === true;\n\n if (record.type === \"text\" && typeof record.text === \"string\") {\n const normalized = normalizeText(record.text, depth + 1, ancestors);\n return {\n value: normalized.value,\n text: record.text,\n isError: envelopeError || normalized.isError,\n };\n }\n\n if (\"structuredContent\" in record) {\n const normalized = normalizeValue(record.structuredContent, depth + 1, ancestors);\n return {\n value: normalized.value,\n text: firstMcpText(record.content) ?? normalized.text,\n isError: envelopeError || normalized.isError,\n };\n }\n\n if (isMcpContent(record.content)) {\n const text = firstMcpText(record.content);\n if (text !== null) {\n const normalized = normalizeText(text, depth + 1, ancestors);\n return {\n value: normalized.value,\n text,\n isError: envelopeError || normalized.isError,\n };\n }\n return {\n value,\n text: safeStringify(value),\n isError: envelopeError,\n };\n }\n\n if (isResultEnvelope(record)) {\n const normalized = normalizeValue(record.result, depth + 1, ancestors);\n return {\n value: normalized.value,\n text: normalized.text,\n isError: envelopeError || normalized.isError,\n };\n }\n\n return {\n value,\n text: safeStringify(value),\n isError: envelopeError,\n };\n } finally {\n ancestors.delete(value);\n }\n}\n\nfunction normalizeText(text: string, depth: number, ancestors: Set<object>): NormalizedValue {\n try {\n const parsed: unknown = JSON.parse(text);\n const normalized = normalizeValue(parsed, depth + 1, ancestors);\n return {\n value: normalized.value,\n text,\n isError: normalized.isError,\n };\n } catch {\n return { value: text, text, isError: false };\n }\n}\n\nfunction isMcpContent(value: unknown): value is readonly Record<string, unknown>[] {\n return (\n Array.isArray(value) &&\n value.some(\n (part) =>\n part !== null &&\n typeof part === \"object\" &&\n typeof (part as { type?: unknown }).type === \"string\",\n )\n );\n}\n\nfunction firstMcpText(value: unknown): string | null {\n if (!Array.isArray(value)) {\n return null;\n }\n for (const part of value) {\n if (\n part !== null &&\n typeof part === \"object\" &&\n (part as { type?: unknown }).type === \"text\" &&\n typeof (part as { text?: unknown }).text === \"string\"\n ) {\n return (part as { text: string }).text;\n }\n }\n return null;\n}\n\nfunction isResultEnvelope(record: Record<string, unknown>): boolean {\n return \"result\" in record && Object.keys(record).every((key) => RESULT_ENVELOPE_KEYS.has(key));\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value) ?? \"\";\n } catch {\n return String(value);\n }\n}\n","// Zero-dependency desktop (noVNC) transport contract.\n//\n// The actual `@novnc/novnc` RFB import is a browser-only DOM dependency and\n// lives in `@opengeni/react` (lazily imported, SSR-safe). The framework-agnostic\n// SDK ships only the transport CONTRACT: a URL assembler, the minimal RFB\n// surface the component drives, the connection state machine, and the\n// rotation/fence reducers — all pure and unit-testable, with no DOM and no deps.\n//\n// Channel A (terminal-as-events, files, git) needs NO new transport here: those\n// are event projections + the synchronous fs/git/terminal point queries on\n// `OpenGeniClient`. Only the desktop pixel plane (Channel B, direct-to-provider)\n// needs this.\n\nimport type { DesktopStreamCapability, StreamUrlRotatedPayload } from \"./types\";\n\n/**\n * Translate the negotiated desktop capability into the WebSocket URL the noVNC\n * RFB client connects to. The scoped provider token is ALREADY embedded in the\n * minted `url` (Modal tunnel host, Blaxel `bl_preview_token`, Daytona signed\n * preview) by `session.resolveExposedPort(6080)` — we do NOT append `cap.token`\n * as a query param (that double-auth was an adversarial-review bug: the box runs\n * `-nopw` in v1, so the RFB password is meaningless and the real auth is the\n * tunnel token in the host). We only normalize the scheme to `ws`/`wss` and, when\n * the minted URL points at a `vnc.html` viewer page, rewrite it to the\n * websockify socket path noVNC actually dials.\n */\nexport function desktopSocketUrl(cap: Pick<DesktopStreamCapability, \"url\">): string {\n if (!cap.url) {\n throw new Error(\"desktop capability has no url (transport is null)\");\n }\n const u = new URL(cap.url);\n // https → wss, http → ws (noVNC dials a WebSocket, not the HTTP viewer page).\n if (u.protocol === \"https:\") {\n u.protocol = \"wss:\";\n } else if (u.protocol === \"http:\") {\n u.protocol = \"ws:\";\n }\n // A minted `…/vnc.html` (or `…/vnc_lite.html`) viewer page → the websockify\n // socket the page itself would open (`…/websockify`). A bare host/path with no\n // viewer page is already the socket path; leave it untouched.\n if (/\\/vnc(_lite)?\\.html$/.test(u.pathname)) {\n u.pathname = u.pathname.replace(/\\/vnc(_lite)?\\.html$/, \"/websockify\");\n u.search = \"\";\n u.hash = \"\";\n }\n return u.toString();\n}\n\n/**\n * The minimal RFB surface the React component drives. Lets tests (and 3rd\n * parties swapping noVNC for a WebRTC client in v3) provide a fake without the\n * DOM. Matches `@novnc/novnc`'s RFB constructor + lifecycle.\n */\nexport interface DesktopRfbLike {\n viewOnly: boolean;\n scaleViewport: boolean;\n /**\n * 1:1 viewport clipping. We always drive this FALSE: with clipping on, noVNC\n * paints the framebuffer pixel-for-pixel and scrolls/crops to the container\n * (the \"zoomed in\" look). FALSE lets `scaleViewport` shrink the 1280x800 frame\n * to fit the panel (aspect-preserved). Declared so the hook can pin it instead\n * of relying on noVNC's default — `scaleViewport=true` forces clip off\n * internally, but a stale/partial state on reconnect could leave it on.\n */\n clipViewport: boolean;\n addEventListener(\n type: \"connect\" | \"disconnect\" | \"securityfailure\",\n cb: (e?: unknown) => void,\n ): void;\n removeEventListener?: (\n type: \"connect\" | \"disconnect\" | \"securityfailure\",\n cb: (e?: unknown) => void,\n ) => void;\n disconnect(): void;\n}\n\nexport type DesktopRfbFactory = (\n target: HTMLElement,\n url: string,\n opts: { credentials?: { password?: string | undefined } | undefined },\n) => DesktopRfbLike;\n\nexport type DesktopConnectionState =\n | \"idle\"\n | \"negotiating\"\n | \"connecting\"\n | \"connected\"\n | \"rotating\"\n | \"reconnecting\"\n | \"error\"\n | \"ended\";\n\nexport type DesktopStreamEvent =\n | { type: \"negotiated\" }\n | { type: \"connected\" }\n | { type: \"disconnected\" }\n | { type: \"rotate\" }\n | { type: \"fail\" }\n | { type: \"abort\" };\n\n/**\n * Pure reducer for the desktop connection lifecycle. The component owns the RFB\n * object + DOM; this owns the transitions so they are unit-testable. Mirrors the\n * Channel-A stream reducer discipline.\n */\nexport function nextDesktopState(\n current: DesktopConnectionState,\n ev: DesktopStreamEvent,\n): DesktopConnectionState {\n switch (ev.type) {\n case \"negotiated\":\n return \"connecting\";\n case \"connected\":\n return \"connected\";\n case \"rotate\":\n return current === \"connected\" ? \"rotating\" : current;\n case \"disconnected\":\n // A deliberate teardown (ended) stays ended; everything else reconnects.\n return current === \"ended\" ? \"ended\" : \"reconnecting\";\n case \"fail\":\n return \"error\";\n case \"abort\":\n return \"ended\";\n default:\n return current;\n }\n}\n\n// `DesktopStreamCapability` is the desktop cell of `SessionCapabilities`; alias\n// it for the rotation reducer below without depending on the whole doc.\nexport type DesktopStreamCapabilityLike = {\n url: string | null;\n token: string | null;\n expiresAt: string | null;\n};\n\n/**\n * Apply a `stream.url.rotated` event onto a desktop capability, fencing on\n * leaseEpoch (split-brain). A rotation minted under an epoch the client has\n * already advanced PAST is from a superseded owner and is dropped (returns\n * null); otherwise the fresh url/token/expiresAt are folded in.\n */\nexport function applyUrlRotation<T extends DesktopStreamCapabilityLike>(\n cap: T,\n payload: StreamUrlRotatedPayload,\n knownEpoch: number,\n): T | null {\n if (payload.leaseEpoch < knownEpoch) {\n return null;\n }\n return { ...cap, url: payload.url, token: payload.token, expiresAt: payload.expiresAt };\n}\n","// Zero-dependency interactive-terminal (ttyd PTY-over-websocket) transport\n// contract. Symmetric with `desktop.ts`: the SDK ships only the pure transport\n// CONTRACT (a URL assembler + the ttyd wire-protocol frame codec), with no DOM\n// and no deps. The actual WebSocket open + xterm attach lives in `@opengeni/react`\n// (`use-terminal-stream.ts`).\n//\n// The interactive terminal is a REAL PTY streamed over the SAME Modal raw-TLS\n// tunnel as the desktop noVNC, with the SAME scoped stream-token mechanism. The\n// box bakes `ttyd` on `TERMINAL_STREAM_PORT` (7681); `session.resolveExposedPort`\n// mints the tunnel URL. The Terminal capability cell carries transport \"pty-ws\" +\n// that url + the scoped token when the box is warm and a viewer is attached.\n\nimport type { TerminalCapability } from \"./types\";\n\n/**\n * Translate the negotiated `pty-ws` Terminal capability into the WebSocket URL\n * the ttyd client dials. The scoped provider token is ALREADY embedded in the\n * minted `url` (the Modal tunnel host) by `session.resolveExposedPort(7681)` —\n * we do NOT append `cap.token` (identical posture to the desktop: the gate is the\n * unguessable short-TTL tunnel URL + the server-recorded scoped stream token; ttyd\n * runs `--writable` with no `-c` credential in v1). We only normalize the scheme\n * to `ws`/`wss`; a bare host is already the ttyd websocket endpoint.\n */\nexport function terminalSocketUrl(cap: Pick<TerminalCapability, \"url\">): string {\n if (!cap.url) {\n throw new Error(\"terminal capability has no url (transport is not pty-ws)\");\n }\n const u = new URL(cap.url);\n // https → wss, http → ws (ttyd is dialed as a WebSocket, not an HTTP page).\n if (u.protocol === \"https:\") {\n u.protocol = \"wss:\";\n } else if (u.protocol === \"http:\") {\n u.protocol = \"ws:\";\n }\n return u.toString();\n}\n\n// ── ttyd wire protocol ───────────────────────────────────────────────────────\n// ttyd frames are a single ASCII command char + payload. These mirror ttyd's\n// `protocol.h` Command enum. Client→server and server→client share the byte 0/1/2\n// values but mean different things per direction (see below).\n\n/** ttyd subprotocol — REQUIRED on the WebSocket handshake or ttyd refuses it. */\nexport const TTYD_SUBPROTOCOL = \"tty\";\n\n/** Client→server command bytes (the first char of each outbound text frame). */\nexport const TtydClientCommand = {\n /** stdin: \"0\" + raw input bytes. */\n INPUT: \"0\",\n /** window resize: \"1\" + JSON.stringify({ columns, rows }). */\n RESIZE: \"1\",\n /** flow-control pause (back-pressure): \"2\". */\n PAUSE: \"2\",\n /** flow-control resume: \"3\". */\n RESUME: \"3\",\n} as const;\n\n/** Server→client command bytes (the first char of each inbound frame). */\nexport const TtydServerCommand = {\n /** stdout/stderr: \"0\" + raw output bytes (write the rest into xterm). */\n OUTPUT: \"0\",\n /** set the window title: \"1\" + title string. */\n SET_WINDOW_TITLE: \"1\",\n /** ttyd client preferences JSON: \"2\" + json (ignored by us). */\n SET_PREFERENCES: \"2\",\n} as const;\n\n/**\n * The ttyd handshake's first frame: an auth message. ttyd expects\n * `JSON.stringify({ AuthToken })` as the FIRST text frame on the socket. We send\n * an empty token — our gate is the tunnel URL + scoped stream token, NOT a ttyd\n * `-c` basic-auth credential (which the box does not set in v1). Optional ttyd\n * `columns`/`rows` can ride this frame to seed the PTY size before the first\n * resize. Pure (string-building only) so it stays unit-testable in the SDK.\n */\nexport function ttydAuthFrame(opts?: { columns?: number; rows?: number }): string {\n const frame: { AuthToken: string; columns?: number; rows?: number } = { AuthToken: \"\" };\n if (opts?.columns && opts.columns > 0) frame.columns = opts.columns;\n if (opts?.rows && opts.rows > 0) frame.rows = opts.rows;\n return JSON.stringify(frame);\n}\n\n/** Build a client→server INPUT (stdin) frame: \"0\" + data. */\nexport function ttydInputFrame(data: string): string {\n return TtydClientCommand.INPUT + data;\n}\n\n/** Build a client→server RESIZE frame: \"1\" + JSON.stringify({ columns, rows }). */\nexport function ttydResizeFrame(columns: number, rows: number): string {\n return TtydClientCommand.RESIZE + JSON.stringify({ columns, rows });\n}\n","export type WorkspaceInstructionPolicyKind = \"charter\" | \"policy\";\nexport type WorkspaceInstructionPolicyScope = \"global\" | \"role\";\nexport type WorkspaceInstructionPolicyProvenanceSource =\n | \"human\"\n | \"onboarding\"\n | \"knowledge_proposal\"\n | \"legacy_import\";\nexport type WorkspaceInstructionPolicyDraftProvenanceSource = Exclude<\n WorkspaceInstructionPolicyProvenanceSource,\n \"legacy_import\"\n>;\nexport type WorkspaceInstructionPolicyActivationType = \"activate\" | \"rollback\";\n\nexport function normalizeWorkspaceInstructionPolicyRoleKey(value: string): string {\n return value.normalize(\"NFKC\").trim().toLowerCase().replace(/\\s+/gu, \"-\").replace(/-+/g, \"-\");\n}\n\nexport type WorkspaceInstructionPolicyTarget = {\n kind: WorkspaceInstructionPolicyKind;\n scope: WorkspaceInstructionPolicyScope;\n roleKey: string | null;\n};\n\nexport type WorkspaceInstructionPolicyRevisionIdentity = {\n id: string;\n revision: number;\n contentHash: string;\n};\n\nexport type WorkspaceInstructionPolicyRevision = WorkspaceInstructionPolicyRevisionIdentity &\n WorkspaceInstructionPolicyTarget & {\n accountId: string;\n workspaceId: string;\n content: string;\n provenance: {\n source: WorkspaceInstructionPolicyProvenanceSource;\n sourceId: string | null;\n };\n supersedesRevisionId: string | null;\n createdBySubjectId: string;\n createdAt: string;\n };\n\nexport type WorkspaceInstructionPolicyHead = WorkspaceInstructionPolicyTarget & {\n workspaceId: string;\n revisionId: string;\n revision: number;\n contentHash: string;\n activationVersion: number;\n activatedAt: string;\n};\n\nexport type WorkspaceInstructionPolicyActivationEvent = WorkspaceInstructionPolicyTarget & {\n id: string;\n accountId: string;\n workspaceId: string;\n type: WorkspaceInstructionPolicyActivationType;\n activationVersion: number;\n oldRevision: WorkspaceInstructionPolicyRevisionIdentity | null;\n newRevision: WorkspaceInstructionPolicyRevisionIdentity;\n actorSubjectId: string;\n reason: string;\n createdAt: string;\n};\n\nexport type CreateWorkspaceInstructionPolicyDraftRequest = WorkspaceInstructionPolicyTarget & {\n content: string;\n provenanceSource?: WorkspaceInstructionPolicyDraftProvenanceSource;\n provenanceSourceId?: string | null;\n supersedesRevisionId?: string | null;\n};\n\nexport type ImportLegacyWorkspaceInstructionPolicyDraftRequest = {\n supersedesRevisionId?: string | null;\n};\n\nexport type WorkspaceInstructionPolicyListOptions = {\n kind?: WorkspaceInstructionPolicyKind;\n scope?: WorkspaceInstructionPolicyScope;\n roleKey?: string;\n afterRevision?: number;\n limit?: number;\n};\n\nexport type WorkspaceInstructionPolicyListResponse = {\n revisions: WorkspaceInstructionPolicyRevision[];\n activeHeads: WorkspaceInstructionPolicyHead[];\n activationEvents: WorkspaceInstructionPolicyActivationEvent[];\n nextAfterRevision: number | null;\n};\n\nexport type WorkspaceInstructionPolicyDiffRequest = {\n fromRevisionId: string;\n toRevisionId: string;\n};\n\nexport type WorkspaceInstructionPolicyDiffResponse = {\n from: WorkspaceInstructionPolicyRevision;\n to: WorkspaceInstructionPolicyRevision;\n format: \"unified\";\n diff: string;\n};\n\nexport type ActivateWorkspaceInstructionPolicyRequest = {\n expectedCurrentRevisionId: string | null;\n reason: string;\n};\n\nexport type RollbackWorkspaceInstructionPolicyRequest = {\n targetRevisionId: string;\n expectedCurrentRevisionId: string;\n reason: string;\n};\n\nexport type WorkspaceInstructionPolicyActivationResponse = {\n head: WorkspaceInstructionPolicyHead;\n event: WorkspaceInstructionPolicyActivationEvent;\n};\n\nexport type WorkspaceInstructionPolicyConflictResponse = {\n code: \"WORKSPACE_INSTRUCTION_POLICY_CONFLICT\";\n message: string;\n currentHead: WorkspaceInstructionPolicyHead | null;\n};\n","export type PreferenceRegistryScope = \"organization\" | \"workspace\" | \"user\";\nexport type PreferenceRegistryStatus =\n | \"proposed\"\n | \"active\"\n | \"inactive\"\n | \"rejected\"\n | \"superseded\"\n | \"expired\";\nexport type PreferenceRegistryProvenanceSource =\n | \"human\"\n | \"onboarding\"\n | \"knowledge_proposal\"\n | \"imported_document\"\n | \"slack\"\n | \"meeting_transcript\"\n | \"call_transcript\";\nexport type PreferenceRegistryTrust =\n | \"untrusted_proposal\"\n | \"personal\"\n | \"workspace_managed\"\n | \"organization_managed\";\nexport type PreferenceRegistryConflictStrategy = \"override\" | \"merge\" | \"reject\" | \"inform\";\n\nexport function normalizePreferenceRegistryStableKey(value: string): string {\n return value.normalize(\"NFKC\").trim().toLowerCase().replace(/\\s+/gu, \"-\").replace(/-+/g, \"-\");\n}\n\nexport type PreferenceRegistryScopeTarget = {\n scope: PreferenceRegistryScope;\n workspaceId: string | null;\n subjectId: string | null;\n};\n\nexport type PreferenceRegistryPrecedence = {\n tier: PreferenceRegistryScope;\n rank: number;\n conflictStrategy: PreferenceRegistryConflictStrategy;\n conflictsWith: string[];\n};\n\nexport type PreferenceRegistryRevisionSummary = {\n id: string;\n preferenceId: string;\n revision: number;\n contentHash: string;\n title: string;\n description: string;\n precedence: PreferenceRegistryPrecedence;\n provenance: {\n source: PreferenceRegistryProvenanceSource;\n sourceId: string | null;\n trust: PreferenceRegistryTrust;\n };\n expiresAt: string | null;\n correctsRevisionId: string | null;\n createdBySubjectId: string;\n createdAt: string;\n};\n\nexport type PreferenceRegistryDescriptorProvenance = {\n source: PreferenceRegistryProvenanceSource;\n sourceIdHash: string | null;\n trust: PreferenceRegistryTrust;\n};\n\nexport type PreferenceRegistryRecord = {\n id: string;\n accountId: string;\n stableKey: string;\n target: PreferenceRegistryScopeTarget;\n status: PreferenceRegistryStatus;\n scopeVersion: number;\n activationVersion: number;\n activeRevision: PreferenceRegistryRevisionSummary | null;\n supersededByPreferenceId: string | null;\n createdBySubjectId: string;\n createdAt: string;\n updatedAt: string;\n};\n\nexport type PreferenceRegistryEvent = {\n id: string;\n accountId: string;\n preferenceId: string;\n type:\n | \"proposal_created\"\n | \"activated\"\n | \"corrected\"\n | \"rejected\"\n | \"deactivated\"\n | \"superseded\"\n | \"scope_changed\";\n version: number;\n oldRevisionId: string | null;\n newRevisionId: string | null;\n oldTarget: PreferenceRegistryScopeTarget | null;\n newTarget: PreferenceRegistryScopeTarget | null;\n relatedPreferenceId: string | null;\n actorSubjectId: string;\n reason: string;\n createdAt: string;\n};\n\nexport type PreferenceRegistryDescriptor = {\n id: string;\n stableKey: string;\n title: string;\n description: string;\n scope: PreferenceRegistryScope;\n activeVersion: number;\n revisionId: string;\n contentHash: string;\n precedence: PreferenceRegistryPrecedence;\n provenance: PreferenceRegistryDescriptorProvenance;\n expiresAt: string | null;\n retrievalHandle: string;\n};\n\nexport type PreferenceRegistrySnapshot = {\n id: string;\n workspaceId: string;\n sessionId: string;\n turnId: string;\n attemptId: string;\n executionGeneration: number;\n initiatingHumanSubjectId: string;\n descriptorHash: string;\n descriptors: PreferenceRegistryDescriptor[];\n truncated: boolean;\n createdAt: string;\n};\n\nexport type PreferenceRegistryFullContent = {\n descriptor: PreferenceRegistryDescriptor;\n content: string;\n};\n\nexport type CreatePreferenceRegistryProposalRequest = {\n stableKey: string;\n scope: PreferenceRegistryScope;\n title: string;\n description: string;\n content: string;\n precedenceRank?: number;\n conflictStrategy?: PreferenceRegistryConflictStrategy;\n conflictsWith?: string[];\n expiresAt?: string | null;\n provenanceSource?: PreferenceRegistryProvenanceSource;\n provenanceSourceId?: string | null;\n};\n\nexport type ActivatePreferenceRegistryRevisionRequest = {\n revisionId: string;\n expectedCurrentRevisionId: string | null;\n expectedScopeVersion: number;\n reason: string;\n};\n\nexport type CorrectPreferenceRegistryRequest = {\n expectedCurrentRevisionId: string;\n expectedScopeVersion: number;\n title: string;\n description: string;\n content: string;\n precedenceRank?: number;\n conflictStrategy?: PreferenceRegistryConflictStrategy;\n conflictsWith?: string[];\n expiresAt?: string | null;\n reason: string;\n};\n\nexport type DeactivatePreferenceRegistryRequest = {\n expectedCurrentRevisionId: string;\n expectedScopeVersion: number;\n reason: string;\n};\n\nexport type ChangePreferenceRegistryScopeRequest = {\n scope: PreferenceRegistryScope;\n expectedScopeVersion: number;\n reason: string;\n};\n\nexport type SupersedePreferenceRegistryRequest = {\n replacementPreferenceId: string;\n expectedCurrentRevisionId: string;\n expectedScopeVersion: number;\n reason: string;\n};\n\nexport type RejectPreferenceRegistryProposalRequest = {\n revisionId: string;\n expectedScopeVersion: number;\n reason: string;\n};\nexport type PreferenceRegistryListOptions = {\n scope?: PreferenceRegistryScope;\n status?: PreferenceRegistryStatus;\n limit?: number;\n};\nexport type PreferenceRegistryListResponse = { preferences: PreferenceRegistryRecord[] };\nexport type PreferenceRegistryDetailResponse = {\n preference: PreferenceRegistryRecord;\n revisions: PreferenceRegistryRevisionSummary[];\n events: PreferenceRegistryEvent[];\n};\nexport type PreferenceRegistryMutationResponse = {\n preference: PreferenceRegistryRecord;\n event: PreferenceRegistryEvent;\n};\n"],"mappings":"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","names":["OpenGeniClient"]}
1
+ {"version":3,"sources":["../src/artifact-client.ts","../src/proxy.ts","../src/mcp-output.ts","../src/desktop.ts","../src/terminal.ts","../src/workspace-instruction-policies.ts","../src/preference-registry.ts"],"sourcesContent":["import { OpenGeniClient as OpenGeniCoreClient } from \"./client\";\nimport type {\n CreateWorkspaceArtifactRequest,\n PublishWorkspaceArtifactVersionRequest,\n RollbackWorkspaceArtifactRequest,\n WorkspaceArtifactContentResponse,\n WorkspaceArtifactDetailResponse,\n WorkspaceArtifactListOptions,\n WorkspaceArtifactListResponse,\n WorkspaceArtifactMutationResponse,\n} from \"./workspace-artifacts\";\n\n/** Public SDK client. Artifact operations stay out of the console's eager core graph. */\nexport class OpenGeniClient extends OpenGeniCoreClient {\n async listWorkspaceArtifacts(\n workspaceId: string,\n options: WorkspaceArtifactListOptions = {},\n ): Promise<WorkspaceArtifactListResponse> {\n const query = new URLSearchParams();\n if (options.limit !== undefined) query.set(\"limit\", String(options.limit));\n if (options.cursor) query.set(\"cursor\", options.cursor);\n const suffix = query.size > 0 ? `?${query.toString()}` : \"\";\n return await this.requestJson<WorkspaceArtifactListResponse>(\n \"GET\",\n `/v1/workspaces/${workspaceId}/published-artifacts${suffix}`,\n );\n }\n\n async getWorkspaceArtifact(\n workspaceId: string,\n artifactId: string,\n ): Promise<WorkspaceArtifactDetailResponse> {\n return await this.requestJson<WorkspaceArtifactDetailResponse>(\n \"GET\",\n `/v1/workspaces/${workspaceId}/published-artifacts/${encodeURIComponent(artifactId)}`,\n );\n }\n\n async getWorkspaceArtifactContent(\n workspaceId: string,\n artifactId: string,\n versionId?: string,\n ): Promise<WorkspaceArtifactContentResponse> {\n const query = versionId ? `?versionId=${encodeURIComponent(versionId)}` : \"\";\n return await this.requestJson<WorkspaceArtifactContentResponse>(\n \"GET\",\n `/v1/workspaces/${workspaceId}/published-artifacts/${encodeURIComponent(artifactId)}/content${query}`,\n );\n }\n\n async createWorkspaceArtifact(\n workspaceId: string,\n request: CreateWorkspaceArtifactRequest,\n ): Promise<WorkspaceArtifactMutationResponse> {\n return await this.requestJson<WorkspaceArtifactMutationResponse>(\n \"POST\",\n `/v1/workspaces/${workspaceId}/published-artifacts`,\n request,\n );\n }\n\n async publishWorkspaceArtifactVersion(\n workspaceId: string,\n artifactId: string,\n request: PublishWorkspaceArtifactVersionRequest,\n ): Promise<WorkspaceArtifactMutationResponse> {\n return await this.requestJson<WorkspaceArtifactMutationResponse>(\n \"POST\",\n `/v1/workspaces/${workspaceId}/published-artifacts/${encodeURIComponent(artifactId)}/versions`,\n request,\n );\n }\n\n async rollbackWorkspaceArtifact(\n workspaceId: string,\n artifactId: string,\n request: RollbackWorkspaceArtifactRequest,\n ): Promise<WorkspaceArtifactMutationResponse> {\n return await this.requestJson<WorkspaceArtifactMutationResponse>(\n \"POST\",\n `/v1/workspaces/${workspaceId}/published-artifacts/${encodeURIComponent(artifactId)}/rollback`,\n request,\n );\n }\n}\n","import type { OpenGeniClient } from \"./client\";\nimport type { StreamSessionEventsOptions } from \"./stream\";\nimport type { SessionEvent } from \"./types\";\n\n/**\n * Proxy-through-your-own-API helpers.\n *\n * The intended pattern: a customer's server consumes the OpenGeni event\n * stream with its own API key (`client.streamEvents(...)`) and re-emits it to\n * its browser clients over its own authenticated endpoint — the OpenGeni key\n * never reaches the browser. The re-emitted wire format is identical to\n * OpenGeni's own SSE stream (`id: <sequence>`, `event: <type>`,\n * `data: <event JSON>`), so the browser side can consume it with this same\n * SDK's streaming core (or a plain `EventSource`), including resume via\n * `?after=` / `Last-Event-ID`.\n */\n\n/** Format one event exactly as OpenGeni's API emits it over SSE. */\nexport function formatSseEvent(event: SessionEvent): string {\n return `id: ${event.sequence}\\nevent: ${event.type}\\ndata: ${JSON.stringify(event)}\\n\\n`;\n}\n\nexport type SseReStreamOptions = {\n /**\n * Emit `: ping` comment lines at this interval, keeping intermediaries from\n * idling the connection out. Disabled when omitted.\n */\n heartbeatMs?: number;\n /**\n * Called when the downstream consumer cancels (e.g. the browser\n * disconnected). Use it to abort the upstream OpenGeni stream — an async\n * iterator that is mid-`await` cannot be interrupted by `return()` alone.\n */\n onCancel?: () => void;\n};\n\n/**\n * Re-emit a stream of session events as an SSE byte stream. Pull-based, so\n * upstream consumption follows downstream demand; cancelling the returned\n * stream fires `onCancel` and ends the upstream iterator.\n */\nexport function sessionEventsToSseStream(\n events: AsyncIterable<SessionEvent>,\n options: SseReStreamOptions = {},\n): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n const iterator = events[Symbol.asyncIterator]();\n let heartbeat: ReturnType<typeof setInterval> | undefined;\n let cancelled = false;\n\n const stopHeartbeat = (): void => {\n if (heartbeat !== undefined) {\n clearInterval(heartbeat);\n heartbeat = undefined;\n }\n };\n\n return new ReadableStream<Uint8Array>({\n start: (controller) => {\n if (options.heartbeatMs !== undefined) {\n heartbeat = setInterval(() => {\n try {\n controller.enqueue(encoder.encode(\": ping\\n\\n\"));\n } catch {\n stopHeartbeat();\n }\n }, options.heartbeatMs);\n }\n },\n pull: async (controller) => {\n let result: IteratorResult<SessionEvent, unknown>;\n try {\n result = await iterator.next();\n } catch (error) {\n stopHeartbeat();\n throw error;\n }\n if (cancelled) {\n return;\n }\n if (result.done) {\n stopHeartbeat();\n controller.close();\n return;\n }\n controller.enqueue(encoder.encode(formatSseEvent(result.value)));\n },\n cancel: () => {\n cancelled = true;\n stopHeartbeat();\n options.onCancel?.();\n // Fire-and-forget: if the iterator is suspended mid-await, return()\n // settles only after onCancel unblocks it; cancel must not hang on it.\n void Promise.resolve(iterator.return?.(undefined)).then(\n () => undefined,\n () => undefined,\n );\n },\n });\n}\n\n/** Wrap an event stream in a ready-to-return SSE `Response`. */\nexport function sessionEventsToSseResponse(\n events: AsyncIterable<SessionEvent>,\n options: SseReStreamOptions = {},\n): Response {\n return new Response(sessionEventsToSseStream(events, options), {\n headers: {\n \"Content-Type\": \"text/event-stream; charset=utf-8\",\n \"Cache-Control\": \"no-cache, no-transform\",\n Connection: \"keep-alive\",\n },\n });\n}\n\n/**\n * Read the resume cursor a reconnecting SSE client sent: the `after` query\n * parameter, or the standard `Last-Event-ID` header (the re-emitted stream\n * sets `id:` to the sequence). Returns 0 (full replay) when absent.\n */\nexport function resumeSequenceFromRequest(request: Request): number {\n const url = new URL(request.url);\n const raw = url.searchParams.get(\"after\") ?? request.headers.get(\"Last-Event-ID\");\n const parsed = raw === null ? 0 : Number(raw);\n return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : 0;\n}\n\nexport type ProxySessionEventStreamOptions = Omit<StreamSessionEventsOptions, \"after\"> & {\n /**\n * Resume cursor. Pass a number, or the incoming browser `Request` to\n * honor its `?after=` / `Last-Event-ID` automatically.\n */\n after?: number | Request;\n /** See {@link SseReStreamOptions.heartbeatMs}. */\n heartbeatMs?: number;\n};\n\n/**\n * One-call proxy: consume the OpenGeni stream server-side and return an SSE\n * `Response` for your own browser clients. Works anywhere WHATWG `Response`\n * is the handler return type (Hono, Next.js route handlers, Bun.serve,\n * Cloudflare Workers, ...).\n *\n * The upstream OpenGeni connection is torn down when the downstream client\n * disconnects, and also when `options.signal` (e.g. the incoming request's\n * signal) aborts.\n */\nexport function proxySessionEventStream(\n client: OpenGeniClient,\n workspaceId: string,\n sessionId: string,\n options: ProxySessionEventStreamOptions = {},\n): Response {\n const { after, heartbeatMs, signal, ...streamOptions } = options;\n const upstream = new AbortController();\n if (signal?.aborted) {\n upstream.abort();\n } else {\n signal?.addEventListener(\"abort\", () => upstream.abort(), { once: true });\n }\n const resolvedAfter = after instanceof Request ? resumeSequenceFromRequest(after) : (after ?? 0);\n const events = client.streamEvents(workspaceId, sessionId, {\n ...streamOptions,\n after: resolvedAfter,\n signal: upstream.signal,\n });\n return sessionEventsToSseResponse(events, {\n ...(heartbeatMs !== undefined ? { heartbeatMs } : {}),\n onCancel: () => upstream.abort(),\n });\n}\n","/**\n * A transport-tolerant MCP tool result.\n *\n * `value` is the canonical machine-readable payload after recognized MCP/JSON\n * envelopes are removed. `text` is the best presentation string without\n * discarding structured data. `raw` always retains the original evidence.\n */\nexport type NormalizedMcpOutput = Readonly<{\n raw: unknown;\n value: unknown;\n text: string;\n isError: boolean;\n}>;\n\nconst MAX_MCP_OUTPUT_DEPTH = 8;\nconst RESULT_ENVELOPE_KEYS = new Set([\"result\", \"isError\", \"jsonrpc\", \"id\", \"_meta\"]);\n\n/** Normalize common direct, JSON, and standard MCP result envelopes without throwing. */\nexport function normalizeMcpOutput(output: unknown): NormalizedMcpOutput {\n const normalized = normalizeValue(output, 0, new Set<object>());\n return {\n raw: output,\n value: normalized.value,\n text: normalized.text,\n isError: normalized.isError,\n };\n}\n\ntype NormalizedValue = Omit<NormalizedMcpOutput, \"raw\">;\n\nfunction normalizeValue(value: unknown, depth: number, ancestors: Set<object>): NormalizedValue {\n if (value === null || value === undefined) {\n return { value, text: \"\", isError: false };\n }\n if (typeof value === \"string\") {\n return normalizeText(value, depth, ancestors);\n }\n if (typeof value !== \"object\") {\n return { value, text: String(value), isError: false };\n }\n if (depth >= MAX_MCP_OUTPUT_DEPTH || ancestors.has(value)) {\n return { value, text: safeStringify(value), isError: false };\n }\n\n ancestors.add(value);\n try {\n if (Array.isArray(value)) {\n return { value, text: safeStringify(value), isError: false };\n }\n\n const record = value as Record<string, unknown>;\n const envelopeError = record.isError === true;\n\n if (record.type === \"text\" && typeof record.text === \"string\") {\n const normalized = normalizeText(record.text, depth + 1, ancestors);\n return {\n value: normalized.value,\n text: record.text,\n isError: envelopeError || normalized.isError,\n };\n }\n\n if (\"structuredContent\" in record) {\n const normalized = normalizeValue(record.structuredContent, depth + 1, ancestors);\n return {\n value: normalized.value,\n text: firstMcpText(record.content) ?? normalized.text,\n isError: envelopeError || normalized.isError,\n };\n }\n\n if (isMcpContent(record.content)) {\n const text = firstMcpText(record.content);\n if (text !== null) {\n const normalized = normalizeText(text, depth + 1, ancestors);\n return {\n value: normalized.value,\n text,\n isError: envelopeError || normalized.isError,\n };\n }\n return {\n value,\n text: safeStringify(value),\n isError: envelopeError,\n };\n }\n\n if (isResultEnvelope(record)) {\n const normalized = normalizeValue(record.result, depth + 1, ancestors);\n return {\n value: normalized.value,\n text: normalized.text,\n isError: envelopeError || normalized.isError,\n };\n }\n\n return {\n value,\n text: safeStringify(value),\n isError: envelopeError,\n };\n } finally {\n ancestors.delete(value);\n }\n}\n\nfunction normalizeText(text: string, depth: number, ancestors: Set<object>): NormalizedValue {\n try {\n const parsed: unknown = JSON.parse(text);\n const normalized = normalizeValue(parsed, depth + 1, ancestors);\n return {\n value: normalized.value,\n text,\n isError: normalized.isError,\n };\n } catch {\n return { value: text, text, isError: false };\n }\n}\n\nfunction isMcpContent(value: unknown): value is readonly Record<string, unknown>[] {\n return (\n Array.isArray(value) &&\n value.some(\n (part) =>\n part !== null &&\n typeof part === \"object\" &&\n typeof (part as { type?: unknown }).type === \"string\",\n )\n );\n}\n\nfunction firstMcpText(value: unknown): string | null {\n if (!Array.isArray(value)) {\n return null;\n }\n for (const part of value) {\n if (\n part !== null &&\n typeof part === \"object\" &&\n (part as { type?: unknown }).type === \"text\" &&\n typeof (part as { text?: unknown }).text === \"string\"\n ) {\n return (part as { text: string }).text;\n }\n }\n return null;\n}\n\nfunction isResultEnvelope(record: Record<string, unknown>): boolean {\n return \"result\" in record && Object.keys(record).every((key) => RESULT_ENVELOPE_KEYS.has(key));\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value) ?? \"\";\n } catch {\n return String(value);\n }\n}\n","// Zero-dependency desktop (noVNC) transport contract.\n//\n// The actual `@novnc/novnc` RFB import is a browser-only DOM dependency and\n// lives in `@opengeni/react` (lazily imported, SSR-safe). The framework-agnostic\n// SDK ships only the transport CONTRACT: a URL assembler, the minimal RFB\n// surface the component drives, the connection state machine, and the\n// rotation/fence reducers — all pure and unit-testable, with no DOM and no deps.\n//\n// Channel A (terminal-as-events, files, git) needs NO new transport here: those\n// are event projections + the synchronous fs/git/terminal point queries on\n// `OpenGeniClient`. Only the desktop pixel plane (Channel B, direct-to-provider)\n// needs this.\n\nimport type { DesktopStreamCapability, StreamUrlRotatedPayload } from \"./types\";\n\n/**\n * Translate the negotiated desktop capability into the WebSocket URL the noVNC\n * RFB client connects to. The scoped provider token is ALREADY embedded in the\n * minted `url` (Modal tunnel host, Blaxel `bl_preview_token`, Daytona signed\n * preview) by `session.resolveExposedPort(6080)` — we do NOT append `cap.token`\n * as a query param (that double-auth was an adversarial-review bug: the box runs\n * `-nopw` in v1, so the RFB password is meaningless and the real auth is the\n * tunnel token in the host). We only normalize the scheme to `ws`/`wss` and, when\n * the minted URL points at a `vnc.html` viewer page, rewrite it to the\n * websockify socket path noVNC actually dials.\n */\nexport function desktopSocketUrl(cap: Pick<DesktopStreamCapability, \"url\">): string {\n if (!cap.url) {\n throw new Error(\"desktop capability has no url (transport is null)\");\n }\n const u = new URL(cap.url);\n // https → wss, http → ws (noVNC dials a WebSocket, not the HTTP viewer page).\n if (u.protocol === \"https:\") {\n u.protocol = \"wss:\";\n } else if (u.protocol === \"http:\") {\n u.protocol = \"ws:\";\n }\n // A minted `…/vnc.html` (or `…/vnc_lite.html`) viewer page → the websockify\n // socket the page itself would open (`…/websockify`). A bare host/path with no\n // viewer page is already the socket path; leave it untouched.\n if (/\\/vnc(_lite)?\\.html$/.test(u.pathname)) {\n u.pathname = u.pathname.replace(/\\/vnc(_lite)?\\.html$/, \"/websockify\");\n u.search = \"\";\n u.hash = \"\";\n }\n return u.toString();\n}\n\n/**\n * The minimal RFB surface the React component drives. Lets tests (and 3rd\n * parties swapping noVNC for a WebRTC client in v3) provide a fake without the\n * DOM. Matches `@novnc/novnc`'s RFB constructor + lifecycle.\n */\nexport interface DesktopRfbLike {\n viewOnly: boolean;\n scaleViewport: boolean;\n /**\n * 1:1 viewport clipping. We always drive this FALSE: with clipping on, noVNC\n * paints the framebuffer pixel-for-pixel and scrolls/crops to the container\n * (the \"zoomed in\" look). FALSE lets `scaleViewport` shrink the 1280x800 frame\n * to fit the panel (aspect-preserved). Declared so the hook can pin it instead\n * of relying on noVNC's default — `scaleViewport=true` forces clip off\n * internally, but a stale/partial state on reconnect could leave it on.\n */\n clipViewport: boolean;\n addEventListener(\n type: \"connect\" | \"disconnect\" | \"securityfailure\",\n cb: (e?: unknown) => void,\n ): void;\n removeEventListener?: (\n type: \"connect\" | \"disconnect\" | \"securityfailure\",\n cb: (e?: unknown) => void,\n ) => void;\n disconnect(): void;\n}\n\nexport type DesktopRfbFactory = (\n target: HTMLElement,\n url: string,\n opts: { credentials?: { password?: string | undefined } | undefined },\n) => DesktopRfbLike;\n\nexport type DesktopConnectionState =\n | \"idle\"\n | \"negotiating\"\n | \"connecting\"\n | \"connected\"\n | \"rotating\"\n | \"reconnecting\"\n | \"error\"\n | \"ended\";\n\nexport type DesktopStreamEvent =\n | { type: \"negotiated\" }\n | { type: \"connected\" }\n | { type: \"disconnected\" }\n | { type: \"rotate\" }\n | { type: \"fail\" }\n | { type: \"abort\" };\n\n/**\n * Pure reducer for the desktop connection lifecycle. The component owns the RFB\n * object + DOM; this owns the transitions so they are unit-testable. Mirrors the\n * Channel-A stream reducer discipline.\n */\nexport function nextDesktopState(\n current: DesktopConnectionState,\n ev: DesktopStreamEvent,\n): DesktopConnectionState {\n switch (ev.type) {\n case \"negotiated\":\n return \"connecting\";\n case \"connected\":\n return \"connected\";\n case \"rotate\":\n return current === \"connected\" ? \"rotating\" : current;\n case \"disconnected\":\n // A deliberate teardown (ended) stays ended; everything else reconnects.\n return current === \"ended\" ? \"ended\" : \"reconnecting\";\n case \"fail\":\n return \"error\";\n case \"abort\":\n return \"ended\";\n default:\n return current;\n }\n}\n\n// `DesktopStreamCapability` is the desktop cell of `SessionCapabilities`; alias\n// it for the rotation reducer below without depending on the whole doc.\nexport type DesktopStreamCapabilityLike = {\n url: string | null;\n token: string | null;\n expiresAt: string | null;\n};\n\n/**\n * Apply a `stream.url.rotated` event onto a desktop capability, fencing on\n * leaseEpoch (split-brain). A rotation minted under an epoch the client has\n * already advanced PAST is from a superseded owner and is dropped (returns\n * null); otherwise the fresh url/token/expiresAt are folded in.\n */\nexport function applyUrlRotation<T extends DesktopStreamCapabilityLike>(\n cap: T,\n payload: StreamUrlRotatedPayload,\n knownEpoch: number,\n): T | null {\n if (payload.leaseEpoch < knownEpoch) {\n return null;\n }\n return { ...cap, url: payload.url, token: payload.token, expiresAt: payload.expiresAt };\n}\n","// Zero-dependency interactive-terminal (ttyd PTY-over-websocket) transport\n// contract. Symmetric with `desktop.ts`: the SDK ships only the pure transport\n// CONTRACT (a URL assembler + the ttyd wire-protocol frame codec), with no DOM\n// and no deps. The actual WebSocket open + xterm attach lives in `@opengeni/react`\n// (`use-terminal-stream.ts`).\n//\n// The interactive terminal is a REAL PTY streamed over the SAME Modal raw-TLS\n// tunnel as the desktop noVNC, with the SAME scoped stream-token mechanism. The\n// box bakes `ttyd` on `TERMINAL_STREAM_PORT` (7681); `session.resolveExposedPort`\n// mints the tunnel URL. The Terminal capability cell carries transport \"pty-ws\" +\n// that url + the scoped token when the box is warm and a viewer is attached.\n\nimport type { TerminalCapability } from \"./types\";\n\n/**\n * Translate the negotiated `pty-ws` Terminal capability into the WebSocket URL\n * the ttyd client dials. The scoped provider token is ALREADY embedded in the\n * minted `url` (the Modal tunnel host) by `session.resolveExposedPort(7681)` —\n * we do NOT append `cap.token` (identical posture to the desktop: the gate is the\n * unguessable short-TTL tunnel URL + the server-recorded scoped stream token; ttyd\n * runs `--writable` with no `-c` credential in v1). We only normalize the scheme\n * to `ws`/`wss`; a bare host is already the ttyd websocket endpoint.\n */\nexport function terminalSocketUrl(cap: Pick<TerminalCapability, \"url\">): string {\n if (!cap.url) {\n throw new Error(\"terminal capability has no url (transport is not pty-ws)\");\n }\n const u = new URL(cap.url);\n // https → wss, http → ws (ttyd is dialed as a WebSocket, not an HTTP page).\n if (u.protocol === \"https:\") {\n u.protocol = \"wss:\";\n } else if (u.protocol === \"http:\") {\n u.protocol = \"ws:\";\n }\n return u.toString();\n}\n\n// ── ttyd wire protocol ───────────────────────────────────────────────────────\n// ttyd frames are a single ASCII command char + payload. These mirror ttyd's\n// `protocol.h` Command enum. Client→server and server→client share the byte 0/1/2\n// values but mean different things per direction (see below).\n\n/** ttyd subprotocol — REQUIRED on the WebSocket handshake or ttyd refuses it. */\nexport const TTYD_SUBPROTOCOL = \"tty\";\n\n/** Client→server command bytes (the first char of each outbound text frame). */\nexport const TtydClientCommand = {\n /** stdin: \"0\" + raw input bytes. */\n INPUT: \"0\",\n /** window resize: \"1\" + JSON.stringify({ columns, rows }). */\n RESIZE: \"1\",\n /** flow-control pause (back-pressure): \"2\". */\n PAUSE: \"2\",\n /** flow-control resume: \"3\". */\n RESUME: \"3\",\n} as const;\n\n/** Server→client command bytes (the first char of each inbound frame). */\nexport const TtydServerCommand = {\n /** stdout/stderr: \"0\" + raw output bytes (write the rest into xterm). */\n OUTPUT: \"0\",\n /** set the window title: \"1\" + title string. */\n SET_WINDOW_TITLE: \"1\",\n /** ttyd client preferences JSON: \"2\" + json (ignored by us). */\n SET_PREFERENCES: \"2\",\n} as const;\n\n/**\n * The ttyd handshake's first frame: an auth message. ttyd expects\n * `JSON.stringify({ AuthToken })` as the FIRST text frame on the socket. We send\n * an empty token — our gate is the tunnel URL + scoped stream token, NOT a ttyd\n * `-c` basic-auth credential (which the box does not set in v1). Optional ttyd\n * `columns`/`rows` can ride this frame to seed the PTY size before the first\n * resize. Pure (string-building only) so it stays unit-testable in the SDK.\n */\nexport function ttydAuthFrame(opts?: { columns?: number; rows?: number }): string {\n const frame: { AuthToken: string; columns?: number; rows?: number } = { AuthToken: \"\" };\n if (opts?.columns && opts.columns > 0) frame.columns = opts.columns;\n if (opts?.rows && opts.rows > 0) frame.rows = opts.rows;\n return JSON.stringify(frame);\n}\n\n/** Build a client→server INPUT (stdin) frame: \"0\" + data. */\nexport function ttydInputFrame(data: string): string {\n return TtydClientCommand.INPUT + data;\n}\n\n/** Build a client→server RESIZE frame: \"1\" + JSON.stringify({ columns, rows }). */\nexport function ttydResizeFrame(columns: number, rows: number): string {\n return TtydClientCommand.RESIZE + JSON.stringify({ columns, rows });\n}\n","export type WorkspaceInstructionPolicyKind = \"charter\" | \"policy\";\nexport type WorkspaceInstructionPolicyScope = \"global\" | \"role\";\nexport type WorkspaceInstructionPolicyProvenanceSource =\n | \"human\"\n | \"onboarding\"\n | \"knowledge_proposal\"\n | \"legacy_import\";\nexport type WorkspaceInstructionPolicyDraftProvenanceSource = Exclude<\n WorkspaceInstructionPolicyProvenanceSource,\n \"legacy_import\"\n>;\nexport type WorkspaceInstructionPolicyActivationType = \"activate\" | \"rollback\";\n\nexport function normalizeWorkspaceInstructionPolicyRoleKey(value: string): string {\n return value.normalize(\"NFKC\").trim().toLowerCase().replace(/\\s+/gu, \"-\").replace(/-+/g, \"-\");\n}\n\nexport type WorkspaceInstructionPolicyTarget = {\n kind: WorkspaceInstructionPolicyKind;\n scope: WorkspaceInstructionPolicyScope;\n roleKey: string | null;\n};\n\nexport type WorkspaceInstructionPolicyRevisionIdentity = {\n id: string;\n revision: number;\n contentHash: string;\n};\n\nexport type WorkspaceInstructionPolicyRevision = WorkspaceInstructionPolicyRevisionIdentity &\n WorkspaceInstructionPolicyTarget & {\n accountId: string;\n workspaceId: string;\n content: string;\n provenance: {\n source: WorkspaceInstructionPolicyProvenanceSource;\n sourceId: string | null;\n };\n supersedesRevisionId: string | null;\n createdBySubjectId: string;\n createdAt: string;\n };\n\nexport type WorkspaceInstructionPolicyHead = WorkspaceInstructionPolicyTarget & {\n workspaceId: string;\n revisionId: string;\n revision: number;\n contentHash: string;\n activationVersion: number;\n activatedAt: string;\n};\n\nexport type WorkspaceInstructionPolicyActivationEvent = WorkspaceInstructionPolicyTarget & {\n id: string;\n accountId: string;\n workspaceId: string;\n type: WorkspaceInstructionPolicyActivationType;\n activationVersion: number;\n oldRevision: WorkspaceInstructionPolicyRevisionIdentity | null;\n newRevision: WorkspaceInstructionPolicyRevisionIdentity;\n actorSubjectId: string;\n reason: string;\n createdAt: string;\n};\n\nexport type CreateWorkspaceInstructionPolicyDraftRequest = WorkspaceInstructionPolicyTarget & {\n content: string;\n provenanceSource?: WorkspaceInstructionPolicyDraftProvenanceSource;\n provenanceSourceId?: string | null;\n supersedesRevisionId?: string | null;\n};\n\nexport type ImportLegacyWorkspaceInstructionPolicyDraftRequest = {\n supersedesRevisionId?: string | null;\n};\n\nexport type WorkspaceInstructionPolicyListOptions = {\n kind?: WorkspaceInstructionPolicyKind;\n scope?: WorkspaceInstructionPolicyScope;\n roleKey?: string;\n afterRevision?: number;\n limit?: number;\n};\n\nexport type WorkspaceInstructionPolicyListResponse = {\n revisions: WorkspaceInstructionPolicyRevision[];\n activeHeads: WorkspaceInstructionPolicyHead[];\n activationEvents: WorkspaceInstructionPolicyActivationEvent[];\n nextAfterRevision: number | null;\n};\n\nexport type WorkspaceInstructionPolicyDiffRequest = {\n fromRevisionId: string;\n toRevisionId: string;\n};\n\nexport type WorkspaceInstructionPolicyDiffResponse = {\n from: WorkspaceInstructionPolicyRevision;\n to: WorkspaceInstructionPolicyRevision;\n format: \"unified\";\n diff: string;\n};\n\nexport type ActivateWorkspaceInstructionPolicyRequest = {\n expectedCurrentRevisionId: string | null;\n reason: string;\n};\n\nexport type RollbackWorkspaceInstructionPolicyRequest = {\n targetRevisionId: string;\n expectedCurrentRevisionId: string;\n reason: string;\n};\n\nexport type WorkspaceInstructionPolicyActivationResponse = {\n head: WorkspaceInstructionPolicyHead;\n event: WorkspaceInstructionPolicyActivationEvent;\n};\n\nexport type WorkspaceInstructionPolicyConflictResponse = {\n code: \"WORKSPACE_INSTRUCTION_POLICY_CONFLICT\";\n message: string;\n currentHead: WorkspaceInstructionPolicyHead | null;\n};\n","export type PreferenceRegistryScope = \"organization\" | \"workspace\" | \"user\";\nexport type PreferenceRegistryStatus =\n | \"proposed\"\n | \"active\"\n | \"inactive\"\n | \"rejected\"\n | \"superseded\"\n | \"expired\";\nexport type PreferenceRegistryProvenanceSource =\n | \"human\"\n | \"onboarding\"\n | \"knowledge_proposal\"\n | \"imported_document\"\n | \"slack\"\n | \"meeting_transcript\"\n | \"call_transcript\";\nexport type PreferenceRegistryTrust =\n | \"untrusted_proposal\"\n | \"personal\"\n | \"workspace_managed\"\n | \"organization_managed\";\nexport type PreferenceRegistryConflictStrategy = \"override\" | \"merge\" | \"reject\" | \"inform\";\n\nexport function normalizePreferenceRegistryStableKey(value: string): string {\n return value.normalize(\"NFKC\").trim().toLowerCase().replace(/\\s+/gu, \"-\").replace(/-+/g, \"-\");\n}\n\nexport type PreferenceRegistryScopeTarget = {\n scope: PreferenceRegistryScope;\n workspaceId: string | null;\n subjectId: string | null;\n};\n\nexport type PreferenceRegistryPrecedence = {\n tier: PreferenceRegistryScope;\n rank: number;\n conflictStrategy: PreferenceRegistryConflictStrategy;\n conflictsWith: string[];\n};\n\nexport type PreferenceRegistryRevisionSummary = {\n id: string;\n preferenceId: string;\n revision: number;\n contentHash: string;\n title: string;\n description: string;\n precedence: PreferenceRegistryPrecedence;\n provenance: {\n source: PreferenceRegistryProvenanceSource;\n sourceId: string | null;\n trust: PreferenceRegistryTrust;\n };\n expiresAt: string | null;\n correctsRevisionId: string | null;\n createdBySubjectId: string;\n createdAt: string;\n};\n\nexport type PreferenceRegistryDescriptorProvenance = {\n source: PreferenceRegistryProvenanceSource;\n sourceIdHash: string | null;\n trust: PreferenceRegistryTrust;\n};\n\nexport type PreferenceRegistryRecord = {\n id: string;\n accountId: string;\n stableKey: string;\n target: PreferenceRegistryScopeTarget;\n status: PreferenceRegistryStatus;\n scopeVersion: number;\n activationVersion: number;\n activeRevision: PreferenceRegistryRevisionSummary | null;\n supersededByPreferenceId: string | null;\n createdBySubjectId: string;\n createdAt: string;\n updatedAt: string;\n};\n\nexport type PreferenceRegistryEvent = {\n id: string;\n accountId: string;\n preferenceId: string;\n type:\n | \"proposal_created\"\n | \"activated\"\n | \"corrected\"\n | \"rejected\"\n | \"deactivated\"\n | \"superseded\"\n | \"scope_changed\";\n version: number;\n oldRevisionId: string | null;\n newRevisionId: string | null;\n oldTarget: PreferenceRegistryScopeTarget | null;\n newTarget: PreferenceRegistryScopeTarget | null;\n relatedPreferenceId: string | null;\n actorSubjectId: string;\n reason: string;\n createdAt: string;\n};\n\nexport type PreferenceRegistryDescriptor = {\n id: string;\n stableKey: string;\n title: string;\n description: string;\n scope: PreferenceRegistryScope;\n activeVersion: number;\n revisionId: string;\n contentHash: string;\n precedence: PreferenceRegistryPrecedence;\n provenance: PreferenceRegistryDescriptorProvenance;\n expiresAt: string | null;\n retrievalHandle: string;\n};\n\nexport type PreferenceRegistrySnapshot = {\n id: string;\n workspaceId: string;\n sessionId: string;\n turnId: string;\n attemptId: string;\n executionGeneration: number;\n initiatingHumanSubjectId: string;\n descriptorHash: string;\n descriptors: PreferenceRegistryDescriptor[];\n truncated: boolean;\n createdAt: string;\n};\n\nexport type PreferenceRegistryFullContent = {\n descriptor: PreferenceRegistryDescriptor;\n content: string;\n};\n\nexport type CreatePreferenceRegistryProposalRequest = {\n stableKey: string;\n scope: PreferenceRegistryScope;\n title: string;\n description: string;\n content: string;\n precedenceRank?: number;\n conflictStrategy?: PreferenceRegistryConflictStrategy;\n conflictsWith?: string[];\n expiresAt?: string | null;\n provenanceSource?: PreferenceRegistryProvenanceSource;\n provenanceSourceId?: string | null;\n};\n\nexport type ActivatePreferenceRegistryRevisionRequest = {\n revisionId: string;\n expectedCurrentRevisionId: string | null;\n expectedScopeVersion: number;\n reason: string;\n};\n\nexport type CorrectPreferenceRegistryRequest = {\n expectedCurrentRevisionId: string;\n expectedScopeVersion: number;\n title: string;\n description: string;\n content: string;\n precedenceRank?: number;\n conflictStrategy?: PreferenceRegistryConflictStrategy;\n conflictsWith?: string[];\n expiresAt?: string | null;\n reason: string;\n};\n\nexport type DeactivatePreferenceRegistryRequest = {\n expectedCurrentRevisionId: string;\n expectedScopeVersion: number;\n reason: string;\n};\n\nexport type ChangePreferenceRegistryScopeRequest = {\n scope: PreferenceRegistryScope;\n expectedScopeVersion: number;\n reason: string;\n};\n\nexport type SupersedePreferenceRegistryRequest = {\n replacementPreferenceId: string;\n expectedCurrentRevisionId: string;\n expectedScopeVersion: number;\n reason: string;\n};\n\nexport type RejectPreferenceRegistryProposalRequest = {\n revisionId: string;\n expectedScopeVersion: number;\n reason: string;\n};\nexport type PreferenceRegistryListOptions = {\n scope?: PreferenceRegistryScope;\n status?: PreferenceRegistryStatus;\n limit?: number;\n};\nexport type PreferenceRegistryListResponse = { preferences: PreferenceRegistryRecord[] };\nexport type PreferenceRegistryDetailResponse = {\n preference: PreferenceRegistryRecord;\n revisions: PreferenceRegistryRevisionSummary[];\n events: PreferenceRegistryEvent[];\n};\nexport type PreferenceRegistryMutationResponse = {\n preference: PreferenceRegistryRecord;\n event: PreferenceRegistryEvent;\n};\n"],"mappings":"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","names":["OpenGeniClient"]}
package/dist/types.d.ts CHANGED
@@ -1,4 +1,165 @@
1
1
  import type { WorkspaceTranscriptionPolicy } from "./transcription";
2
+ export type CodexRealtimeWebrtcVersion = "v3";
3
+ export type CodexRealtimeVoice = "juniper" | "maple" | "spruce" | "ember" | "vale" | "breeze" | "arbor" | "sol" | "cove";
4
+ export type CodexRealtimeWebrtcRequest = {
5
+ realtimeId: string;
6
+ operationId: string;
7
+ browserInstanceId: string;
8
+ ownerKey: string;
9
+ expectedVersion: number;
10
+ expectedConnectionEpoch: number;
11
+ rotate: boolean;
12
+ browserActivation?: "required" | undefined;
13
+ sdp: string;
14
+ version: CodexRealtimeWebrtcVersion;
15
+ instructions?: string | undefined;
16
+ voice?: CodexRealtimeVoice | undefined;
17
+ };
18
+ export type CodexRealtimeWebrtcResponse = {
19
+ sdp: string;
20
+ version: CodexRealtimeWebrtcVersion;
21
+ model: "gpt-live-1-boulder-alpha";
22
+ connectionId: string;
23
+ connectionEpoch: number;
24
+ startupFenceSequence: number;
25
+ modeVersion: number;
26
+ replay: boolean;
27
+ };
28
+ export type GatewayRealtimeConnectRequest = {
29
+ realtimeId: string;
30
+ operationId: string;
31
+ browserInstanceId: string;
32
+ ownerKey: string;
33
+ expectedVersion: number;
34
+ expectedConnectionEpoch: number;
35
+ rotate: boolean;
36
+ };
37
+ export type GatewayRealtimeInitialItem = {
38
+ role: "user" | "developer" | "assistant";
39
+ text: string;
40
+ };
41
+ export type GatewayRealtimeConnectResponse = {
42
+ token: string;
43
+ url: string;
44
+ upstreamModelId: string;
45
+ expiresAt: number | null;
46
+ connectionId: string;
47
+ connectionEpoch: number;
48
+ startupFenceSequence: number;
49
+ modeVersion: number;
50
+ initialItems: GatewayRealtimeInitialItem[];
51
+ instructions: string;
52
+ replay: false;
53
+ };
54
+ export type ActivateCodexRealtimeConnectionRequest = {
55
+ operationId: string;
56
+ browserInstanceId: string;
57
+ ownerKey: string;
58
+ connectionEpoch: number;
59
+ expectedVersion: number;
60
+ expectedConnectionEpoch: number;
61
+ };
62
+ export type SessionRealtimeLedgerDirection = "provider_in" | "provider_out";
63
+ export type SessionRealtimeLedgerKind = "user_transcript" | "assistant_transcript" | "delegation_call" | "delegation_progress" | "delegation_result" | "interruption" | "session_update" | "error";
64
+ export type SessionRealtimeLedgerEntry = {
65
+ id: string;
66
+ realtimeId: string;
67
+ operationId: string;
68
+ connectionEpoch: number;
69
+ sequence: number;
70
+ direction: SessionRealtimeLedgerDirection;
71
+ kind: SessionRealtimeLedgerKind;
72
+ role: "user" | "assistant" | null;
73
+ providerEventId: string | null;
74
+ delegationItemId: string | null;
75
+ sourceUpdateId: string | null;
76
+ historyItemId: string | null;
77
+ turnId: string | null;
78
+ text: string | null;
79
+ payload: Record<string, unknown>;
80
+ clientAckedAt: string | null;
81
+ providerAckedAt: string | null;
82
+ createdAt: string;
83
+ updatedAt: string;
84
+ };
85
+ export type SessionRealtimeInboundEntry = {
86
+ operationId: string;
87
+ kind: Exclude<SessionRealtimeLedgerKind, "delegation_progress" | "delegation_result" | "session_update">;
88
+ role?: "user" | "assistant" | null | undefined;
89
+ providerEventId?: string | null | undefined;
90
+ delegationItemId?: string | null | undefined;
91
+ text?: string | null | undefined;
92
+ payload?: Record<string, unknown> | undefined;
93
+ };
94
+ export type SyncSessionRealtimeLedgerRequest = {
95
+ browserInstanceId: string;
96
+ ownerKey: string;
97
+ expectedVersion: number;
98
+ connectionId: string;
99
+ connectionEpoch: number;
100
+ entries?: SessionRealtimeInboundEntry[] | undefined;
101
+ clientAckThroughSequence?: number | null | undefined;
102
+ providerAckSequences?: number[] | undefined;
103
+ providerStarted?: {
104
+ providerSessionId: string;
105
+ providerEventId?: string | null | undefined;
106
+ } | undefined;
107
+ };
108
+ export type SyncSessionRealtimeLedgerResponse = {
109
+ accepted: Array<{
110
+ entry: SessionRealtimeLedgerEntry;
111
+ replay: boolean;
112
+ }>;
113
+ outbound: SessionRealtimeLedgerEntry[];
114
+ };
115
+ export type SessionRealtimeModel = "gpt-live-1-boulder-alpha" | "opengeni-gateway/openai/gpt-realtime-2.1" | "opengeni-gateway/openai/gpt-realtime-mini" | "opengeni-gateway/xai/grok-voice-think-fast-2.0" | "workspace-gateway/openai/gpt-realtime-2.1" | "workspace-gateway/openai/gpt-realtime-mini" | "workspace-gateway/xai/grok-voice-think-fast-2.0";
116
+ export type WorkspaceRealtimeModelCatalogItem = {
117
+ id: SessionRealtimeModel;
118
+ label: string;
119
+ provider: "OpenGeni" | "Connected Codex" | "Your Gateway";
120
+ description: string;
121
+ available: boolean;
122
+ unavailableReason: string | null;
123
+ recommended: boolean;
124
+ };
125
+ export type WorkspaceRealtimeModelCatalogResponse = {
126
+ models: WorkspaceRealtimeModelCatalogItem[];
127
+ };
128
+ export type SessionRealtimeState = "active" | "ended";
129
+ export type SessionRealtimeEndReason = "user_stop" | "browser_unload" | "lease_expired";
130
+ export type SessionRealtimeMode = {
131
+ id: string;
132
+ sessionId: string;
133
+ operationId: string;
134
+ browserInstanceId: string;
135
+ model: SessionRealtimeModel;
136
+ state: SessionRealtimeState;
137
+ version: number;
138
+ connectionEpoch: number;
139
+ leaseExpiresAt: string;
140
+ lastHeartbeatAt: string;
141
+ startedAt: string;
142
+ endedAt: string | null;
143
+ endReason: SessionRealtimeEndReason | null;
144
+ };
145
+ export type BeginSessionRealtimeRequest = {
146
+ operationId: string;
147
+ browserInstanceId: string;
148
+ ownerKey: string;
149
+ model: SessionRealtimeModel;
150
+ };
151
+ export type RenewSessionRealtimeRequest = {
152
+ browserInstanceId: string;
153
+ ownerKey: string;
154
+ expectedVersion: number;
155
+ };
156
+ export type EndSessionRealtimeRequest = RenewSessionRealtimeRequest & {
157
+ reason: Extract<SessionRealtimeEndReason, "user_stop" | "browser_unload">;
158
+ };
159
+ export type SessionRealtimeMutationResponse = {
160
+ mode: SessionRealtimeMode;
161
+ replay: boolean;
162
+ };
2
163
  export type SessionStatus = "queued" | "running" | "idle" | "requires_action" | "recovering" | "waiting_capacity" | "failed" | "cancelled";
3
164
  export type SandboxBackend = "docker" | "modal" | "local" | "none" | "daytona" | "runloop" | "e2b" | "blaxel" | "cloudflare" | "vercel" | "selfhosted";
4
165
  export type SandboxOs = "linux" | "macos" | "windows";
@@ -130,7 +291,7 @@ export type ViewerHeartbeatRequest = {
130
291
  export type ViewerHeartbeatResponse = {
131
292
  alive: boolean;
132
293
  };
133
- export type ReasoningEffort = "none" | "minimal" | "low" | "medium" | "high" | "xhigh";
294
+ export type ReasoningEffort = "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
134
295
  export type LatencyMode = "standard" | "priority" | "fast";
135
296
  export type GitCredentialProvider = "github" | "gitlab" | "azure_devops";
136
297
  export type GitCredentialBindingId = string;
@@ -453,6 +614,8 @@ export type Session = {
453
614
  title: string | null;
454
615
  titleSource: "user" | "agent" | null;
455
616
  instructions: string | null;
617
+ /** Immutable normalized prompt-policy role; distinct from membership roles. */
618
+ policyRole: string | null;
456
619
  resources: ResourceRef[];
457
620
  skills: SessionSkill[];
458
621
  tools: ToolRef[];
@@ -641,7 +804,7 @@ export type SessionHumanInputRequest = {
641
804
  createdAt: string;
642
805
  updatedAt: string;
643
806
  };
644
- export declare const SESSION_EVENT_TYPES: readonly ["session.created", "session.event.envelope_omitted", "session.status.changed", "session.requiresAction", "session.humanInput.requested", "session.context.compaction.requested", "session.context.compaction.started", "session.context.compacted", "session.context.compaction.skipped", "session.context.cleared", "user.message", "user.pause", "user.approvalDecision", "user.humanInputResponse", "turn.queued", "turn.started", "turn.completed", "turn.failed", "turn.cancelled", "turn.superseded", "turn.recovery.requested", "turn.capacity_waiting", "agent.message.delta", "agent.message.completed", "agent.reasoning.delta", "agent.toolCall.created", "agent.toolCall.output", "agent.model.request", "agent.model.usage", "tool.auth_needed", "credential.auth_needed", "agent.updated", "rig.setup.started", "rig.setup.completed", "rig.setup.skipped", "rig.setup.failed", "sandbox.operation.started", "sandbox.operation.completed", "sandbox.operation.failed", "sandbox.command.output.delta", "artifact.created", "goal.set", "goal.updated", "goal.completed", "goal.paused", "goal.resumed", "goal.cleared", "goal.continuation", "system.update.pending", "system.update.delivered", "system.update.superseded", "system.update.cancelled", "system.update.settled", "session.control.paused", "session.control.resumed", "session.control.steer_requested", "workspace.inference.paused", "workspace.inference.resumed", "session.queue.changed", "session.queue.prompt.cancelled", "session.queue.history", "turn.event.rejected_late", "memory.saved", "memory.corrected", "stream.url.rotated", "stream.opened", "stream.closed", "stream.revoked", "recording.started", "recording.available", "recording.failed", "fs.changed", "git.changed", "terminal.pty.started", "terminal.pty.output.delta", "terminal.pty.exited", "session.title_set", "session.mcp.approval_policy.updated", "session.tool_policy.updated", "codex.account.switched", "codex.credential.selected", "codex.fleet.decision", "codex.capacity.waiting", "codex.capacity.resumed", "codex.capacity.superseded", "sandbox.box.created", "sandbox.box.lost", "sandbox.box.terminated", "sandbox.box.snapshot", "sandbox.env.drift", "session.route.reconciled", "workspace.revision.captured", "workspace.revision.degraded", "machine.op.failed", "machine.op.recovered", "machine.link.lost", "machine.link.restored", "machine.runner.restarted"];
807
+ export declare const SESSION_EVENT_TYPES: readonly ["session.created", "session.event.envelope_omitted", "session.status.changed", "session.realtime.started", "session.realtime.ended", "session.requiresAction", "session.humanInput.requested", "session.context.compaction.requested", "session.context.compaction.started", "session.context.compacted", "session.context.compaction.skipped", "session.context.cleared", "user.message", "user.pause", "user.approvalDecision", "user.humanInputResponse", "turn.queued", "turn.started", "turn.completed", "turn.failed", "turn.cancelled", "turn.superseded", "turn.recovery.requested", "turn.capacity_waiting", "agent.message.delta", "agent.message.completed", "agent.reasoning.delta", "agent.toolCall.created", "agent.toolCall.output", "agent.model.request", "agent.model.usage", "tool.auth_needed", "credential.auth_needed", "agent.updated", "rig.setup.started", "rig.setup.completed", "rig.setup.skipped", "rig.setup.failed", "sandbox.operation.started", "sandbox.operation.completed", "sandbox.operation.failed", "sandbox.command.output.delta", "artifact.created", "goal.set", "goal.updated", "goal.completed", "goal.paused", "goal.resumed", "goal.cleared", "goal.continuation", "system.update.pending", "system.update.delivered", "system.update.superseded", "system.update.cancelled", "system.update.settled", "session.control.paused", "session.control.resumed", "session.control.steer_requested", "workspace.inference.paused", "workspace.inference.resumed", "session.queue.changed", "session.queue.prompt.cancelled", "session.queue.history", "turn.event.rejected_late", "memory.saved", "memory.corrected", "stream.url.rotated", "stream.opened", "stream.closed", "stream.revoked", "recording.started", "recording.available", "recording.failed", "fs.changed", "git.changed", "terminal.pty.started", "terminal.pty.output.delta", "terminal.pty.exited", "session.title_set", "session.mcp.approval_policy.updated", "session.tool_policy.updated", "codex.account.switched", "codex.credential.selected", "codex.fleet.decision", "codex.capacity.waiting", "codex.capacity.resumed", "codex.capacity.superseded", "sandbox.box.created", "sandbox.box.lost", "sandbox.box.terminated", "sandbox.box.snapshot", "sandbox.env.drift", "session.route.reconciled", "workspace.revision.captured", "workspace.revision.degraded", "machine.op.failed", "machine.op.recovered", "machine.link.lost", "machine.link.restored", "machine.runner.restarted"];
645
808
  export type KnownSessionEventType = (typeof SESSION_EVENT_TYPES)[number];
646
809
  /**
647
810
  * Event types the SDK knows about today, kept open so a newer OpenGeni server
@@ -1321,10 +1484,14 @@ export type ScheduledTask = {
1321
1484
  };
1322
1485
  export type CreateSessionRequest = {
1323
1486
  requestedSessionId?: string | undefined;
1324
- initialMessage: string;
1487
+ initialMessage?: string | undefined;
1488
+ /** Create an idle session shell so realtime voice can be the first interaction. */
1489
+ startMode?: "realtime" | undefined;
1325
1490
  /** System instructions scoped to the initial turn; never visible timeline text. */
1326
1491
  turnInstructions?: string | undefined;
1327
1492
  instructions?: string | undefined;
1493
+ /** Immutable normalized prompt-policy role; distinct from membership roles. */
1494
+ policyRole?: string | undefined;
1328
1495
  resources?: ResourceRef[] | undefined;
1329
1496
  /** Inline skills fixed onto this session; omitted children inherit them. */
1330
1497
  skills?: SessionSkill[] | undefined;
@@ -1810,8 +1977,28 @@ export type WorkspaceSettings = {
1810
1977
  maxNestedAgentDepth?: number | null | undefined;
1811
1978
  /** Default for new Codex sessions; absent ⇒ remote_v2. */
1812
1979
  codexCompactionDefault?: "remote_v2" | "portable" | undefined;
1980
+ slackReactionSummon?: WorkspaceSlackReactionSummonSettings | undefined;
1813
1981
  [key: string]: unknown;
1814
1982
  };
1983
+ export type WorkspaceSlackReactionSummonSettings = {
1984
+ enabled: boolean;
1985
+ emoji: string;
1986
+ channelPolicy: {
1987
+ mode: "bot_member";
1988
+ } | {
1989
+ mode: "allowlist";
1990
+ channelIds: string[];
1991
+ };
1992
+ };
1993
+ export type SlackReactionChannel = {
1994
+ id: string;
1995
+ name: string | null;
1996
+ isPrivate: boolean;
1997
+ };
1998
+ export type SlackReactionChannelListResponse = {
1999
+ channels: SlackReactionChannel[];
2000
+ nextCursor: string | null;
2001
+ };
1815
2002
  export type WorkspaceVoiceInputSettings = {
1816
2003
  enabled: boolean;
1817
2004
  };
@@ -1821,6 +2008,7 @@ export type UpdateWorkspaceSettingsRequest = {
1821
2008
  transcription?: WorkspaceTranscriptionPolicy | undefined;
1822
2009
  maxNestedAgentDepth?: number | null | undefined;
1823
2010
  codexCompactionDefault?: "remote_v2" | "portable" | undefined;
2011
+ slackReactionSummon?: WorkspaceSlackReactionSummonSettings | undefined;
1824
2012
  [key: string]: unknown;
1825
2013
  };
1826
2014
  export type SetWorkspaceDefaultRigRequest = {
@@ -2054,6 +2242,8 @@ export type SessionControlResponse = {
2054
2242
  effectiveControl: EffectiveSessionControl;
2055
2243
  interruptionCount: number;
2056
2244
  wakeCount: number;
2245
+ cancelledSessionCount: number;
2246
+ cancelledTurnCount: number;
2057
2247
  };
2058
2248
  export type WorkspaceInferenceControlResponse = {
2059
2249
  receipt: SessionCommandReceipt;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/sdk",
3
- "version": "0.36.1",
3
+ "version": "0.37.0",
4
4
  "description": "Framework-agnostic TypeScript SDK for the OpenGeni API: typed client, session lifecycle, SSE event streaming with reconnect + replay-by-sequence, and proxy re-streaming helpers.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -25,6 +25,14 @@
25
25
  "./core": {
26
26
  "types": "./dist/core.d.ts",
27
27
  "import": "./dist/core.js"
28
+ },
29
+ "./codex-realtime-controller": {
30
+ "types": "./dist/codex-realtime-controller.d.ts",
31
+ "import": "./dist/codex-realtime-controller.js"
32
+ },
33
+ "./gateway-realtime-transport": {
34
+ "types": "./dist/gateway-realtime-transport.d.ts",
35
+ "import": "./dist/gateway-realtime-transport.js"
28
36
  }
29
37
  },
30
38
  "publishConfig": {
@@ -36,6 +44,7 @@
36
44
  "build": "bun ../../scripts/build-typescript-package.ts",
37
45
  "prepublishOnly": "bash ../../scripts/prepublish-guard"
38
46
  },
47
+ "dependencies": {},
39
48
  "engines": {
40
49
  "node": ">=18"
41
50
  }