@opengeni/sdk 0.29.0 → 0.32.1
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 +12 -4
- package/dist/client.d.ts +643 -0
- package/dist/desktop.d.ts +71 -0
- package/dist/errors.d.ts +39 -0
- package/dist/index.d.ts +25 -4211
- package/dist/index.js +195 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp-output.d.ts +15 -0
- package/dist/preference-registry.d.ts +169 -0
- package/dist/proxy.d.ts +64 -0
- package/dist/sse.d.ts +14 -0
- package/dist/stream.d.ts +48 -0
- package/dist/terminal.d.ts +49 -0
- package/dist/transcription.d.ts +189 -0
- package/dist/types.d.ts +3221 -0
- package/dist/workspace-control-stream.d.ts +12 -0
- package/dist/workspace-instruction-policies.d.ts +98 -0
- package/dist/workspace-state.d.ts +122 -0
- package/package.json +3 -3
- package/src/client.ts +279 -2
- package/src/index.ts +65 -0
- package/src/preference-registry.ts +210 -0
- package/src/transcription.ts +16 -0
- package/src/types.ts +254 -1
- package/src/workspace-state.ts +134 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A transport-tolerant MCP tool result.
|
|
3
|
+
*
|
|
4
|
+
* `value` is the canonical machine-readable payload after recognized MCP/JSON
|
|
5
|
+
* envelopes are removed. `text` is the best presentation string without
|
|
6
|
+
* discarding structured data. `raw` always retains the original evidence.
|
|
7
|
+
*/
|
|
8
|
+
export type NormalizedMcpOutput = Readonly<{
|
|
9
|
+
raw: unknown;
|
|
10
|
+
value: unknown;
|
|
11
|
+
text: string;
|
|
12
|
+
isError: boolean;
|
|
13
|
+
}>;
|
|
14
|
+
/** Normalize common direct, JSON, and standard MCP result envelopes without throwing. */
|
|
15
|
+
export declare function normalizeMcpOutput(output: unknown): NormalizedMcpOutput;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
export type PreferenceRegistryScope = "organization" | "workspace" | "user";
|
|
2
|
+
export type PreferenceRegistryStatus = "proposed" | "active" | "inactive" | "rejected" | "superseded" | "expired";
|
|
3
|
+
export type PreferenceRegistryProvenanceSource = "human" | "onboarding" | "knowledge_proposal" | "imported_document" | "slack" | "meeting_transcript" | "call_transcript";
|
|
4
|
+
export type PreferenceRegistryTrust = "untrusted_proposal" | "personal" | "workspace_managed" | "organization_managed";
|
|
5
|
+
export type PreferenceRegistryConflictStrategy = "override" | "merge" | "reject" | "inform";
|
|
6
|
+
export declare function normalizePreferenceRegistryStableKey(value: string): string;
|
|
7
|
+
export type PreferenceRegistryScopeTarget = {
|
|
8
|
+
scope: PreferenceRegistryScope;
|
|
9
|
+
workspaceId: string | null;
|
|
10
|
+
subjectId: string | null;
|
|
11
|
+
};
|
|
12
|
+
export type PreferenceRegistryPrecedence = {
|
|
13
|
+
tier: PreferenceRegistryScope;
|
|
14
|
+
rank: number;
|
|
15
|
+
conflictStrategy: PreferenceRegistryConflictStrategy;
|
|
16
|
+
conflictsWith: string[];
|
|
17
|
+
};
|
|
18
|
+
export type PreferenceRegistryRevisionSummary = {
|
|
19
|
+
id: string;
|
|
20
|
+
preferenceId: string;
|
|
21
|
+
revision: number;
|
|
22
|
+
contentHash: string;
|
|
23
|
+
title: string;
|
|
24
|
+
description: string;
|
|
25
|
+
precedence: PreferenceRegistryPrecedence;
|
|
26
|
+
provenance: {
|
|
27
|
+
source: PreferenceRegistryProvenanceSource;
|
|
28
|
+
sourceId: string | null;
|
|
29
|
+
trust: PreferenceRegistryTrust;
|
|
30
|
+
};
|
|
31
|
+
expiresAt: string | null;
|
|
32
|
+
correctsRevisionId: string | null;
|
|
33
|
+
createdBySubjectId: string;
|
|
34
|
+
createdAt: string;
|
|
35
|
+
};
|
|
36
|
+
export type PreferenceRegistryDescriptorProvenance = {
|
|
37
|
+
source: PreferenceRegistryProvenanceSource;
|
|
38
|
+
sourceIdHash: string | null;
|
|
39
|
+
trust: PreferenceRegistryTrust;
|
|
40
|
+
};
|
|
41
|
+
export type PreferenceRegistryRecord = {
|
|
42
|
+
id: string;
|
|
43
|
+
accountId: string;
|
|
44
|
+
stableKey: string;
|
|
45
|
+
target: PreferenceRegistryScopeTarget;
|
|
46
|
+
status: PreferenceRegistryStatus;
|
|
47
|
+
scopeVersion: number;
|
|
48
|
+
activationVersion: number;
|
|
49
|
+
activeRevision: PreferenceRegistryRevisionSummary | null;
|
|
50
|
+
supersededByPreferenceId: string | null;
|
|
51
|
+
createdBySubjectId: string;
|
|
52
|
+
createdAt: string;
|
|
53
|
+
updatedAt: string;
|
|
54
|
+
};
|
|
55
|
+
export type PreferenceRegistryEvent = {
|
|
56
|
+
id: string;
|
|
57
|
+
accountId: string;
|
|
58
|
+
preferenceId: string;
|
|
59
|
+
type: "proposal_created" | "activated" | "corrected" | "rejected" | "deactivated" | "superseded" | "scope_changed";
|
|
60
|
+
version: number;
|
|
61
|
+
oldRevisionId: string | null;
|
|
62
|
+
newRevisionId: string | null;
|
|
63
|
+
oldTarget: PreferenceRegistryScopeTarget | null;
|
|
64
|
+
newTarget: PreferenceRegistryScopeTarget | null;
|
|
65
|
+
relatedPreferenceId: string | null;
|
|
66
|
+
actorSubjectId: string;
|
|
67
|
+
reason: string;
|
|
68
|
+
createdAt: string;
|
|
69
|
+
};
|
|
70
|
+
export type PreferenceRegistryDescriptor = {
|
|
71
|
+
id: string;
|
|
72
|
+
stableKey: string;
|
|
73
|
+
title: string;
|
|
74
|
+
description: string;
|
|
75
|
+
scope: PreferenceRegistryScope;
|
|
76
|
+
activeVersion: number;
|
|
77
|
+
revisionId: string;
|
|
78
|
+
contentHash: string;
|
|
79
|
+
precedence: PreferenceRegistryPrecedence;
|
|
80
|
+
provenance: PreferenceRegistryDescriptorProvenance;
|
|
81
|
+
expiresAt: string | null;
|
|
82
|
+
retrievalHandle: string;
|
|
83
|
+
};
|
|
84
|
+
export type PreferenceRegistrySnapshot = {
|
|
85
|
+
id: string;
|
|
86
|
+
workspaceId: string;
|
|
87
|
+
sessionId: string;
|
|
88
|
+
turnId: string;
|
|
89
|
+
attemptId: string;
|
|
90
|
+
executionGeneration: number;
|
|
91
|
+
initiatingHumanSubjectId: string;
|
|
92
|
+
descriptorHash: string;
|
|
93
|
+
descriptors: PreferenceRegistryDescriptor[];
|
|
94
|
+
truncated: boolean;
|
|
95
|
+
createdAt: string;
|
|
96
|
+
};
|
|
97
|
+
export type PreferenceRegistryFullContent = {
|
|
98
|
+
descriptor: PreferenceRegistryDescriptor;
|
|
99
|
+
content: string;
|
|
100
|
+
};
|
|
101
|
+
export type CreatePreferenceRegistryProposalRequest = {
|
|
102
|
+
stableKey: string;
|
|
103
|
+
scope: PreferenceRegistryScope;
|
|
104
|
+
title: string;
|
|
105
|
+
description: string;
|
|
106
|
+
content: string;
|
|
107
|
+
precedenceRank?: number;
|
|
108
|
+
conflictStrategy?: PreferenceRegistryConflictStrategy;
|
|
109
|
+
conflictsWith?: string[];
|
|
110
|
+
expiresAt?: string | null;
|
|
111
|
+
provenanceSource?: PreferenceRegistryProvenanceSource;
|
|
112
|
+
provenanceSourceId?: string | null;
|
|
113
|
+
};
|
|
114
|
+
export type ActivatePreferenceRegistryRevisionRequest = {
|
|
115
|
+
revisionId: string;
|
|
116
|
+
expectedCurrentRevisionId: string | null;
|
|
117
|
+
expectedScopeVersion: number;
|
|
118
|
+
reason: string;
|
|
119
|
+
};
|
|
120
|
+
export type CorrectPreferenceRegistryRequest = {
|
|
121
|
+
expectedCurrentRevisionId: string;
|
|
122
|
+
expectedScopeVersion: number;
|
|
123
|
+
title: string;
|
|
124
|
+
description: string;
|
|
125
|
+
content: string;
|
|
126
|
+
precedenceRank?: number;
|
|
127
|
+
conflictStrategy?: PreferenceRegistryConflictStrategy;
|
|
128
|
+
conflictsWith?: string[];
|
|
129
|
+
expiresAt?: string | null;
|
|
130
|
+
reason: string;
|
|
131
|
+
};
|
|
132
|
+
export type DeactivatePreferenceRegistryRequest = {
|
|
133
|
+
expectedCurrentRevisionId: string;
|
|
134
|
+
expectedScopeVersion: number;
|
|
135
|
+
reason: string;
|
|
136
|
+
};
|
|
137
|
+
export type ChangePreferenceRegistryScopeRequest = {
|
|
138
|
+
scope: PreferenceRegistryScope;
|
|
139
|
+
expectedScopeVersion: number;
|
|
140
|
+
reason: string;
|
|
141
|
+
};
|
|
142
|
+
export type SupersedePreferenceRegistryRequest = {
|
|
143
|
+
replacementPreferenceId: string;
|
|
144
|
+
expectedCurrentRevisionId: string;
|
|
145
|
+
expectedScopeVersion: number;
|
|
146
|
+
reason: string;
|
|
147
|
+
};
|
|
148
|
+
export type RejectPreferenceRegistryProposalRequest = {
|
|
149
|
+
revisionId: string;
|
|
150
|
+
expectedScopeVersion: number;
|
|
151
|
+
reason: string;
|
|
152
|
+
};
|
|
153
|
+
export type PreferenceRegistryListOptions = {
|
|
154
|
+
scope?: PreferenceRegistryScope;
|
|
155
|
+
status?: PreferenceRegistryStatus;
|
|
156
|
+
limit?: number;
|
|
157
|
+
};
|
|
158
|
+
export type PreferenceRegistryListResponse = {
|
|
159
|
+
preferences: PreferenceRegistryRecord[];
|
|
160
|
+
};
|
|
161
|
+
export type PreferenceRegistryDetailResponse = {
|
|
162
|
+
preference: PreferenceRegistryRecord;
|
|
163
|
+
revisions: PreferenceRegistryRevisionSummary[];
|
|
164
|
+
events: PreferenceRegistryEvent[];
|
|
165
|
+
};
|
|
166
|
+
export type PreferenceRegistryMutationResponse = {
|
|
167
|
+
preference: PreferenceRegistryRecord;
|
|
168
|
+
event: PreferenceRegistryEvent;
|
|
169
|
+
};
|
package/dist/proxy.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { OpenGeniClient } from "./client";
|
|
2
|
+
import type { StreamSessionEventsOptions } from "./stream";
|
|
3
|
+
import type { SessionEvent } from "./types";
|
|
4
|
+
/**
|
|
5
|
+
* Proxy-through-your-own-API helpers.
|
|
6
|
+
*
|
|
7
|
+
* The intended pattern: a customer's server consumes the OpenGeni event
|
|
8
|
+
* stream with its own API key (`client.streamEvents(...)`) and re-emits it to
|
|
9
|
+
* its browser clients over its own authenticated endpoint — the OpenGeni key
|
|
10
|
+
* never reaches the browser. The re-emitted wire format is identical to
|
|
11
|
+
* OpenGeni's own SSE stream (`id: <sequence>`, `event: <type>`,
|
|
12
|
+
* `data: <event JSON>`), so the browser side can consume it with this same
|
|
13
|
+
* SDK's streaming core (or a plain `EventSource`), including resume via
|
|
14
|
+
* `?after=` / `Last-Event-ID`.
|
|
15
|
+
*/
|
|
16
|
+
/** Format one event exactly as OpenGeni's API emits it over SSE. */
|
|
17
|
+
export declare function formatSseEvent(event: SessionEvent): string;
|
|
18
|
+
export type SseReStreamOptions = {
|
|
19
|
+
/**
|
|
20
|
+
* Emit `: ping` comment lines at this interval, keeping intermediaries from
|
|
21
|
+
* idling the connection out. Disabled when omitted.
|
|
22
|
+
*/
|
|
23
|
+
heartbeatMs?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Called when the downstream consumer cancels (e.g. the browser
|
|
26
|
+
* disconnected). Use it to abort the upstream OpenGeni stream — an async
|
|
27
|
+
* iterator that is mid-`await` cannot be interrupted by `return()` alone.
|
|
28
|
+
*/
|
|
29
|
+
onCancel?: () => void;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Re-emit a stream of session events as an SSE byte stream. Pull-based, so
|
|
33
|
+
* upstream consumption follows downstream demand; cancelling the returned
|
|
34
|
+
* stream fires `onCancel` and ends the upstream iterator.
|
|
35
|
+
*/
|
|
36
|
+
export declare function sessionEventsToSseStream(events: AsyncIterable<SessionEvent>, options?: SseReStreamOptions): ReadableStream<Uint8Array>;
|
|
37
|
+
/** Wrap an event stream in a ready-to-return SSE `Response`. */
|
|
38
|
+
export declare function sessionEventsToSseResponse(events: AsyncIterable<SessionEvent>, options?: SseReStreamOptions): Response;
|
|
39
|
+
/**
|
|
40
|
+
* Read the resume cursor a reconnecting SSE client sent: the `after` query
|
|
41
|
+
* parameter, or the standard `Last-Event-ID` header (the re-emitted stream
|
|
42
|
+
* sets `id:` to the sequence). Returns 0 (full replay) when absent.
|
|
43
|
+
*/
|
|
44
|
+
export declare function resumeSequenceFromRequest(request: Request): number;
|
|
45
|
+
export type ProxySessionEventStreamOptions = Omit<StreamSessionEventsOptions, "after"> & {
|
|
46
|
+
/**
|
|
47
|
+
* Resume cursor. Pass a number, or the incoming browser `Request` to
|
|
48
|
+
* honor its `?after=` / `Last-Event-ID` automatically.
|
|
49
|
+
*/
|
|
50
|
+
after?: number | Request;
|
|
51
|
+
/** See {@link SseReStreamOptions.heartbeatMs}. */
|
|
52
|
+
heartbeatMs?: number;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* One-call proxy: consume the OpenGeni stream server-side and return an SSE
|
|
56
|
+
* `Response` for your own browser clients. Works anywhere WHATWG `Response`
|
|
57
|
+
* is the handler return type (Hono, Next.js route handlers, Bun.serve,
|
|
58
|
+
* Cloudflare Workers, ...).
|
|
59
|
+
*
|
|
60
|
+
* The upstream OpenGeni connection is torn down when the downstream client
|
|
61
|
+
* disconnects, and also when `options.signal` (e.g. the incoming request's
|
|
62
|
+
* signal) aborts.
|
|
63
|
+
*/
|
|
64
|
+
export declare function proxySessionEventStream(client: OpenGeniClient, workspaceId: string, sessionId: string, options?: ProxySessionEventStreamOptions): Response;
|
package/dist/sse.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal incremental Server-Sent Events parser over a byte stream.
|
|
3
|
+
*
|
|
4
|
+
* Implements the parts of the SSE wire format OpenGeni uses: `id`, `event`,
|
|
5
|
+
* and `data` fields, multi-line data, comment lines, and both LF and CRLF
|
|
6
|
+
* line endings. Messages without any `data` (comments, id-only blocks) are
|
|
7
|
+
* not emitted.
|
|
8
|
+
*/
|
|
9
|
+
export type SseMessage = {
|
|
10
|
+
id?: string;
|
|
11
|
+
event?: string;
|
|
12
|
+
data: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function parseSseStream(stream: ReadableStream<Uint8Array>): AsyncGenerator<SseMessage, void, void>;
|
package/dist/stream.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { SessionEvent } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Transport boundary for the streaming core. The client implements it with
|
|
4
|
+
* `fetch`; unit tests script it directly.
|
|
5
|
+
*/
|
|
6
|
+
export type SessionEventStreamTransport = {
|
|
7
|
+
/** Open the SSE stream, replaying durable events after `after` first. */
|
|
8
|
+
openStream: (after: number, signal: AbortSignal | undefined) => Promise<ReadableStream<Uint8Array>>;
|
|
9
|
+
/** Replay durable events by sequence (`GET .../events?after=&limit=`). */
|
|
10
|
+
listEvents: (after: number, limit: number) => Promise<SessionEvent[]>;
|
|
11
|
+
};
|
|
12
|
+
export type StreamConnectionState = "connecting" | "live" | "reconnecting";
|
|
13
|
+
export type StreamSessionEventsOptions = {
|
|
14
|
+
/** Resume after this sequence number (exclusive). Defaults to 0 (full replay). */
|
|
15
|
+
after?: number;
|
|
16
|
+
/** Aborting ends the stream gracefully (the generator returns). */
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
/** Reconnect on transient drops. Defaults to true. */
|
|
19
|
+
reconnect?: boolean;
|
|
20
|
+
/** Initial reconnect backoff. Defaults to 500ms. */
|
|
21
|
+
reconnectDelayMs?: number;
|
|
22
|
+
/** Backoff ceiling. Defaults to 10s. */
|
|
23
|
+
maxReconnectDelayMs?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Give up after this many consecutive failed reconnect attempts (i.e. N
|
|
26
|
+
* reconnects = N+1 total open-stream calls). Defaults to unlimited.
|
|
27
|
+
*/
|
|
28
|
+
maxReconnectAttempts?: number;
|
|
29
|
+
/** Await authoritative client reconciliation before exposing `live`. */
|
|
30
|
+
beforeLive?: (() => void | Promise<void>) | undefined;
|
|
31
|
+
onStateChange?: (state: StreamConnectionState) => void;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Stream a session's events with exactly-once, in-order delivery.
|
|
35
|
+
*
|
|
36
|
+
* Guarantees, anchored on the per-session contiguous `sequence`:
|
|
37
|
+
* - **No duplicates**: events at or below the cursor are dropped, so server
|
|
38
|
+
* replay overlap and reconnect overlap never re-yield.
|
|
39
|
+
* - **No gaps**: each reconnect resumes from the last seen sequence, and a
|
|
40
|
+
* gap observed inside one connection is backfilled from the durable replay
|
|
41
|
+
* endpoint before the newer event is yielded (events are durable before
|
|
42
|
+
* they are published live, so the backfill always finds them).
|
|
43
|
+
* - **Ordered**: sequences are yielded strictly ascending.
|
|
44
|
+
*
|
|
45
|
+
* The generator ends when `signal` aborts, when the server closes and
|
|
46
|
+
* `reconnect` is false, or with an error for non-retryable failures.
|
|
47
|
+
*/
|
|
48
|
+
export declare function streamSessionEvents(transport: SessionEventStreamTransport, options?: StreamSessionEventsOptions): AsyncGenerator<SessionEvent, void, void>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { TerminalCapability } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Translate the negotiated `pty-ws` Terminal capability into the WebSocket URL
|
|
4
|
+
* the ttyd client dials. The scoped provider token is ALREADY embedded in the
|
|
5
|
+
* minted `url` (the Modal tunnel host) by `session.resolveExposedPort(7681)` —
|
|
6
|
+
* we do NOT append `cap.token` (identical posture to the desktop: the gate is the
|
|
7
|
+
* unguessable short-TTL tunnel URL + the server-recorded scoped stream token; ttyd
|
|
8
|
+
* runs `--writable` with no `-c` credential in v1). We only normalize the scheme
|
|
9
|
+
* to `ws`/`wss`; a bare host is already the ttyd websocket endpoint.
|
|
10
|
+
*/
|
|
11
|
+
export declare function terminalSocketUrl(cap: Pick<TerminalCapability, "url">): string;
|
|
12
|
+
/** ttyd subprotocol — REQUIRED on the WebSocket handshake or ttyd refuses it. */
|
|
13
|
+
export declare const TTYD_SUBPROTOCOL = "tty";
|
|
14
|
+
/** Client→server command bytes (the first char of each outbound text frame). */
|
|
15
|
+
export declare const TtydClientCommand: {
|
|
16
|
+
/** stdin: "0" + raw input bytes. */
|
|
17
|
+
readonly INPUT: "0";
|
|
18
|
+
/** window resize: "1" + JSON.stringify({ columns, rows }). */
|
|
19
|
+
readonly RESIZE: "1";
|
|
20
|
+
/** flow-control pause (back-pressure): "2". */
|
|
21
|
+
readonly PAUSE: "2";
|
|
22
|
+
/** flow-control resume: "3". */
|
|
23
|
+
readonly RESUME: "3";
|
|
24
|
+
};
|
|
25
|
+
/** Server→client command bytes (the first char of each inbound frame). */
|
|
26
|
+
export declare const TtydServerCommand: {
|
|
27
|
+
/** stdout/stderr: "0" + raw output bytes (write the rest into xterm). */
|
|
28
|
+
readonly OUTPUT: "0";
|
|
29
|
+
/** set the window title: "1" + title string. */
|
|
30
|
+
readonly SET_WINDOW_TITLE: "1";
|
|
31
|
+
/** ttyd client preferences JSON: "2" + json (ignored by us). */
|
|
32
|
+
readonly SET_PREFERENCES: "2";
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The ttyd handshake's first frame: an auth message. ttyd expects
|
|
36
|
+
* `JSON.stringify({ AuthToken })` as the FIRST text frame on the socket. We send
|
|
37
|
+
* an empty token — our gate is the tunnel URL + scoped stream token, NOT a ttyd
|
|
38
|
+
* `-c` basic-auth credential (which the box does not set in v1). Optional ttyd
|
|
39
|
+
* `columns`/`rows` can ride this frame to seed the PTY size before the first
|
|
40
|
+
* resize. Pure (string-building only) so it stays unit-testable in the SDK.
|
|
41
|
+
*/
|
|
42
|
+
export declare function ttydAuthFrame(opts?: {
|
|
43
|
+
columns?: number;
|
|
44
|
+
rows?: number;
|
|
45
|
+
}): string;
|
|
46
|
+
/** Build a client→server INPUT (stdin) frame: "0" + data. */
|
|
47
|
+
export declare function ttydInputFrame(data: string): string;
|
|
48
|
+
/** Build a client→server RESIZE frame: "1" + JSON.stringify({ columns, rows }). */
|
|
49
|
+
export declare function ttydResizeFrame(columns: number, rows: number): string;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework- and transport-agnostic speech-to-text capability contract.
|
|
3
|
+
*
|
|
4
|
+
* Audio transport, microphone access, credentials, and provider SDKs belong to
|
|
5
|
+
* host-supplied adapters. This module deliberately contains no browser globals
|
|
6
|
+
* and no provider implementation.
|
|
7
|
+
*/
|
|
8
|
+
export type TranscriptionCredentialMode = "managed" | "byok";
|
|
9
|
+
export type WorkspaceTranscriptionTarget = {
|
|
10
|
+
provider: string;
|
|
11
|
+
model: string | null;
|
|
12
|
+
credentialMode: TranscriptionCredentialMode;
|
|
13
|
+
/** Workspace-scoped connection reference. This is never a secret. */
|
|
14
|
+
credentialConnectionId: string | null;
|
|
15
|
+
region: string | null;
|
|
16
|
+
};
|
|
17
|
+
export type WorkspaceTranscriptionPolicy = {
|
|
18
|
+
enabled: boolean;
|
|
19
|
+
/** Exact admin-accepted policy identity; required whenever enabled. */
|
|
20
|
+
acceptanceId: string | null;
|
|
21
|
+
primary: WorkspaceTranscriptionTarget | null;
|
|
22
|
+
/** Explicit language preference. Required when automatic detection is not accepted. */
|
|
23
|
+
language: string | null;
|
|
24
|
+
/** Whether the accepted adapter may automatically detect the spoken language. */
|
|
25
|
+
autoDetectLanguage: boolean;
|
|
26
|
+
/** Whether the accepted adapter may identify distinct speakers. */
|
|
27
|
+
diarization: {
|
|
28
|
+
enabled: boolean;
|
|
29
|
+
maxSpeakers: number | null;
|
|
30
|
+
};
|
|
31
|
+
retention: {
|
|
32
|
+
mode: "none" | "provider-policy";
|
|
33
|
+
maxDays: number | null;
|
|
34
|
+
};
|
|
35
|
+
privacy: {
|
|
36
|
+
allowProviderLogging: boolean;
|
|
37
|
+
allowProviderTraining: boolean;
|
|
38
|
+
};
|
|
39
|
+
fallback: {
|
|
40
|
+
mode: "disabled" | "explicit";
|
|
41
|
+
targets: WorkspaceTranscriptionTarget[];
|
|
42
|
+
};
|
|
43
|
+
cost: {
|
|
44
|
+
currency: "USD";
|
|
45
|
+
maxPerHour: number | null;
|
|
46
|
+
maxPerMonth: number | null;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
export declare const DEFAULT_WORKSPACE_TRANSCRIPTION_POLICY: WorkspaceTranscriptionPolicy;
|
|
50
|
+
export type TranscriptionAdapterDescriptor = {
|
|
51
|
+
provider: string;
|
|
52
|
+
model: string | null;
|
|
53
|
+
credentialMode: TranscriptionCredentialMode;
|
|
54
|
+
region: string | null;
|
|
55
|
+
};
|
|
56
|
+
export type TranscriptionTargetSelection = {
|
|
57
|
+
kind: "primary";
|
|
58
|
+
} | {
|
|
59
|
+
kind: "fallback";
|
|
60
|
+
index: number;
|
|
61
|
+
};
|
|
62
|
+
export type TranscriptionPolicyBlockReason = "disabled" | "unaccepted" | "target_missing" | "fallback_disabled" | "fallback_unaccepted" | "provider_mismatch" | "model_mismatch" | "credential_mode_mismatch" | "region_mismatch";
|
|
63
|
+
export type TranscriptionAuthorization = {
|
|
64
|
+
authorized: true;
|
|
65
|
+
acceptanceId: string;
|
|
66
|
+
target: WorkspaceTranscriptionTarget;
|
|
67
|
+
selection: TranscriptionTargetSelection;
|
|
68
|
+
} | {
|
|
69
|
+
authorized: false;
|
|
70
|
+
reason: TranscriptionPolicyBlockReason;
|
|
71
|
+
};
|
|
72
|
+
export type TranscriptionLifecycleStatus = "idle" | "requesting-permission" | "listening" | "reconnecting" | "cancelling" | "closed" | "error";
|
|
73
|
+
export type TranscriptionErrorCode = "permission_denied" | "not_supported" | "network" | "provider" | "policy_blocked" | "timeout" | "cancelled" | "unavailable" | "too_large" | "invalid_audio" | "unknown";
|
|
74
|
+
/** Native browser voice input defaults to the configured deployment capability. */
|
|
75
|
+
export declare function resolveWorkspaceVoiceInputEnabled(settings: unknown): boolean | null;
|
|
76
|
+
export type TranscriptionTimeSpan = {
|
|
77
|
+
startMilliseconds: number;
|
|
78
|
+
endMilliseconds: number;
|
|
79
|
+
};
|
|
80
|
+
export type TranscriptionSpeaker = {
|
|
81
|
+
/** Provider-neutral identity stable within the local transcription session. */
|
|
82
|
+
id: string;
|
|
83
|
+
label?: string | undefined;
|
|
84
|
+
};
|
|
85
|
+
export type TranscriptionWord = {
|
|
86
|
+
text: string;
|
|
87
|
+
span: TranscriptionTimeSpan;
|
|
88
|
+
confidence?: number | undefined;
|
|
89
|
+
speaker?: TranscriptionSpeaker | undefined;
|
|
90
|
+
};
|
|
91
|
+
/** Optional result detail; adapters omit fields their provider cannot supply. */
|
|
92
|
+
export type TranscriptionResultMetadata = {
|
|
93
|
+
detectedLanguage?: string | undefined;
|
|
94
|
+
span?: TranscriptionTimeSpan | undefined;
|
|
95
|
+
confidence?: number | undefined;
|
|
96
|
+
speaker?: TranscriptionSpeaker | undefined;
|
|
97
|
+
words?: TranscriptionWord[] | undefined;
|
|
98
|
+
};
|
|
99
|
+
export type TranscriptionDiagnostic = {
|
|
100
|
+
operation: "start" | "session" | "cancel" | "close";
|
|
101
|
+
code: TranscriptionErrorCode;
|
|
102
|
+
/** Diagnostic-only detail. React sanitizes and bounds this before forwarding it. */
|
|
103
|
+
detail: string;
|
|
104
|
+
};
|
|
105
|
+
type TranscriptionEventBase = {
|
|
106
|
+
/** Stable across reconnects and explicitly accepted fallback attempts. */
|
|
107
|
+
localSessionId: string;
|
|
108
|
+
/** Adapter-monotonic across the entire local session, including replay. */
|
|
109
|
+
sequence: number;
|
|
110
|
+
occurredAt: string;
|
|
111
|
+
};
|
|
112
|
+
export type TranscriptionEvent = (TranscriptionEventBase & {
|
|
113
|
+
type: "permission.requested";
|
|
114
|
+
}) | (TranscriptionEventBase & {
|
|
115
|
+
type: "session.opened";
|
|
116
|
+
providerSessionId: string;
|
|
117
|
+
}) | (TranscriptionEventBase & {
|
|
118
|
+
type: "transcript.partial";
|
|
119
|
+
segmentId: string;
|
|
120
|
+
text: string;
|
|
121
|
+
metadata?: TranscriptionResultMetadata | undefined;
|
|
122
|
+
}) | (TranscriptionEventBase & {
|
|
123
|
+
type: "transcript.final";
|
|
124
|
+
segmentId: string;
|
|
125
|
+
text: string;
|
|
126
|
+
/** Stable provider/coordinator acceptance identity used for dedupe. */
|
|
127
|
+
providerAcceptanceId: string;
|
|
128
|
+
metadata?: TranscriptionResultMetadata | undefined;
|
|
129
|
+
}) | (TranscriptionEventBase & {
|
|
130
|
+
type: "usage";
|
|
131
|
+
audioMilliseconds: number;
|
|
132
|
+
costUsd: number | null;
|
|
133
|
+
}) | (TranscriptionEventBase & {
|
|
134
|
+
type: "session.reconnecting";
|
|
135
|
+
attempt: number;
|
|
136
|
+
reason: string;
|
|
137
|
+
}) | (TranscriptionEventBase & {
|
|
138
|
+
type: "session.error";
|
|
139
|
+
code: TranscriptionErrorCode;
|
|
140
|
+
recoverable: boolean;
|
|
141
|
+
}) | (TranscriptionEventBase & {
|
|
142
|
+
type: "session.closed";
|
|
143
|
+
reason: "completed" | "cancelled" | "error" | "replaced";
|
|
144
|
+
});
|
|
145
|
+
export type TranscriptionSessionRequest = {
|
|
146
|
+
localSessionId: string;
|
|
147
|
+
policyAcceptanceId: string;
|
|
148
|
+
selection: TranscriptionTargetSelection;
|
|
149
|
+
target: WorkspaceTranscriptionTarget;
|
|
150
|
+
language: string | null;
|
|
151
|
+
autoDetectLanguage: boolean;
|
|
152
|
+
diarization: WorkspaceTranscriptionPolicy["diarization"];
|
|
153
|
+
retention: WorkspaceTranscriptionPolicy["retention"];
|
|
154
|
+
privacy: WorkspaceTranscriptionPolicy["privacy"];
|
|
155
|
+
cost: WorkspaceTranscriptionPolicy["cost"];
|
|
156
|
+
/** A replacement/reconnect adapter must emit events above this floor. */
|
|
157
|
+
sequenceFloor: number;
|
|
158
|
+
};
|
|
159
|
+
export type TranscriptionEventListener = (event: TranscriptionEvent) => void;
|
|
160
|
+
export type TranscriptionAdapterStartContext = {
|
|
161
|
+
/** Aborted on local cancellation, policy replacement, timeout, or unmount. */
|
|
162
|
+
signal: AbortSignal;
|
|
163
|
+
/** Non-UI observability seam; callers receive only bounded, redacted detail. */
|
|
164
|
+
reportDiagnostic: (diagnostic: TranscriptionDiagnostic) => void;
|
|
165
|
+
};
|
|
166
|
+
export type TranscriptionSession = {
|
|
167
|
+
readonly localSessionId: string;
|
|
168
|
+
cancel(reason?: string): Promise<void>;
|
|
169
|
+
close(): Promise<void>;
|
|
170
|
+
};
|
|
171
|
+
export type TranscriptionAdapter = {
|
|
172
|
+
readonly descriptor: TranscriptionAdapterDescriptor;
|
|
173
|
+
start(request: TranscriptionSessionRequest, listener: TranscriptionEventListener, context: TranscriptionAdapterStartContext): Promise<TranscriptionSession>;
|
|
174
|
+
};
|
|
175
|
+
/** Invalid or absent settings always resolve to the fail-closed default. */
|
|
176
|
+
export declare function resolveWorkspaceTranscriptionPolicy(settings: unknown): WorkspaceTranscriptionPolicy;
|
|
177
|
+
/**
|
|
178
|
+
* Speech authorization is intentionally independent from turn model policy.
|
|
179
|
+
* Every selected adapter must match one exact admin-accepted target.
|
|
180
|
+
*/
|
|
181
|
+
export declare function authorizeTranscriptionAdapter(policy: WorkspaceTranscriptionPolicy, descriptor: TranscriptionAdapterDescriptor, selection?: TranscriptionTargetSelection): TranscriptionAuthorization;
|
|
182
|
+
export declare function createTranscriptionSessionRequest(input: {
|
|
183
|
+
policy: WorkspaceTranscriptionPolicy;
|
|
184
|
+
adapter: TranscriptionAdapter;
|
|
185
|
+
localSessionId: string;
|
|
186
|
+
selection?: TranscriptionTargetSelection | undefined;
|
|
187
|
+
sequenceFloor?: number | undefined;
|
|
188
|
+
}): TranscriptionSessionRequest | null;
|
|
189
|
+
export {};
|