@opengeni/sdk 0.36.1 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -2
- package/dist/chunk-DXDL7EEW.js +573 -0
- package/dist/chunk-DXDL7EEW.js.map +1 -0
- package/dist/chunk-OINSI33U.js +97 -0
- package/dist/chunk-OINSI33U.js.map +1 -0
- package/dist/{chunk-B7E4FPNZ.js → chunk-SSQPCFEN.js} +159 -108
- package/dist/chunk-SSQPCFEN.js.map +1 -0
- package/dist/chunk-XBBPYTI5.js +2018 -0
- package/dist/chunk-XBBPYTI5.js.map +1 -0
- package/dist/client.d.ts +39 -4
- package/dist/codex-realtime-controller.d.ts +124 -0
- package/dist/codex-realtime-controller.js +18 -0
- package/dist/codex-realtime-controller.js.map +1 -0
- package/dist/codex-realtime-lifecycle.d.ts +18 -0
- package/dist/codex-realtime-v3-wire.d.ts +86 -0
- package/dist/codex-realtime-v3.d.ts +52 -0
- package/dist/codex-realtime.d.ts +68 -0
- package/dist/core.js +6 -4
- package/dist/gateway-realtime-transport.d.ts +2 -0
- package/dist/gateway-realtime-transport.js +7 -0
- package/dist/gateway-realtime-transport.js.map +1 -0
- package/dist/index.d.ts +13 -4
- package/dist/index.js +40 -6
- package/dist/index.js.map +1 -1
- package/dist/realtime.d.ts +45 -0
- package/dist/realtime.js +73 -0
- package/dist/realtime.js.map +1 -0
- package/dist/types.d.ts +225 -6
- package/dist/workspace-instruction-policies.d.ts +12 -0
- package/dist/workspace-state.d.ts +70 -4
- package/package.json +14 -1
- package/src/client.ts +248 -20
- package/src/codex-realtime-controller.ts +1465 -0
- package/src/codex-realtime-lifecycle.ts +97 -0
- package/src/codex-realtime-v3-wire.ts +349 -0
- package/src/codex-realtime-v3.ts +575 -0
- package/src/codex-realtime.ts +411 -0
- package/src/gateway-realtime-transport.ts +650 -0
- package/src/index.ts +81 -0
- package/src/realtime.ts +172 -0
- package/src/types.ts +280 -6
- package/src/workspace-instruction-policies.ts +13 -0
- package/src/workspace-state.ts +82 -4
- package/dist/chunk-B7E4FPNZ.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/gateway-realtime-transport.ts"],"sourcesContent":["import type { CodexRealtimeAudibleOutputState, CodexRealtimeWebrtcSession } from \"./codex-realtime\";\nimport type {\n CodexRealtimeControllerClient,\n RealtimeControllerTransportStarter,\n} from \"./codex-realtime-controller\";\n\ntype GatewayClientEvent = Record<string, unknown> & { type: string };\ntype GatewayServerEvent = Record<string, unknown> & { type: string };\n\nconst AUDIO_SAMPLE_RATE = 24_000;\nconst DELEGATION_TOOL = \"delegate_to_session\";\n\nexport function createGatewayRealtimeTransportStarter(): RealtimeControllerTransportStarter {\n return async (input) => {\n const client = input.client as CodexRealtimeControllerClient;\n if (!client.negotiateGatewayRealtime) {\n throw new Error(\"The OpenGeni client does not support AI Gateway realtime\");\n }\n const answer = await client.negotiateGatewayRealtime(\n input.workspaceId,\n input.sessionId,\n {\n realtimeId: input.realtimeId,\n operationId: input.operationId,\n browserInstanceId: input.browserInstanceId,\n ownerKey: input.ownerKey,\n expectedVersion: input.expectedVersion,\n expectedConnectionEpoch: input.expectedConnectionEpoch,\n rotate: input.rotate,\n },\n { signal: input.signal },\n );\n throwIfAborted(input.signal);\n\n const websocket = new WebSocket(answer.url, [\n \"ai-gateway-realtime.v1\",\n `ai-gateway-auth.${answer.token}`,\n ]);\n const channel = new GatewayRealtimeDataChannel((payload) =>\n handleBridgeOutbound(websocket, payload),\n );\n input.onEventsCreated(channel.asRtcDataChannel());\n const audio = new GatewayRealtimeAudio({\n onAudio: (encoded) => send(websocket, { type: \"input-audio-append\", audio: encoded }),\n onAudibleOutputState: input.onAudibleOutputState,\n });\n let stopped = false;\n let currentOutputItemId: string | null = null;\n const finalizedAssistantItems = new Set<string>();\n const microphoneTracks = input.media.getAudioTracks();\n const onMicrophoneEnded = (): void => {\n if (!stopped) input.onMicrophoneEnded();\n };\n for (const track of microphoneTracks) track.addEventListener?.(\"ended\", onMicrophoneEnded);\n\n const onMessage = (event: MessageEvent): void => {\n if (typeof event.data !== \"string\") return;\n let parsed: unknown;\n try {\n parsed = JSON.parse(event.data);\n } catch {\n return;\n }\n if (!isRecord(parsed) || typeof parsed.type !== \"string\") return;\n handleGatewayEvent({\n event: parsed as GatewayServerEvent,\n channel,\n websocket,\n audio,\n finalizedAssistantItems,\n getCurrentOutputItemId: () => currentOutputItemId,\n setCurrentOutputItemId: (value) => {\n currentOutputItemId = value;\n },\n });\n };\n const onClose = (): void => {\n if (!stopped) input.onConnectionHealth(\"closed\");\n };\n const onError = (): void => {\n if (!stopped) input.onConnectionHealth(\"failed\");\n };\n websocket.addEventListener(\"message\", onMessage);\n websocket.addEventListener(\"close\", onClose);\n websocket.addEventListener(\"error\", onError);\n\n await waitForWebSocketOpen(websocket, input.signal);\n channel.open();\n send(websocket, {\n type: \"session-update\",\n config: {\n instructions: answer.instructions,\n outputModalities: [\"audio\"],\n inputAudioFormat: { type: \"audio/pcm\", rate: AUDIO_SAMPLE_RATE },\n outputAudioFormat: { type: \"audio/pcm\", rate: AUDIO_SAMPLE_RATE },\n inputAudioTranscription: {},\n outputAudioTranscription: {},\n turnDetection: {\n type: \"server-vad\",\n prefixPaddingMs: 300,\n silenceDurationMs: 500,\n },\n tools: [\n {\n type: \"function\",\n name: DELEGATION_TOOL,\n description:\n \"Pass execution work, actions, and session tasks to the underlying session agent. Include the complete standalone request and relevant conversational context.\",\n parameters: {\n type: \"object\",\n properties: {\n request: {\n type: \"string\",\n description: \"Complete standalone task for the session agent\",\n },\n },\n required: [\"request\"],\n additionalProperties: false,\n },\n },\n ],\n },\n });\n for (const item of answer.initialItems) {\n send(websocket, {\n type: \"conversation-item-create\",\n item: {\n type: \"text-message\",\n role: \"user\",\n text: `<session_initial_item role=\"${item.role}\">\\n${item.text}\\n</session_initial_item>`,\n },\n });\n }\n await audio.startCapture(input.media);\n input.onConnectionHealth(\"connected\");\n\n const stop = (): void => {\n if (stopped) return;\n stopped = true;\n input.signal.removeEventListener(\"abort\", stop);\n websocket.removeEventListener(\"message\", onMessage);\n websocket.removeEventListener(\"close\", onClose);\n websocket.removeEventListener(\"error\", onError);\n for (const track of microphoneTracks) track.removeEventListener?.(\"ended\", onMicrophoneEnded);\n channel.close();\n audio.dispose();\n if (\n websocket.readyState === WebSocket.OPEN ||\n websocket.readyState === WebSocket.CONNECTING\n ) {\n websocket.close(1000, \"OpenGeni realtime connection retired\");\n }\n };\n input.signal.addEventListener(\"abort\", stop, { once: true });\n\n return {\n peerConnection: null as unknown as RTCPeerConnection,\n events: channel.asRtcDataChannel(),\n media: input.media,\n operationId: input.operationId,\n connectionId: answer.connectionId,\n connectionEpoch: answer.connectionEpoch,\n startupFenceSequence: answer.startupFenceSequence,\n modeVersion: answer.modeVersion,\n microphoneHealthy: () =>\n microphoneTracks.length > 0 &&\n microphoneTracks.every((track) => track.readyState !== \"ended\"),\n audibleOutputState: () => audio.audibleOutputState(),\n setOutputMuted: (muted) => audio.setMuted(muted),\n activateRemoteAudio: () => void audio.resume(),\n retryAudibleOutput: () => audio.resume(),\n stop,\n } satisfies CodexRealtimeWebrtcSession;\n };\n}\n\nfunction handleGatewayEvent(input: {\n event: GatewayServerEvent;\n channel: GatewayRealtimeDataChannel;\n websocket: WebSocket;\n audio: GatewayRealtimeAudio;\n finalizedAssistantItems: Set<string>;\n getCurrentOutputItemId(): string | null;\n setCurrentOutputItemId(value: string | null): void;\n}): void {\n const event = input.event;\n const eventId = providerEventId(event);\n if (event.type === \"session-created\") {\n const sessionId = stringValue(event.sessionId) ?? `gateway-${crypto.randomUUID()}`;\n input.channel.providerEvent({\n type: \"session.started\",\n event_id: eventId,\n session: { id: sessionId },\n });\n return;\n }\n if (event.type === \"speech-started\") {\n const itemId = input.getCurrentOutputItemId();\n if (itemId && input.audio.isPlaying()) {\n const audioEndMs = input.audio.playbackOffsetMs();\n input.audio.stopPlayback();\n send(input.websocket, {\n type: \"conversation-item-truncate\",\n itemId,\n contentIndex: 0,\n audioEndMs: Math.max(0, Math.round(audioEndMs)),\n });\n }\n return;\n }\n if (event.type === \"input-transcription-completed\") {\n const transcript = stringValue(event.transcript) ?? \"\";\n const itemId = stringValue(event.itemId) ?? crypto.randomUUID();\n if (transcript.trim()) {\n input.channel.providerEvent({\n type: \"turn.done\",\n event_id: eventId,\n turn: { id: itemId, role: \"user\", transcript },\n });\n }\n return;\n }\n if (event.type === \"audio-delta\") {\n const delta = stringValue(event.delta);\n if (!delta) return;\n const itemId = stringValue(event.itemId);\n if (itemId) input.setCurrentOutputItemId(itemId);\n input.audio.play(delta);\n input.channel.providerEvent({ type: \"output_audio.delta\", event_id: eventId, audio: delta });\n return;\n }\n if (event.type === \"audio-transcript-done\" || event.type === \"text-done\") {\n const itemId = stringValue(event.itemId) ?? crypto.randomUUID();\n const transcript = stringValue(event.transcript) ?? stringValue(event.text) ?? \"\";\n if (transcript.trim() && !input.finalizedAssistantItems.has(itemId)) {\n input.finalizedAssistantItems.add(itemId);\n input.channel.providerEvent({\n type: \"turn.done\",\n event_id: eventId,\n turn: { id: itemId, role: \"assistant\", transcript },\n });\n }\n return;\n }\n if (event.type === \"audio-done\") return;\n if (event.type === \"function-call-arguments-done\") {\n const callId = stringValue(event.callId) ?? stringValue(event.itemId) ?? crypto.randomUUID();\n const name = stringValue(event.name);\n if (name !== DELEGATION_TOOL) {\n send(input.websocket, {\n type: \"conversation-item-create\",\n item: {\n type: \"function-call-output\",\n callId,\n name,\n output: JSON.stringify({ error: \"Unsupported realtime tool\" }),\n },\n });\n send(input.websocket, { type: \"response-create\" });\n return;\n }\n const request = delegationRequest(stringValue(event.arguments) ?? \"\");\n input.channel.providerEvent({\n type: \"delegation.created\",\n event_id: eventId,\n item: {\n id: callId,\n type: \"delegation\",\n target: \"client\",\n content: [{ type: \"input_text\", text: request }],\n },\n });\n return;\n }\n if (event.type === \"error\") {\n input.channel.providerEvent({\n type: \"error\",\n event_id: eventId,\n message: stringValue(event.message) ?? \"AI Gateway realtime provider error\",\n });\n }\n}\n\nclass GatewayRealtimeDataChannel extends EventTarget {\n readyState: RTCDataChannelState = \"connecting\";\n private pendingOutbound: Array<Record<string, unknown>> = [];\n private outboundScheduled = false;\n\n constructor(private readonly outbound: (messages: Array<Record<string, unknown>>) => void) {\n super();\n }\n\n asRtcDataChannel(): RTCDataChannel {\n return this as unknown as RTCDataChannel;\n }\n\n open(): void {\n this.readyState = \"open\";\n this.dispatchEvent(new Event(\"open\"));\n }\n\n send(payload: string): void {\n if (this.readyState !== \"open\") throw new Error(\"Gateway realtime channel is not open\");\n let parsed: unknown;\n try {\n parsed = JSON.parse(payload);\n } catch {\n return;\n }\n if (!isRecord(parsed)) return;\n this.pendingOutbound.push(parsed);\n if (this.outboundScheduled) return;\n this.outboundScheduled = true;\n queueMicrotask(() => {\n this.outboundScheduled = false;\n const messages = this.pendingOutbound;\n this.pendingOutbound = [];\n if (messages.length > 0 && this.readyState === \"open\") this.outbound(messages);\n });\n }\n\n providerEvent(event: Record<string, unknown>): void {\n if (this.readyState === \"closed\") return;\n this.dispatchEvent(new MessageEvent(\"message\", { data: JSON.stringify(event) }));\n }\n\n close(): void {\n if (this.readyState === \"closed\") return;\n this.readyState = \"closed\";\n this.pendingOutbound = [];\n this.dispatchEvent(new Event(\"close\"));\n }\n}\n\nfunction handleBridgeOutbound(\n websocket: WebSocket,\n messages: Array<Record<string, unknown>>,\n): void {\n const groups = new Map<\n string,\n { type: string; id: string | null; channel: string; text: string }\n >();\n for (const message of messages) {\n const type = stringValue(message.type);\n if (type !== \"session.context.append\" && type !== \"delegation.context.append\") continue;\n const id = stringValue(message.delegation_item_id) ?? null;\n const channel = stringValue(message.channel) ?? \"commentary\";\n const key = `${type}:${id ?? \"session\"}:${channel}`;\n const content = Array.isArray(message.content) ? message.content : [];\n const text = content\n .filter(isRecord)\n .map((part) => stringValue(part.text) ?? \"\")\n .join(\"\");\n const existing = groups.get(key);\n groups.set(key, {\n type,\n id,\n channel,\n text: `${existing?.text ?? \"\"}${text}`,\n });\n }\n for (const group of groups.values()) {\n if (group.type === \"delegation.context.append\" && group.id && group.channel === \"speakable\") {\n send(websocket, {\n type: \"conversation-item-create\",\n item: {\n type: \"function-call-output\",\n callId: group.id,\n name: DELEGATION_TOOL,\n output: JSON.stringify({ result: group.text }),\n },\n });\n send(websocket, { type: \"response-create\" });\n continue;\n }\n const wrapper =\n group.type === \"delegation.context.append\"\n ? group.channel === \"commentary\"\n ? \"execution_progress\"\n : \"execution_result\"\n : \"session_update\";\n send(websocket, {\n type: \"conversation-item-create\",\n item: {\n type: \"text-message\",\n role: \"user\",\n text: `<${wrapper}>\\n${group.text}\\n</${wrapper}>`,\n },\n });\n if (group.channel === \"speakable\") send(websocket, { type: \"response-create\" });\n }\n}\n\nclass GatewayRealtimeAudio {\n private captureContext: AudioContext | null = null;\n private captureSource: MediaStreamAudioSourceNode | null = null;\n private captureProcessor: ScriptProcessorNode | null = null;\n private playbackContext: AudioContext | null = null;\n private playbackGain: GainNode | null = null;\n private playbackTime = 0;\n private playbackStartedAt = 0;\n private activeSources = new Set<AudioBufferSourceNode>();\n private outputState: CodexRealtimeAudibleOutputState = \"inactive\";\n private muted = false;\n\n constructor(\n private readonly options: {\n onAudio(audio: string): void;\n onAudibleOutputState(state: CodexRealtimeAudibleOutputState): void;\n },\n ) {}\n\n async startCapture(media: MediaStream): Promise<void> {\n const context = new AudioContext({ sampleRate: AUDIO_SAMPLE_RATE });\n this.captureContext = context;\n const source = context.createMediaStreamSource(media);\n const processor = context.createScriptProcessor(4096, 1, 1);\n this.captureSource = source;\n this.captureProcessor = processor;\n processor.onaudioprocess = (event) => {\n const samples = resample(\n new Float32Array(event.inputBuffer.getChannelData(0)),\n context.sampleRate,\n AUDIO_SAMPLE_RATE,\n );\n this.options.onAudio(encodePcm16(samples));\n };\n source.connect(processor);\n processor.connect(context.destination);\n await context.resume();\n }\n\n play(encoded: string): void {\n const context = (this.playbackContext ??= new AudioContext({ sampleRate: AUDIO_SAMPLE_RATE }));\n if (context.state !== \"running\") {\n void this.resume().then((resumed) => {\n if (resumed) this.schedule(encoded);\n });\n return;\n }\n this.schedule(encoded);\n }\n\n private schedule(encoded: string): void {\n const context = this.playbackContext;\n if (!context) return;\n const samples = decodePcm16(encoded);\n const buffer = context.createBuffer(1, samples.length, AUDIO_SAMPLE_RATE);\n buffer.getChannelData(0).set(samples);\n const source = context.createBufferSource();\n source.buffer = buffer;\n source.connect(this.outputNode(context));\n const startAt = Math.max(context.currentTime, this.playbackTime);\n if (this.activeSources.size === 0) this.playbackStartedAt = startAt;\n source.start(startAt);\n this.playbackTime = startAt + buffer.duration;\n this.activeSources.add(source);\n this.publish(\"audible\");\n source.onended = () => {\n this.activeSources.delete(source);\n if (this.activeSources.size === 0) this.publish(\"inactive\");\n };\n }\n\n stopPlayback(): void {\n for (const source of this.activeSources) {\n try {\n source.stop();\n } catch {\n // Already stopped.\n }\n }\n this.activeSources.clear();\n if (this.playbackContext) this.playbackTime = this.playbackContext.currentTime;\n this.publish(\"inactive\");\n }\n\n playbackOffsetMs(): number {\n return this.playbackContext\n ? Math.max(0, (this.playbackContext.currentTime - this.playbackStartedAt) * 1000)\n : 0;\n }\n\n audibleOutputState(): CodexRealtimeAudibleOutputState {\n return this.outputState;\n }\n\n setMuted(muted: boolean): void {\n this.muted = muted;\n const context = this.playbackContext;\n const gain = this.playbackGain;\n if (context && gain) gain.gain.setValueAtTime(muted ? 0 : 1, context.currentTime);\n }\n\n isPlaying(): boolean {\n return this.activeSources.size > 0;\n }\n\n async resume(): Promise<boolean> {\n const context = (this.playbackContext ??= new AudioContext({ sampleRate: AUDIO_SAMPLE_RATE }));\n this.publish(\"pending\");\n try {\n await context.resume();\n this.publish(this.activeSources.size > 0 ? \"audible\" : \"inactive\");\n return true;\n } catch {\n this.publish(\"blocked\");\n return false;\n }\n }\n\n dispose(): void {\n this.captureProcessor?.disconnect();\n this.captureSource?.disconnect();\n void this.captureContext?.close();\n this.captureProcessor = null;\n this.captureSource = null;\n this.captureContext = null;\n this.stopPlayback();\n this.playbackGain?.disconnect();\n void this.playbackContext?.close();\n this.playbackGain = null;\n this.playbackContext = null;\n }\n\n private outputNode(context: AudioContext): GainNode {\n if (!this.playbackGain) {\n this.playbackGain = context.createGain();\n this.playbackGain.gain.value = this.muted ? 0 : 1;\n this.playbackGain.connect(context.destination);\n }\n return this.playbackGain;\n }\n\n private publish(state: CodexRealtimeAudibleOutputState): void {\n if (state === this.outputState) return;\n this.outputState = state;\n this.options.onAudibleOutputState(state);\n }\n}\n\nfunction send(websocket: WebSocket, event: GatewayClientEvent): void {\n if (websocket.readyState !== WebSocket.OPEN) return;\n websocket.send(JSON.stringify(event));\n}\n\nfunction delegationRequest(argumentsJson: string): string {\n try {\n const parsed = JSON.parse(argumentsJson) as unknown;\n if (isRecord(parsed) && typeof parsed.request === \"string\" && parsed.request.trim()) {\n return parsed.request.trim();\n }\n } catch {\n // Fall through to the provider's raw argument string.\n }\n return argumentsJson.trim() || \"Continue the user's current request.\";\n}\n\nfunction providerEventId(event: Record<string, unknown>): string {\n const raw = isRecord(event.raw) ? event.raw : null;\n return (\n stringValue(event.eventId) ??\n stringValue(raw?.event_id) ??\n stringValue(raw?.id) ??\n crypto.randomUUID()\n );\n}\n\nfunction encodePcm16(samples: Float32Array): string {\n const bytes = new Uint8Array(samples.length * 2);\n const view = new DataView(bytes.buffer);\n for (let index = 0; index < samples.length; index += 1) {\n const sample = Math.max(-1, Math.min(1, samples[index] ?? 0));\n view.setInt16(index * 2, sample < 0 ? sample * 0x8000 : sample * 0x7fff, true);\n }\n let binary = \"\";\n for (let start = 0; start < bytes.length; start += 0x8000) {\n binary += String.fromCharCode(...bytes.subarray(start, start + 0x8000));\n }\n return btoa(binary);\n}\n\nfunction decodePcm16(encoded: string): Float32Array {\n const binary = atob(encoded);\n const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n const samples = new Float32Array(Math.floor(bytes.byteLength / 2));\n for (let index = 0; index < samples.length; index += 1) {\n samples[index] = view.getInt16(index * 2, true) / 32768;\n }\n return samples;\n}\n\nfunction resample(input: Float32Array, inputRate: number, outputRate: number): Float32Array {\n if (inputRate === outputRate) return input;\n const ratio = inputRate / outputRate;\n const output = new Float32Array(Math.round(input.length / ratio));\n for (let index = 0; index < output.length; index += 1) {\n const source = index * ratio;\n const floor = Math.floor(source);\n const ceil = Math.min(floor + 1, input.length - 1);\n const fraction = source - floor;\n output[index] = (input[floor] ?? 0) * (1 - fraction) + (input[ceil] ?? 0) * fraction;\n }\n return output;\n}\n\nasync function waitForWebSocketOpen(websocket: WebSocket, signal: AbortSignal): Promise<void> {\n if (websocket.readyState === WebSocket.OPEN) return;\n await new Promise<void>((resolve, reject) => {\n const cleanup = (): void => {\n websocket.removeEventListener(\"open\", onOpen);\n websocket.removeEventListener(\"error\", onError);\n websocket.removeEventListener(\"close\", onClose);\n signal.removeEventListener(\"abort\", onAbort);\n };\n const onOpen = (): void => {\n cleanup();\n resolve();\n };\n const onError = (): void => {\n cleanup();\n reject(new Error(\"AI Gateway realtime WebSocket failed to open\"));\n };\n const onClose = (): void => {\n cleanup();\n reject(new Error(\"AI Gateway realtime WebSocket closed before opening\"));\n };\n const onAbort = (): void => {\n cleanup();\n reject(signal.reason ?? new DOMException(\"Aborted\", \"AbortError\"));\n };\n websocket.addEventListener(\"open\", onOpen, { once: true });\n websocket.addEventListener(\"error\", onError, { once: true });\n websocket.addEventListener(\"close\", onClose, { once: true });\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction stringValue(value: unknown): string | null {\n return typeof value === \"string\" ? value : null;\n}\n\nfunction throwIfAborted(signal: AbortSignal): void {\n if (signal.aborted) throw signal.reason ?? new DOMException(\"Aborted\", \"AbortError\");\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var OpenGeniApiError = class extends Error {
|
|
3
|
+
status;
|
|
4
|
+
code;
|
|
5
|
+
retryable;
|
|
6
|
+
correlationId;
|
|
7
|
+
/** True only when an uncontrolled transport failed after a mutation may have been accepted. */
|
|
8
|
+
outcomeUnknown;
|
|
9
|
+
body;
|
|
10
|
+
constructor(status, body, options = {}) {
|
|
11
|
+
const decoded = decodeApiErrorBody(body);
|
|
12
|
+
const correlationId = decoded?.requestId ?? boundedCorrelationId(options.correlationId);
|
|
13
|
+
const gatewayFailure = status >= 502 && status <= 504;
|
|
14
|
+
const fromResponse = options.mutation !== void 0;
|
|
15
|
+
const message = decoded?.message ?? (fromResponse ? "Request failed." : body || "(empty body)");
|
|
16
|
+
const displayMessage = options.displayMessage ?? (gatewayFailure && fromResponse ? "OpenGeni is temporarily unavailable \u2014 retry." : `OpenGeni API ${status}: ${message}`);
|
|
17
|
+
super(correlationId ? `${displayMessage} Reference: ${correlationId}.` : displayMessage);
|
|
18
|
+
this.name = "OpenGeniApiError";
|
|
19
|
+
this.status = status;
|
|
20
|
+
this.code = options.code ?? decoded?.code ?? (gatewayFailure && fromResponse ? "upstream_unavailable" : void 0);
|
|
21
|
+
this.retryable = options.retryable ?? decoded?.retryable ?? retryableApiStatus(status);
|
|
22
|
+
this.correlationId = correlationId;
|
|
23
|
+
this.outcomeUnknown = options.outcomeUnknown ?? (gatewayFailure && !!options.mutation && !decoded);
|
|
24
|
+
this.body = !fromResponse || decoded ? body : "";
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
function decodeApiErrorBody(body) {
|
|
28
|
+
if (!body) return null;
|
|
29
|
+
try {
|
|
30
|
+
const decoded = JSON.parse(body);
|
|
31
|
+
if (!decoded || typeof decoded !== "object" || Array.isArray(decoded)) return null;
|
|
32
|
+
const record = decoded;
|
|
33
|
+
const nested = record.error && typeof record.error === "object" && !Array.isArray(record.error) ? record.error : record;
|
|
34
|
+
const code = boundedApiField(nested.code);
|
|
35
|
+
const message = boundedApiField(nested.message);
|
|
36
|
+
const requestId = boundedCorrelationId(nested.requestId);
|
|
37
|
+
const retryable = typeof nested.retryable === "boolean" ? nested.retryable : void 0;
|
|
38
|
+
if (!code && !message && !requestId && retryable === void 0) return null;
|
|
39
|
+
return {
|
|
40
|
+
code,
|
|
41
|
+
message,
|
|
42
|
+
requestId,
|
|
43
|
+
retryable
|
|
44
|
+
};
|
|
45
|
+
} catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function boundedApiField(value) {
|
|
50
|
+
if (typeof value !== "string") return;
|
|
51
|
+
const bytes = new TextEncoder().encode(value);
|
|
52
|
+
return bytes.byteLength <= 512 ? value : new TextDecoder().decode(bytes.slice(0, 512));
|
|
53
|
+
}
|
|
54
|
+
function retryableApiStatus(status) {
|
|
55
|
+
return status === 408 || status === 409 || status === 425 || status === 429 || status >= 500;
|
|
56
|
+
}
|
|
57
|
+
function boundedCorrelationId(value) {
|
|
58
|
+
if (typeof value !== "string" || value.length > 128 || !/^[\w.:-]+$/.test(value)) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
var OpenGeniSessionListCursorError = class extends OpenGeniApiError {
|
|
64
|
+
};
|
|
65
|
+
var OpenGeniApiContractMismatchError = class extends Error {
|
|
66
|
+
expected;
|
|
67
|
+
actual;
|
|
68
|
+
constructor(expected, actual) {
|
|
69
|
+
super(`OpenGeni API contract mismatch: client expects ${expected}, API serves ${actual}`);
|
|
70
|
+
this.name = "OpenGeniApiContractMismatchError";
|
|
71
|
+
this.expected = expected;
|
|
72
|
+
this.actual = actual;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
var OpenGeniStreamError = class extends Error {
|
|
76
|
+
constructor(message) {
|
|
77
|
+
super(message);
|
|
78
|
+
this.name = "OpenGeniStreamError";
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
function isAbortError(error) {
|
|
82
|
+
return error instanceof DOMException && error.name === "AbortError" || error instanceof Error && error.name === "AbortError";
|
|
83
|
+
}
|
|
84
|
+
function isRetryableStreamError(error) {
|
|
85
|
+
if (error instanceof OpenGeniApiError) return error.retryable;
|
|
86
|
+
return error instanceof TypeError;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export {
|
|
90
|
+
OpenGeniApiError,
|
|
91
|
+
OpenGeniSessionListCursorError,
|
|
92
|
+
OpenGeniApiContractMismatchError,
|
|
93
|
+
OpenGeniStreamError,
|
|
94
|
+
isAbortError,
|
|
95
|
+
isRetryableStreamError
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=chunk-OINSI33U.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts"],"sourcesContent":["/** Error for a non-2xx OpenGeni API response. */\nexport class OpenGeniApiError extends Error {\n readonly status: number;\n readonly code: string | undefined;\n readonly retryable: boolean;\n readonly correlationId: string | undefined;\n /** True only when an uncontrolled transport failed after a mutation may have been accepted. */\n readonly outcomeUnknown: boolean;\n readonly body: string;\n\n constructor(\n status: number,\n body: string,\n options: {\n code?: string | undefined;\n retryable?: boolean | undefined;\n correlationId?: string | undefined;\n outcomeUnknown?: boolean | undefined;\n displayMessage?: string | undefined;\n mutation?: boolean | undefined;\n } = {},\n ) {\n const decoded = decodeApiErrorBody(body);\n const correlationId = decoded?.requestId ?? boundedCorrelationId(options.correlationId);\n const gatewayFailure = status >= 502 && status <= 504;\n const fromResponse = options.mutation !== undefined;\n const message = decoded?.message ?? (fromResponse ? \"Request failed.\" : body || \"(empty body)\");\n const displayMessage =\n options.displayMessage ??\n (gatewayFailure && fromResponse\n ? \"OpenGeni is temporarily unavailable — retry.\"\n : `OpenGeni API ${status}: ${message}`);\n super(correlationId ? `${displayMessage} Reference: ${correlationId}.` : displayMessage);\n this.name = \"OpenGeniApiError\";\n this.status = status;\n this.code =\n options.code ??\n decoded?.code ??\n (gatewayFailure && fromResponse ? \"upstream_unavailable\" : undefined);\n this.retryable = options.retryable ?? decoded?.retryable ?? retryableApiStatus(status);\n this.correlationId = correlationId;\n this.outcomeUnknown =\n options.outcomeUnknown ?? (gatewayFailure && !!options.mutation && !decoded);\n this.body = !fromResponse || decoded ? body : \"\";\n }\n}\n\nfunction decodeApiErrorBody(body: string): {\n code: string | undefined;\n message: string | undefined;\n requestId: string | undefined;\n retryable: boolean | undefined;\n} | null {\n if (!body) return null;\n try {\n const decoded: unknown = JSON.parse(body);\n if (!decoded || typeof decoded !== \"object\" || Array.isArray(decoded)) return null;\n const record = decoded as Record<string, unknown>;\n const nested =\n record.error && typeof record.error === \"object\" && !Array.isArray(record.error)\n ? (record.error as Record<string, unknown>)\n : record;\n const code = boundedApiField(nested.code);\n const message = boundedApiField(nested.message);\n const requestId = boundedCorrelationId(nested.requestId);\n const retryable = typeof nested.retryable === \"boolean\" ? nested.retryable : undefined;\n if (!code && !message && !requestId && retryable === undefined) return null;\n return {\n code,\n message,\n requestId,\n retryable,\n };\n } catch {\n return null;\n }\n}\n\nfunction boundedApiField(value: unknown): string | undefined {\n if (typeof value !== \"string\") return;\n const bytes = new TextEncoder().encode(value);\n return bytes.byteLength <= 512 ? value : new TextDecoder().decode(bytes.slice(0, 512));\n}\n\nfunction retryableApiStatus(status: number): boolean {\n return status === 408 || status === 409 || status === 425 || status === 429 || status >= 500;\n}\n\nfunction boundedCorrelationId(value: unknown): string | undefined {\n if (typeof value !== \"string\" || value.length > 128 || !/^[\\w.:-]+$/.test(value)) {\n return;\n }\n return value;\n}\n\n/** A short-lived session-list snapshot cursor can no longer be continued. */\nexport class OpenGeniSessionListCursorError extends OpenGeniApiError {}\n\n/** The browser bundle and API disagree about their state-changing wire contract. */\nexport class OpenGeniApiContractMismatchError extends Error {\n readonly expected: string;\n readonly actual: string;\n\n constructor(expected: string, actual: string) {\n super(`OpenGeni API contract mismatch: client expects ${expected}, API serves ${actual}`);\n this.name = \"OpenGeniApiContractMismatchError\";\n this.expected = expected;\n this.actual = actual;\n }\n}\n\n/** Error for an unrecoverable event-stream condition (not a transient drop). */\nexport class OpenGeniStreamError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"OpenGeniStreamError\";\n }\n}\n\nexport function isAbortError(error: unknown): boolean {\n return (\n (error instanceof DOMException && error.name === \"AbortError\") ||\n (error instanceof Error && error.name === \"AbortError\")\n );\n}\n\n/**\n * Transient conditions worth a reconnect: network-level failures (`fetch`\n * rejects with `TypeError`) and HTTP statuses that signal a temporary server\n * or contention condition. Auth/validation failures (401/403/404/...) are\n * permanent and surface to the caller instead.\n */\nexport function isRetryableStreamError(error: unknown): boolean {\n if (error instanceof OpenGeniApiError) return error.retryable;\n return error instanceof TypeError;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,90 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
body;
|
|
10
|
-
constructor(status, body, options = {}) {
|
|
11
|
-
const decoded = decodeApiErrorBody(body);
|
|
12
|
-
const correlationId = decoded?.requestId ?? boundedCorrelationId(options.correlationId);
|
|
13
|
-
const gatewayFailure = status >= 502 && status <= 504;
|
|
14
|
-
const fromResponse = options.mutation !== void 0;
|
|
15
|
-
const message = decoded?.message ?? (fromResponse ? "Request failed." : body || "(empty body)");
|
|
16
|
-
const displayMessage = options.displayMessage ?? (gatewayFailure && fromResponse ? "OpenGeni is temporarily unavailable \u2014 retry." : `OpenGeni API ${status}: ${message}`);
|
|
17
|
-
super(correlationId ? `${displayMessage} Reference: ${correlationId}.` : displayMessage);
|
|
18
|
-
this.name = "OpenGeniApiError";
|
|
19
|
-
this.status = status;
|
|
20
|
-
this.code = options.code ?? decoded?.code ?? (gatewayFailure && fromResponse ? "upstream_unavailable" : void 0);
|
|
21
|
-
this.retryable = options.retryable ?? decoded?.retryable ?? retryableApiStatus(status);
|
|
22
|
-
this.correlationId = correlationId;
|
|
23
|
-
this.outcomeUnknown = options.outcomeUnknown ?? (gatewayFailure && !!options.mutation && !decoded);
|
|
24
|
-
this.body = !fromResponse || decoded ? body : "";
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
function decodeApiErrorBody(body) {
|
|
28
|
-
if (!body) return null;
|
|
29
|
-
try {
|
|
30
|
-
const decoded = JSON.parse(body);
|
|
31
|
-
if (!decoded || typeof decoded !== "object" || Array.isArray(decoded)) return null;
|
|
32
|
-
const record = decoded;
|
|
33
|
-
const nested = record.error && typeof record.error === "object" && !Array.isArray(record.error) ? record.error : record;
|
|
34
|
-
const code = boundedApiField(nested.code);
|
|
35
|
-
const message = boundedApiField(nested.message);
|
|
36
|
-
const requestId = boundedCorrelationId(nested.requestId);
|
|
37
|
-
const retryable = typeof nested.retryable === "boolean" ? nested.retryable : void 0;
|
|
38
|
-
if (!code && !message && !requestId && retryable === void 0) return null;
|
|
39
|
-
return {
|
|
40
|
-
code,
|
|
41
|
-
message,
|
|
42
|
-
requestId,
|
|
43
|
-
retryable
|
|
44
|
-
};
|
|
45
|
-
} catch {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
function boundedApiField(value) {
|
|
50
|
-
if (typeof value !== "string") return;
|
|
51
|
-
const bytes = new TextEncoder().encode(value);
|
|
52
|
-
return bytes.byteLength <= 512 ? value : new TextDecoder().decode(bytes.slice(0, 512));
|
|
53
|
-
}
|
|
54
|
-
function retryableApiStatus(status) {
|
|
55
|
-
return status === 408 || status === 409 || status === 425 || status === 429 || status >= 500;
|
|
56
|
-
}
|
|
57
|
-
function boundedCorrelationId(value) {
|
|
58
|
-
if (typeof value !== "string" || value.length > 128 || !/^[\w.:-]+$/.test(value)) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
return value;
|
|
62
|
-
}
|
|
63
|
-
var OpenGeniSessionListCursorError = class extends OpenGeniApiError {
|
|
64
|
-
};
|
|
65
|
-
var OpenGeniApiContractMismatchError = class extends Error {
|
|
66
|
-
expected;
|
|
67
|
-
actual;
|
|
68
|
-
constructor(expected, actual) {
|
|
69
|
-
super(`OpenGeni API contract mismatch: client expects ${expected}, API serves ${actual}`);
|
|
70
|
-
this.name = "OpenGeniApiContractMismatchError";
|
|
71
|
-
this.expected = expected;
|
|
72
|
-
this.actual = actual;
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
var OpenGeniStreamError = class extends Error {
|
|
76
|
-
constructor(message) {
|
|
77
|
-
super(message);
|
|
78
|
-
this.name = "OpenGeniStreamError";
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
function isAbortError(error) {
|
|
82
|
-
return error instanceof DOMException && error.name === "AbortError" || error instanceof Error && error.name === "AbortError";
|
|
83
|
-
}
|
|
84
|
-
function isRetryableStreamError(error) {
|
|
85
|
-
if (error instanceof OpenGeniApiError) return error.retryable;
|
|
86
|
-
return error instanceof TypeError;
|
|
87
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
OpenGeniApiContractMismatchError,
|
|
3
|
+
OpenGeniApiError,
|
|
4
|
+
OpenGeniSessionListCursorError,
|
|
5
|
+
OpenGeniStreamError,
|
|
6
|
+
isAbortError,
|
|
7
|
+
isRetryableStreamError
|
|
8
|
+
} from "./chunk-OINSI33U.js";
|
|
88
9
|
|
|
89
10
|
// src/sse.ts
|
|
90
11
|
async function* parseSseStream(stream) {
|
|
@@ -342,11 +263,14 @@ async function sleep2(delayMs, signal) {
|
|
|
342
263
|
}
|
|
343
264
|
|
|
344
265
|
// src/types.ts
|
|
266
|
+
var DEFAULT_FILE_RESOURCE_MOUNT_ROOT = ".opengeni/files";
|
|
345
267
|
var SESSION_EVENT_TYPES = [
|
|
346
268
|
"session.created",
|
|
347
269
|
// Defensive bounded projection for malformed/legacy oversized envelopes.
|
|
348
270
|
"session.event.envelope_omitted",
|
|
349
271
|
"session.status.changed",
|
|
272
|
+
"session.realtime.started",
|
|
273
|
+
"session.realtime.ended",
|
|
350
274
|
"session.requiresAction",
|
|
351
275
|
"session.humanInput.requested",
|
|
352
276
|
"session.context.compaction.requested",
|
|
@@ -714,6 +638,68 @@ var OpenGeniClient = class {
|
|
|
714
638
|
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/lineage`
|
|
715
639
|
);
|
|
716
640
|
}
|
|
641
|
+
/** Negotiate one server-mediated connected-Codex GPT-Live V3 WebRTC call. */
|
|
642
|
+
async negotiateCodexRealtimeWebrtc(workspaceId, sessionId, request, options = {}) {
|
|
643
|
+
return await this.requestJson(
|
|
644
|
+
"POST",
|
|
645
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/realtime/webrtc`,
|
|
646
|
+
request,
|
|
647
|
+
{},
|
|
648
|
+
{ signal: options.signal }
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
/** Mint a short-lived browser token for one AI Gateway realtime connection. */
|
|
652
|
+
async negotiateGatewayRealtime(workspaceId, sessionId, request, options = {}) {
|
|
653
|
+
return await this.requestJson(
|
|
654
|
+
"POST",
|
|
655
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/realtime/gateway`,
|
|
656
|
+
request,
|
|
657
|
+
{},
|
|
658
|
+
{ signal: options.signal }
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
/** Promote a negotiated connection only after its browser data channel is ready. */
|
|
662
|
+
async activateCodexRealtimeConnection(workspaceId, sessionId, realtimeId, connectionId, request, options = {}) {
|
|
663
|
+
return await this.requestJson(
|
|
664
|
+
"POST",
|
|
665
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/realtime/${realtimeId}/connections/${connectionId}/activate`,
|
|
666
|
+
request,
|
|
667
|
+
{},
|
|
668
|
+
{ signal: options.signal }
|
|
669
|
+
);
|
|
670
|
+
}
|
|
671
|
+
/** Atomically enter realtime mode for this ordinary session. */
|
|
672
|
+
async beginSessionRealtime(workspaceId, sessionId, request) {
|
|
673
|
+
return await this.requestJson(
|
|
674
|
+
"POST",
|
|
675
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/realtime`,
|
|
676
|
+
request
|
|
677
|
+
);
|
|
678
|
+
}
|
|
679
|
+
/** Renew the exact authenticated browser owner's realtime lease. */
|
|
680
|
+
async heartbeatSessionRealtime(workspaceId, sessionId, realtimeId, request) {
|
|
681
|
+
return await this.requestJson(
|
|
682
|
+
"PATCH",
|
|
683
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/realtime/${realtimeId}/heartbeat`,
|
|
684
|
+
request
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
/** Persist finalized V3 events, acknowledge delivery, and replay pending outbound context. */
|
|
688
|
+
async syncSessionRealtimeLedger(workspaceId, sessionId, realtimeId, request) {
|
|
689
|
+
return await this.requestJson(
|
|
690
|
+
"POST",
|
|
691
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/realtime/${realtimeId}/sync`,
|
|
692
|
+
request
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
/** End realtime mode and restore ordinary text workflow admission. */
|
|
696
|
+
async endSessionRealtime(workspaceId, sessionId, realtimeId, request) {
|
|
697
|
+
return await this.requestJson(
|
|
698
|
+
"DELETE",
|
|
699
|
+
`/v1/workspaces/${workspaceId}/sessions/${sessionId}/realtime/${realtimeId}`,
|
|
700
|
+
request
|
|
701
|
+
);
|
|
702
|
+
}
|
|
717
703
|
async listTurns(workspaceId, sessionId, options = {}) {
|
|
718
704
|
return await this.requestJson(
|
|
719
705
|
"GET",
|
|
@@ -787,7 +773,10 @@ var OpenGeniClient = class {
|
|
|
787
773
|
return await this.requestJson(
|
|
788
774
|
"POST",
|
|
789
775
|
`/v1/workspaces/${workspaceId}/enrollments/device/approve`,
|
|
790
|
-
{
|
|
776
|
+
{
|
|
777
|
+
userCode: request.userCode,
|
|
778
|
+
allowScreenControl: request.allowScreenControl ?? false
|
|
779
|
+
}
|
|
791
780
|
);
|
|
792
781
|
}
|
|
793
782
|
/** Deny a pending device-enrollment flow (the explicit "no" at the approve page). */
|
|
@@ -887,7 +876,10 @@ var OpenGeniClient = class {
|
|
|
887
876
|
);
|
|
888
877
|
assertApiContractResponse(response);
|
|
889
878
|
if (!response.ok) {
|
|
890
|
-
throw await apiErrorFromResponse(response, {
|
|
879
|
+
throw await apiErrorFromResponse(response, {
|
|
880
|
+
method: "GET",
|
|
881
|
+
correlationId
|
|
882
|
+
});
|
|
891
883
|
}
|
|
892
884
|
await assertJsonResponse(response, { method: "GET", correlationId });
|
|
893
885
|
const body = await response.json();
|
|
@@ -933,7 +925,9 @@ var OpenGeniClient = class {
|
|
|
933
925
|
* never creates a model turn. `latest: "receipt"` aliases `tool_receipt`;
|
|
934
926
|
* turn generation remains scoped retry metadata.
|
|
935
927
|
*/
|
|
936
|
-
async getLatestEventResult(workspaceId, sessionId, options = {
|
|
928
|
+
async getLatestEventResult(workspaceId, sessionId, options = {
|
|
929
|
+
latest: "terminal"
|
|
930
|
+
}) {
|
|
937
931
|
return await this.listEventPage(workspaceId, sessionId, {
|
|
938
932
|
...options,
|
|
939
933
|
resultMode: "compact"
|
|
@@ -1025,7 +1019,10 @@ var OpenGeniClient = class {
|
|
|
1025
1019
|
});
|
|
1026
1020
|
assertApiContractResponse(response);
|
|
1027
1021
|
if (!response.ok) {
|
|
1028
|
-
throw await apiErrorFromResponse(response, {
|
|
1022
|
+
throw await apiErrorFromResponse(response, {
|
|
1023
|
+
method: "GET",
|
|
1024
|
+
correlationId
|
|
1025
|
+
});
|
|
1029
1026
|
}
|
|
1030
1027
|
if (!response.body) {
|
|
1031
1028
|
throw new OpenGeniApiError(response.status, "SSE response did not include a readable body");
|
|
@@ -1095,6 +1092,19 @@ var OpenGeniClient = class {
|
|
|
1095
1092
|
...options.expectedControlEtag ? { expectedControlEtag: options.expectedControlEtag } : {}
|
|
1096
1093
|
});
|
|
1097
1094
|
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Terminally cancel a session subtree. Unlike pause, cancellation drains
|
|
1097
|
+
* queued work and permanently fences new prompts for the session and every
|
|
1098
|
+
* descendant.
|
|
1099
|
+
*/
|
|
1100
|
+
async cancelSession(workspaceId, sessionId, options = {}) {
|
|
1101
|
+
return await this.controlSession(workspaceId, sessionId, {
|
|
1102
|
+
action: "cancel",
|
|
1103
|
+
clientEventId: options.clientEventId ?? crypto.randomUUID(),
|
|
1104
|
+
...options.reason ? { reason: options.reason } : {},
|
|
1105
|
+
...options.expectedControlEtag ? { expectedControlEtag: options.expectedControlEtag } : {}
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1098
1108
|
async setWorkspaceInferenceState(workspaceId, request) {
|
|
1099
1109
|
return await this.requestJson(
|
|
1100
1110
|
"POST",
|
|
@@ -1120,7 +1130,10 @@ var OpenGeniClient = class {
|
|
|
1120
1130
|
);
|
|
1121
1131
|
assertApiContractResponse(response);
|
|
1122
1132
|
if (!response.ok) {
|
|
1123
|
-
throw await apiErrorFromResponse(response, {
|
|
1133
|
+
throw await apiErrorFromResponse(response, {
|
|
1134
|
+
method: "GET",
|
|
1135
|
+
correlationId
|
|
1136
|
+
});
|
|
1124
1137
|
}
|
|
1125
1138
|
await assertJsonResponse(response, { method: "GET", correlationId });
|
|
1126
1139
|
const events = await response.json();
|
|
@@ -1154,13 +1167,19 @@ var OpenGeniClient = class {
|
|
|
1154
1167
|
}),
|
|
1155
1168
|
{
|
|
1156
1169
|
method: "GET",
|
|
1157
|
-
headers: {
|
|
1170
|
+
headers: {
|
|
1171
|
+
...this.headers(correlationId),
|
|
1172
|
+
Accept: "text/event-stream"
|
|
1173
|
+
},
|
|
1158
1174
|
...options.signal ? { signal: options.signal } : {}
|
|
1159
1175
|
}
|
|
1160
1176
|
);
|
|
1161
1177
|
assertApiContractResponse(response);
|
|
1162
1178
|
if (!response.ok) {
|
|
1163
|
-
throw await apiErrorFromResponse(response, {
|
|
1179
|
+
throw await apiErrorFromResponse(response, {
|
|
1180
|
+
method: "GET",
|
|
1181
|
+
correlationId
|
|
1182
|
+
});
|
|
1164
1183
|
}
|
|
1165
1184
|
if (!response.body) {
|
|
1166
1185
|
throw new OpenGeniApiError(response.status, "SSE response did not include a readable body");
|
|
@@ -1478,6 +1497,13 @@ var OpenGeniClient = class {
|
|
|
1478
1497
|
`/v1/workspaces/${workspaceId}/model-catalog`
|
|
1479
1498
|
);
|
|
1480
1499
|
}
|
|
1500
|
+
/** Authenticated realtime voice models and credential readiness. */
|
|
1501
|
+
async getWorkspaceRealtimeModelCatalog(workspaceId) {
|
|
1502
|
+
return await this.requestJson(
|
|
1503
|
+
"GET",
|
|
1504
|
+
`/v1/workspaces/${workspaceId}/realtime-model-catalog`
|
|
1505
|
+
);
|
|
1506
|
+
}
|
|
1481
1507
|
/** The caller's access context: subject, account + workspace grants, defaults. */
|
|
1482
1508
|
async getAccessContext() {
|
|
1483
1509
|
return await this.requestJson("GET", "/v1/access/me");
|
|
@@ -1492,10 +1518,13 @@ var OpenGeniClient = class {
|
|
|
1492
1518
|
return await this.requestJson("GET", `/v1/workspaces/${workspaceId}`);
|
|
1493
1519
|
}
|
|
1494
1520
|
/** Read-time, secret-safe inventory of policy heads and visible workspace knowledge. */
|
|
1495
|
-
async getWorkspaceState(workspaceId) {
|
|
1521
|
+
async getWorkspaceState(workspaceId, options = {}) {
|
|
1522
|
+
const params = new URLSearchParams();
|
|
1523
|
+
if (options.attemptId) params.set("attemptId", options.attemptId);
|
|
1524
|
+
const query = params.size > 0 ? `?${params.toString()}` : "";
|
|
1496
1525
|
return await this.requestJson(
|
|
1497
1526
|
"GET",
|
|
1498
|
-
`/v1/workspaces/${workspaceId}/workspace-state`
|
|
1527
|
+
`/v1/workspaces/${workspaceId}/workspace-state${query}`
|
|
1499
1528
|
);
|
|
1500
1529
|
}
|
|
1501
1530
|
async updateWorkspace(workspaceId, request) {
|
|
@@ -1735,7 +1764,9 @@ var OpenGeniClient = class {
|
|
|
1735
1764
|
"GET",
|
|
1736
1765
|
`/v1/workspaces/${workspaceId}/scheduled-tasks/${taskId}/runs`,
|
|
1737
1766
|
void 0,
|
|
1738
|
-
{
|
|
1767
|
+
{
|
|
1768
|
+
...options.limit !== void 0 ? { limit: String(options.limit) } : {}
|
|
1769
|
+
}
|
|
1739
1770
|
);
|
|
1740
1771
|
}
|
|
1741
1772
|
// --- VariableSets --------------------------------------------------------------
|
|
@@ -1996,7 +2027,10 @@ var OpenGeniClient = class {
|
|
|
1996
2027
|
throw error;
|
|
1997
2028
|
}
|
|
1998
2029
|
if (!response.ok) {
|
|
1999
|
-
throw await apiErrorFromResponse(response, {
|
|
2030
|
+
throw await apiErrorFromResponse(response, {
|
|
2031
|
+
method: "GET",
|
|
2032
|
+
correlationId
|
|
2033
|
+
});
|
|
2000
2034
|
}
|
|
2001
2035
|
if (response.status !== 200 && response.status !== 206) {
|
|
2002
2036
|
await cancelResponseBody(response, "unexpected retained artifact response status");
|
|
@@ -2282,6 +2316,14 @@ var OpenGeniClient = class {
|
|
|
2282
2316
|
request
|
|
2283
2317
|
);
|
|
2284
2318
|
}
|
|
2319
|
+
async listOpenGeniSlackReactionChannels(workspaceId, connectionId, cursor) {
|
|
2320
|
+
const query = new URLSearchParams({ connectionId });
|
|
2321
|
+
if (cursor) query.set("cursor", cursor);
|
|
2322
|
+
return await this.requestJson(
|
|
2323
|
+
"GET",
|
|
2324
|
+
`/v1/workspaces/${workspaceId}/integrations/slack/reaction-channels?${query}`
|
|
2325
|
+
);
|
|
2326
|
+
}
|
|
2285
2327
|
async updateConnection(workspaceId, connectionId, request) {
|
|
2286
2328
|
const response = await this.requestJson(
|
|
2287
2329
|
"PATCH",
|
|
@@ -2297,6 +2339,22 @@ var OpenGeniClient = class {
|
|
|
2297
2339
|
);
|
|
2298
2340
|
return response.connection;
|
|
2299
2341
|
}
|
|
2342
|
+
async disconnectGoogleDriveConnection(workspaceId, connectionId, request) {
|
|
2343
|
+
const response = await this.requestJson(
|
|
2344
|
+
"DELETE",
|
|
2345
|
+
`/v1/workspaces/${workspaceId}/connections/${connectionId}`,
|
|
2346
|
+
request
|
|
2347
|
+
);
|
|
2348
|
+
return response.connection;
|
|
2349
|
+
}
|
|
2350
|
+
async transitionGoogleDriveLifecycle(workspaceId, connectionId, request) {
|
|
2351
|
+
const response = await this.requestJson(
|
|
2352
|
+
"PATCH",
|
|
2353
|
+
`/v1/workspaces/${workspaceId}/connections/google-drive/${connectionId}/lifecycle`,
|
|
2354
|
+
request
|
|
2355
|
+
);
|
|
2356
|
+
return response.connection;
|
|
2357
|
+
}
|
|
2300
2358
|
/** Start an OAuth connection flow; redirect the user to the returned `authorizationUrl`. */
|
|
2301
2359
|
async startConnectionOAuth(workspaceId, request, options = {}) {
|
|
2302
2360
|
return await this.requestJson(
|
|
@@ -2536,10 +2594,7 @@ var OpenGeniClient = class {
|
|
|
2536
2594
|
}
|
|
2537
2595
|
/** Disconnect ONE Codex account by id (re-picks active when the removed one was active). */
|
|
2538
2596
|
async disconnectCodexAccount(workspaceId, accountId) {
|
|
2539
|
-
return await this.requestJson(
|
|
2540
|
-
"DELETE",
|
|
2541
|
-
`/v1/workspaces/${workspaceId}/codex/accounts/${accountId}`
|
|
2542
|
-
);
|
|
2597
|
+
return await this.requestJson("DELETE", `/v1/workspaces/${workspaceId}/codex/accounts/${accountId}`);
|
|
2543
2598
|
}
|
|
2544
2599
|
/** Rename a Codex account (label only in P1). */
|
|
2545
2600
|
async renameCodexAccount(workspaceId, accountId, label) {
|
|
@@ -2976,14 +3031,10 @@ function isNullableBoundedNumber(value, maximum) {
|
|
|
2976
3031
|
}
|
|
2977
3032
|
|
|
2978
3033
|
export {
|
|
2979
|
-
OpenGeniApiError,
|
|
2980
|
-
OpenGeniSessionListCursorError,
|
|
2981
|
-
OpenGeniApiContractMismatchError,
|
|
2982
|
-
OpenGeniStreamError,
|
|
2983
|
-
isRetryableStreamError,
|
|
2984
3034
|
parseSseStream,
|
|
2985
3035
|
streamSessionEvents,
|
|
2986
3036
|
streamWorkspaceControlEvents,
|
|
3037
|
+
DEFAULT_FILE_RESOURCE_MOUNT_ROOT,
|
|
2987
3038
|
SESSION_EVENT_TYPES,
|
|
2988
3039
|
KNOWN_PERMISSIONS,
|
|
2989
3040
|
OPENGENI_API_CONTRACT_REVISION,
|
|
@@ -2999,4 +3050,4 @@ export {
|
|
|
2999
3050
|
authorizeTranscriptionAdapter,
|
|
3000
3051
|
createTranscriptionSessionRequest
|
|
3001
3052
|
};
|
|
3002
|
-
//# sourceMappingURL=chunk-
|
|
3053
|
+
//# sourceMappingURL=chunk-SSQPCFEN.js.map
|