@proteos/sdk 0.18.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.
Files changed (94) hide show
  1. package/LICENSE +40 -0
  2. package/dist/chunk-7RGN4E22.cjs +1185 -0
  3. package/dist/chunk-7RGN4E22.cjs.map +1 -0
  4. package/dist/chunk-XJP5WCRZ.js +1125 -0
  5. package/dist/chunk-XJP5WCRZ.js.map +1 -0
  6. package/dist/index.cjs +2384 -0
  7. package/dist/index.cjs.map +1 -0
  8. package/dist/index.d.cts +5225 -0
  9. package/dist/index.d.ts +5225 -0
  10. package/dist/index.js +2146 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/meta/index.cjs +204 -0
  13. package/dist/meta/index.cjs.map +1 -0
  14. package/dist/meta/index.d.cts +2 -0
  15. package/dist/meta/index.d.ts +2 -0
  16. package/dist/meta/index.js +3 -0
  17. package/dist/meta/index.js.map +1 -0
  18. package/dist/types-BNsjfU8N.d.cts +3299 -0
  19. package/dist/types-BNsjfU8N.d.ts +3299 -0
  20. package/package.json +86 -0
  21. package/src/agent/agents.ts +53 -0
  22. package/src/agent/index.ts +134 -0
  23. package/src/agent/mcp-servers.ts +102 -0
  24. package/src/agent/prompts.ts +80 -0
  25. package/src/agent/session-types.ts +397 -0
  26. package/src/agent/sessions.ts +197 -0
  27. package/src/agent/skills.ts +89 -0
  28. package/src/agent/tools.ts +53 -0
  29. package/src/agent/types.ts +362 -0
  30. package/src/auth/index.ts +111 -0
  31. package/src/auth/me.ts +46 -0
  32. package/src/auth/organizations.ts +128 -0
  33. package/src/auth/platform-entities.ts +78 -0
  34. package/src/auth/roles.ts +213 -0
  35. package/src/auth/types.ts +294 -0
  36. package/src/auth/users.ts +226 -0
  37. package/src/client.ts +441 -0
  38. package/src/connector/index.ts +120 -0
  39. package/src/connector/types.ts +150 -0
  40. package/src/conversation/index.ts +297 -0
  41. package/src/conversation/types.ts +590 -0
  42. package/src/conversation/voice.ts +123 -0
  43. package/src/data/index.ts +53 -0
  44. package/src/data/queries.ts +66 -0
  45. package/src/data/records.ts +122 -0
  46. package/src/data/types.ts +89 -0
  47. package/src/errors.ts +148 -0
  48. package/src/events/index.ts +172 -0
  49. package/src/events/types.ts +77 -0
  50. package/src/functions/actions.ts +95 -0
  51. package/src/functions/index.ts +32 -0
  52. package/src/functions/types.ts +71 -0
  53. package/src/http/index.ts +2 -0
  54. package/src/http/query-params.ts +106 -0
  55. package/src/index.ts +598 -0
  56. package/src/iterator.ts +183 -0
  57. package/src/knowledge/graph.ts +35 -0
  58. package/src/knowledge/index.ts +104 -0
  59. package/src/knowledge/labels.ts +70 -0
  60. package/src/knowledge/links.ts +65 -0
  61. package/src/knowledge/nodes.ts +198 -0
  62. package/src/knowledge/record-links.ts +66 -0
  63. package/src/knowledge/types.ts +569 -0
  64. package/src/meta/apps.ts +107 -0
  65. package/src/meta/components.ts +124 -0
  66. package/src/meta/currency/index.ts +202 -0
  67. package/src/meta/entities.ts +193 -0
  68. package/src/meta/filters.ts +76 -0
  69. package/src/meta/index.ts +227 -0
  70. package/src/meta/layout/common-props.ts +93 -0
  71. package/src/meta/layout/control-registry.json +70 -0
  72. package/src/meta/layout/control-registry.ts +92 -0
  73. package/src/meta/layout/elements.ts +203 -0
  74. package/src/meta/layout/index.ts +41 -0
  75. package/src/meta/layout/page-layout.ts +35 -0
  76. package/src/meta/layout/size-value.ts +27 -0
  77. package/src/meta/list-views.ts +109 -0
  78. package/src/meta/lists.ts +104 -0
  79. package/src/meta/menu-configurations.ts +128 -0
  80. package/src/meta/modules.ts +159 -0
  81. package/src/meta/pages.ts +106 -0
  82. package/src/meta/types.ts +1115 -0
  83. package/src/meta/variables.ts +98 -0
  84. package/src/storage/files.ts +183 -0
  85. package/src/storage/index.ts +33 -0
  86. package/src/storage/types.ts +70 -0
  87. package/src/types/common.ts +143 -0
  88. package/src/types/index.ts +28 -0
  89. package/src/types/options.ts +95 -0
  90. package/src/workflow/executions.ts +99 -0
  91. package/src/workflow/index.ts +109 -0
  92. package/src/workflow/node-types.ts +50 -0
  93. package/src/workflow/types.ts +658 -0
  94. package/src/workflow/workflows.ts +152 -0
@@ -0,0 +1,590 @@
1
+ /**
2
+ * Wire types for conversation-service (/conversations/v1) — hand-maintained
3
+ * mirror of packages/go/model/conversation (snake_case, Is-prefixed booleans).
4
+ */
5
+
6
+ import type { FileRef } from '../types/common.js'
7
+
8
+ /** Platform medium a conversation lives on (closed enum; platform identity). */
9
+ export type Channel =
10
+ | 'slack'
11
+ | 'email'
12
+ | 'linkedin'
13
+ | 'sms'
14
+ | 'teams'
15
+ | 'telegram'
16
+ | 'whatsapp'
17
+ | 'meeting'
18
+ | 'adhoc'
19
+ | 'instagram'
20
+ | 'messenger'
21
+ | 'x'
22
+
23
+ /**
24
+ * Concrete integration serving a channel (typed union — one value per shipped
25
+ * connector; runtime availability is decided by the service's registry).
26
+ * The unipile-* family serves the six messaging systems aggregated through
27
+ * Unipile — one key per messaging system.
28
+ */
29
+ export type ConnectorKey =
30
+ | 'slack'
31
+ | 'gmail'
32
+ | 'echo'
33
+ | 'unipile-whatsapp'
34
+ | 'unipile-linkedin'
35
+ | 'unipile-telegram'
36
+ | 'unipile-instagram'
37
+ | 'unipile-messenger'
38
+ | 'unipile-x'
39
+
40
+ /**
41
+ * Who operates the integration mechanics behind a connector: Proteos' own
42
+ * integration (native) or an account aggregated through Unipile (unipile).
43
+ * Computed on connection reads; the UI groups the connector catalog by it.
44
+ */
45
+ export type ConnectorProvider = 'native' | 'unipile'
46
+
47
+ export type MessageDirection = 'inbound' | 'outbound'
48
+ export type MessageStatus = 'received' | 'pending' | 'sent' | 'failed'
49
+ export type ConnectionScope = 'org' | 'user'
50
+ export type ConnectionStatus = 'pending' | 'active' | 'error' | 'revoked'
51
+ export type ConversationStatus = 'active' | 'ended' | 'archived'
52
+ export type AgentListenerTriggerType = 'always' | 'mention' | 'channel' | 'keyword'
53
+
54
+ export interface UserRef {
55
+ type: string
56
+ id: string
57
+ }
58
+
59
+ /**
60
+ * Inline snapshot of a person on a message/reaction — the integration-side
61
+ * identity plus, when resolved via email match, the platform user.
62
+ */
63
+ export interface ParticipantRef {
64
+ external_id?: string
65
+ name: string
66
+ email?: string
67
+ /** Resolved platform identity (email match); absent when unresolved. */
68
+ platform_user?: UserRef
69
+ }
70
+
71
+ /**
72
+ * One member of a conversation's roster — everyone in the thread, INCLUDING the
73
+ * connected account itself. The account's own entries carry is_self=true; a UI
74
+ * renders "who it's with" as the non-self subset (1 → single avatar, ≥2 →
75
+ * stacked).
76
+ */
77
+ export interface ConversationParticipant extends ParticipantRef {
78
+ is_self: boolean
79
+ }
80
+
81
+ /** How a MessageRecipient was addressed: primary, carbon copy, blind copy. */
82
+ export type RecipientRole = 'to' | 'cc' | 'bcc'
83
+
84
+ /**
85
+ * One addressee of a message with the role it was addressed under. Bcc is only
86
+ * present on messages the platform itself sent (inbound bcc is SMTP-stripped).
87
+ */
88
+ export interface MessageRecipient extends ParticipantRef {
89
+ role: RecipientRole
90
+ }
91
+
92
+ /**
93
+ * One unit of message content — what was SAID. Files a message CARRIED are
94
+ * NOT content: they are Attachment rows (Message.attachments).
95
+ */
96
+ export interface ContentBlock {
97
+ type: 'text' | 'html'
98
+ text?: string
99
+ /**
100
+ * Sanitized rich email body (ingest-time allowlist: layout tables, inline
101
+ * styles, https images; no scripts/forms/handlers). Rides ALONGSIDE the
102
+ * canonical text block. Render only in an isolated, script-less surface.
103
+ */
104
+ html?: string
105
+ }
106
+
107
+ /** Secret material is redacted on every read ("********" when set). */
108
+ export interface ConnectionCredentials {
109
+ bot_token?: string
110
+ bot_user_id?: string
111
+ refresh_token?: string
112
+ access_token?: string
113
+ token_expires_at?: string
114
+ granted_scopes?: string
115
+ /** Aggregator-hosted account identity (unipile-*) — nothing secret. */
116
+ account_id?: string
117
+ owner_provider_id?: string
118
+ }
119
+
120
+ /** How a channel's reaction vocabulary is shaped. */
121
+ export type ReactionSetKind = 'open' | 'fixed'
122
+
123
+ /** One entry of a fixed reaction vocabulary (token = the value to send). */
124
+ export interface ReactionOption {
125
+ token: string
126
+ unicode?: string
127
+ label?: string
128
+ }
129
+
130
+ /**
131
+ * A connector's declarative reaction capability, projected onto the
132
+ * connection read: open → show an emoji picker; fixed → exactly the allowed
133
+ * buttons; absent (connection.reactions undefined) → no affordance.
134
+ */
135
+ export interface ReactionCapability {
136
+ kind: ReactionSetKind
137
+ allowed?: ReactionOption[]
138
+ /** 0 = unbounded (Slack); 1 = single-slot (a new reaction replaces the old). */
139
+ max_per_actor: number
140
+ }
141
+
142
+ export interface Connection {
143
+ id: string
144
+ org_id: string
145
+ connector_key: ConnectorKey
146
+ channel: Channel
147
+ name: string
148
+ scope: ConnectionScope
149
+ /** Set only when scope=user (the connecting user); absent for org-wide. */
150
+ owner?: UserRef
151
+ external_workspace_id: string
152
+ credentials: ConnectionCredentials
153
+ settings: Record<string, unknown>
154
+ status: ConnectionStatus
155
+ /** Computed on read: the connector implements the reaction capability. */
156
+ supports_reactions: boolean
157
+ /** The capability descriptor; absent when unsupported. */
158
+ reactions?: ReactionCapability
159
+ /**
160
+ * Computed on read like supports_reactions: who operates the integration
161
+ * (native | unipile). Absent when the connector is not registered in this
162
+ * environment.
163
+ */
164
+ provider?: ConnectorProvider
165
+ created_at: string
166
+ created_by: UserRef
167
+ updated_at: string
168
+ updated_by: UserRef
169
+ }
170
+
171
+ export interface Conversation {
172
+ id: string
173
+ org_id: string
174
+ connection_id: string
175
+ channel: Channel
176
+ external_conversation_id: string
177
+ subject: string
178
+ status: ConversationStatus
179
+ /**
180
+ * Room directory row a room-borne thread (Slack channel conversation) lives
181
+ * in; absent for DMs, email, meeting, adhoc.
182
+ */
183
+ room_id?: string
184
+ /**
185
+ * Main conversation a child conversation forked from (Slack: the channel's
186
+ * main conversation; provider-side the child is a native Slack thread);
187
+ * absent for main/DM/email/meeting/adhoc.
188
+ */
189
+ parent_conversation_id?: string
190
+ /**
191
+ * Message id of the child conversation's root message, which lives in the
192
+ * parent conversation; absent when the root is unknown (predates ingest).
193
+ */
194
+ started_by_message_id?: string
195
+ started_at?: string
196
+ ended_at?: string
197
+ /**
198
+ * The thread's complete roster — everyone in it, including the connected
199
+ * account (its own entries marked is_self). Deduped by external_id; the
200
+ * queryable person dimension. Replaces the old single `counterpart`.
201
+ */
202
+ participants?: ConversationParticipant[]
203
+ last_message_at: string
204
+ metadata: Record<string, unknown>
205
+ /**
206
+ * Messages summary — present only when the list opted in via
207
+ * include: 'messages_summary'. Renders a hub stream row (root on Slack,
208
+ * latest on email, reply affordance) without a per-conversation fetch.
209
+ */
210
+ root_message?: MessagePreview
211
+ latest_message?: MessagePreview
212
+ messages_total?: number
213
+ /** Up to 3 most recent distinct senders excluding the root sender. */
214
+ last_repliers?: ParticipantRef[]
215
+ /** Requesting user's read marker; absent = never opened. */
216
+ last_read_at?: string
217
+ /**
218
+ * Server-computed unread predicate for the requesting user: activity after
219
+ * the marker AND the latest message is inbound.
220
+ */
221
+ is_unread: boolean
222
+ created_at: string
223
+ created_by: UserRef
224
+ updated_at: string
225
+ updated_by: UserRef
226
+ }
227
+
228
+ /**
229
+ * Compact snapshot of one message riding on conversation reads
230
+ * (include: 'messages_summary'): enough for a stream row — who, the first
231
+ * ~500 chars of text, direction/status for outbound identity.
232
+ */
233
+ export interface MessagePreview {
234
+ sender: ParticipantRef
235
+ text: string
236
+ direction: MessageDirection
237
+ status: MessageStatus
238
+ occurred_at: string
239
+ }
240
+
241
+ /**
242
+ * Aggregated unread-conversation counts for the requesting user (unit:
243
+ * conversations, not messages) — the envelope total and per-channel badges.
244
+ */
245
+ export interface UnreadCounts {
246
+ total: number
247
+ channels: Partial<Record<Channel, number>>
248
+ }
249
+
250
+ /**
251
+ * One file that arrived with a message. `file` is the platform FileRef —
252
+ * bytes live in storage-service; size and content type resolve from storage
253
+ * by id. content_id/is_inline carry the MIME inline-image semantics
254
+ * (cid: references in the html body vs user-facing downloads).
255
+ */
256
+ export interface Attachment {
257
+ id: string
258
+ org_id: string
259
+ message_id: string
260
+ connection_id: string
261
+ file: FileRef
262
+ content_id?: string
263
+ is_inline: boolean
264
+ created_at: string
265
+ created_by: UserRef
266
+ }
267
+
268
+ /** Aggregated reactions on a message: one entry per emoji (native token). */
269
+ export interface Reaction {
270
+ emoji: string
271
+ count: number
272
+ participants: ParticipantRef[]
273
+ }
274
+
275
+ export interface Message {
276
+ id: string
277
+ org_id: string
278
+ conversation_id: string
279
+ connection_id: string
280
+ channel: Channel
281
+ direction: MessageDirection
282
+ external_message_id: string
283
+ sender: ParticipantRef
284
+ /** Who the message was addressed to (To/Cc/Bcc), each tagged with its role. */
285
+ recipients?: MessageRecipient[]
286
+ content: ContentBlock[]
287
+ status: MessageStatus
288
+ occurred_at: string
289
+ /** Read-time projection; absent/empty on channels without reactions. */
290
+ reactions?: Reaction[]
291
+ /** Read-time projection of the message's attachment rows; absent without files. */
292
+ attachments?: Attachment[]
293
+ /**
294
+ * Child-conversation projection (read-time, per-conversation lists): the
295
+ * conversation rooted at this message and its message count — the "N
296
+ * replies" affordance. Absent for messages no child conversation forked
297
+ * from.
298
+ */
299
+ child_conversation_id?: string
300
+ child_messages_total?: number
301
+ metadata: Record<string, unknown>
302
+ error: string
303
+ created_at: string
304
+ created_by: UserRef
305
+ updated_at: string
306
+ updated_by: UserRef
307
+ }
308
+
309
+ /**
310
+ * Per-trigger configuration, discriminated by the sibling trigger_type: channel
311
+ * carries external_channel_id, keyword carries phrases, always/mention carry
312
+ * neither. (Serialized as the bare variant; both fields optional here.)
313
+ */
314
+ export interface AgentListenerTriggerConfig {
315
+ external_channel_id?: string
316
+ phrases?: string[]
317
+ }
318
+
319
+ export interface AgentListener {
320
+ id: string
321
+ org_id: string
322
+ connection_id: string
323
+ conversation_id: string
324
+ name: string
325
+ agent_key: string
326
+ trigger_type: AgentListenerTriggerType
327
+ trigger_config: AgentListenerTriggerConfig
328
+ /** The user the dispatcher acts as when driving the agent. */
329
+ acting_user: UserRef
330
+ is_enabled: boolean
331
+ priority: number
332
+ created_at: string
333
+ created_by: UserRef
334
+ updated_at: string
335
+ updated_by: UserRef
336
+ }
337
+
338
+ export interface CreateConnectionRequest {
339
+ connector_key: ConnectorKey
340
+ name: string
341
+ scope: ConnectionScope
342
+ settings?: Record<string, unknown>
343
+ }
344
+
345
+ export interface UpdateConnectionRequest {
346
+ name?: string
347
+ settings?: Record<string, unknown>
348
+ }
349
+
350
+ export interface InstallConnectionResponse {
351
+ authorization_url: string
352
+ }
353
+
354
+ export interface SendMessageRequest {
355
+ /** Reply mode: send into this existing conversation. */
356
+ conversation_id?: string
357
+ /**
358
+ * Targeted reply: reply aimed at ONE message (mutually exclusive with the
359
+ * other modes). Slack starts/continues the child conversation rooted at
360
+ * that message (carrying parent_conversation_id/started_by_message_id —
361
+ * provider-side a native Slack thread); email replies in the same
362
+ * conversation with In-Reply-To anchored at the target; channels without
363
+ * message-targeted replies reject with `child_conversation_not_supported`.
364
+ */
365
+ reply_to_message_id?: string
366
+ /** Originate mode (omit conversation_id): connection_id + at least one To are required. */
367
+ connection_id?: string
368
+ /**
369
+ * Primary destinations for originate: one room (Slack channel) OR one-or-more
370
+ * participants (email To, a Slack DM, or several users → a Slack MPIM).
371
+ */
372
+ to?: SendRecipient[]
373
+ /** Carbon-copy participants (email only). */
374
+ cc?: SendRecipient[]
375
+ /** Blind-carbon-copy participants (email only). */
376
+ bcc?: SendRecipient[]
377
+ /** Optional subject, used by email when originating. */
378
+ subject?: string
379
+ /** May be empty when attachments are present. */
380
+ content: ContentBlock[]
381
+ /**
382
+ * Files to send with the message. Pre-upload each file to storage-service
383
+ * and reference it here ({id, name}); the server downloads the bytes and
384
+ * hands them to the channel connector (Slack: one native message with the
385
+ * text as its comment; Gmail: multipart/mixed mail; ≤25MB per file, Slack
386
+ * ≤10 files per message). Channels without file support reject with
387
+ * `unsupported_content`.
388
+ */
389
+ attachments?: FileRef[]
390
+ }
391
+
392
+ export interface CreateAgentListenerRequest {
393
+ connection_id?: string
394
+ conversation_id?: string
395
+ name: string
396
+ agent_key: string
397
+ trigger_type: AgentListenerTriggerType
398
+ trigger_config?: AgentListenerTriggerConfig
399
+ /** A bare user id; the service wraps it into a person UserRef. */
400
+ acting_user_id: string
401
+ /** Omit to default to enabled. */
402
+ is_enabled?: boolean
403
+ priority?: number
404
+ }
405
+
406
+ export interface UpdateAgentListenerRequest {
407
+ name?: string
408
+ agent_key?: string
409
+ trigger_type?: AgentListenerTriggerType
410
+ trigger_config?: AgentListenerTriggerConfig
411
+ acting_user_id?: string
412
+ is_enabled?: boolean
413
+ priority?: number
414
+ }
415
+
416
+ export interface PaginationQuery {
417
+ page?: number
418
+ page_size?: number
419
+ sort_by?: string
420
+ sort_direction?: 'asc' | 'desc'
421
+ }
422
+
423
+ export interface ListConnectionsQuery extends PaginationQuery {
424
+ connector_key?: string
425
+ channel?: string
426
+ scope?: string
427
+ status?: string
428
+ }
429
+
430
+ export interface ListConversationsQuery extends PaginationQuery {
431
+ channel?: string
432
+ status?: string
433
+ connection_id?: string
434
+ /** Conversations of one room (Slack channel) — the room stream. */
435
+ room_id?: string
436
+ /** Child conversations forked from one main conversation. */
437
+ parent_conversation_id?: string
438
+ /** Threads whose roster contains this external party — the person stream. */
439
+ participant_external_id?: string
440
+ /** Opt into the root/latest message projection on each row. */
441
+ include?: 'messages_summary'
442
+ }
443
+
444
+ export interface ListMessagesQuery extends PaginationQuery {
445
+ direction?: string
446
+ status?: string
447
+ }
448
+
449
+ export interface ListAgentListenersQuery extends PaginationQuery {
450
+ connection_id?: string
451
+ conversation_id?: string
452
+ agent_key?: string
453
+ is_enabled?: boolean
454
+ }
455
+
456
+ /** Discriminates a send target: a person or a venue. */
457
+ export type RecipientKind = 'participant' | 'room'
458
+ export type ParticipantSource = 'sync' | 'ingest'
459
+ export type RoomSource = 'sync' | 'ingest'
460
+
461
+ /**
462
+ * Send-time addressing VO: who/where an originated message goes. Points at a
463
+ * Participant or a Room by kind + external id (never a stored entity itself).
464
+ */
465
+ export interface SendRecipient {
466
+ kind: RecipientKind
467
+ /** The connector-side id: a room's (Slack channel id) or a participant's (Slack user id, email address). */
468
+ external_id: string
469
+ }
470
+
471
+ /** A PERSON known on a connection (directory row; resolvable to a platform user). */
472
+ export interface Participant {
473
+ id: string
474
+ org_id: string
475
+ connection_id: string
476
+ /** Slack user id / email address — the id to DM or email. */
477
+ external_id: string
478
+ name: string
479
+ email?: string
480
+ /** Resolved platform identity (email match); absent when unresolved. */
481
+ platform_user?: UserRef
482
+ metadata: Record<string, unknown>
483
+ source: ParticipantSource
484
+ last_seen_at: string
485
+ created_at: string
486
+ created_by: UserRef
487
+ updated_at: string
488
+ updated_by: UserRef
489
+ }
490
+
491
+ /** An addressable VENUE on a connection (Slack channel; later meeting rooms). */
492
+ export interface Room {
493
+ id: string
494
+ org_id: string
495
+ connection_id: string
496
+ /** Slack channel id — the id to post into. */
497
+ external_id: string
498
+ name: string
499
+ metadata: Record<string, unknown>
500
+ /** How the row was populated: a directory sweep or minted at ingest. */
501
+ source: RoomSource
502
+ last_seen_at: string
503
+ created_at: string
504
+ created_by: UserRef
505
+ updated_at: string
506
+ updated_by: UserRef
507
+ }
508
+
509
+ export interface ListParticipantsQuery extends PaginationQuery {
510
+ /** Free-text needle matched against display name + external id. */
511
+ q?: string
512
+ }
513
+
514
+ export interface ListRoomsQuery extends PaginationQuery {
515
+ /** Free-text needle matched against name + external id. */
516
+ q?: string
517
+ }
518
+
519
+ export interface AddReactionRequest {
520
+ /** Connector-native token (Slack shortcode like "thumbsup"). */
521
+ emoji: string
522
+ }
523
+
524
+ export interface ListReactionsResponse {
525
+ data: Reaction[]
526
+ }
527
+
528
+ export interface ResponseMeta {
529
+ page: number
530
+ page_size: number
531
+ items_total: number
532
+ pages_total: number
533
+ }
534
+
535
+ export interface ListResponse<T> {
536
+ meta: ResponseMeta
537
+ data: T[]
538
+ }
539
+
540
+ export type TranscriptionStatus = 'pending' | 'processing' | 'completed' | 'failed'
541
+
542
+ export interface TranscriptTurn {
543
+ speaker: number
544
+ speaker_label: string
545
+ text: string
546
+ start_ms: number
547
+ end_ms: number
548
+ confidence: number
549
+ }
550
+
551
+ export interface Transcription {
552
+ id: string
553
+ org_id: string
554
+ source_file_id: string
555
+ audio_file_id: string
556
+ transcript_file_id: string
557
+ status: TranscriptionStatus
558
+ language: string
559
+ duration_seconds: number
560
+ model: string
561
+ is_diarized: boolean
562
+ turns: TranscriptTurn[]
563
+ speaker_count: number
564
+ provider_request_id: string
565
+ conversation_id: string
566
+ error: string
567
+ created_at: string
568
+ created_by: UserRef
569
+ updated_at: string
570
+ updated_by: UserRef
571
+ }
572
+
573
+ export interface CreateTranscriptionRequest {
574
+ file_id: string
575
+ language?: string
576
+ model?: string
577
+ is_diarized?: boolean
578
+ }
579
+
580
+ /** Channel defaults to adhoc; meeting is the only other allowed target. */
581
+ export interface MaterializeTranscriptionRequest {
582
+ channel?: Channel
583
+ subject?: string
584
+ /** Maps diarized speaker indexes ("0", "1", …) to display names. */
585
+ speaker_names?: Record<string, string>
586
+ }
587
+
588
+ export interface ListTranscriptionsQuery extends PaginationQuery {
589
+ status?: string
590
+ }
@@ -0,0 +1,123 @@
1
+ import type { ProteosClient } from '../client.js'
2
+
3
+ const VOICE_BASE_PATH = '/conversations/v1/voice'
4
+
5
+ /** One normalized transcription update streamed back from the server. */
6
+ export interface TranscriptResult {
7
+ /** The recognized text for this segment. */
8
+ transcript: string
9
+ /** True once this segment is final and will not change. */
10
+ is_final: boolean
11
+ /** True when the server detected end-of-speech (a natural pause). */
12
+ speech_final: boolean
13
+ /** Recognition confidence, 0–1. */
14
+ confidence: number
15
+ }
16
+
17
+ /** Options for opening a live transcription stream. */
18
+ export interface TranscribeStreamOptions {
19
+ /** BCP-47 language code (e.g. `en`, `de`). Defaults to the server's default. */
20
+ language?: string
21
+ /** Stream interim (non-final) results as audio arrives. Defaults to `true`. */
22
+ interimResults?: boolean
23
+ /** Add punctuation to results. Defaults to `true`. */
24
+ punctuate?: boolean
25
+ /** Format entities (numbers, dates…) in results. Defaults to `true`. */
26
+ smartFormat?: boolean
27
+ /**
28
+ * Raw audio encoding (e.g. `linear16`). Omit for containerized audio
29
+ * (WebM/Opus from MediaRecorder), which the server auto-detects.
30
+ */
31
+ encoding?: string
32
+ /** Sample rate in Hz. Required only when `encoding` is set. */
33
+ sampleRate?: number
34
+ /** Called for each transcription result. */
35
+ onResult: (result: TranscriptResult) => void
36
+ /** Called if the stream errors. */
37
+ onError?: (error: Event) => void
38
+ /** Called when the stream closes (either side). */
39
+ onClose?: () => void
40
+ }
41
+
42
+ /** A live transcription session: push audio in, results arrive via `onResult`. */
43
+ export interface VoiceTranscriptionStream {
44
+ /** Forward one audio chunk (binary) to the server. */
45
+ sendAudio(chunk: Blob | ArrayBufferView | ArrayBuffer): void
46
+ /** Ask the server to flush pending results without closing the stream. */
47
+ finalize(): void
48
+ /** Close the stream. */
49
+ close(): void
50
+ }
51
+
52
+ /**
53
+ * Service for realtime speech-to-text on conversation-service.
54
+ *
55
+ * Transcription is a WebSocket: open a stream, push audio chunks, and receive
56
+ * {@link TranscriptResult}s. The transcription provider is a server-side concern
57
+ * and is not exposed here.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * const stream = await agent.voice.transcribeStream({
62
+ * onResult: (r) => console.log(r.transcript, r.is_final),
63
+ * });
64
+ * recorder.ondataavailable = (e) => stream.sendAudio(e.data);
65
+ * // …later: stream.finalize(); stream.close();
66
+ * ```
67
+ */
68
+ export interface VoiceService {
69
+ /**
70
+ * Opens a live transcription stream and resolves once it is connected.
71
+ *
72
+ * @param options - Stream configuration and result/lifecycle callbacks
73
+ * @returns A handle to push audio and control the stream
74
+ */
75
+ transcribeStream(options: TranscribeStreamOptions): Promise<VoiceTranscriptionStream>
76
+ }
77
+
78
+ export class VoiceServiceImpl implements VoiceService {
79
+ constructor(private readonly client: ProteosClient) {}
80
+
81
+ async transcribeStream(options: TranscribeStreamOptions): Promise<VoiceTranscriptionStream> {
82
+ const query = buildQuery(options)
83
+ const socket = await this.client.openWebSocket(`${VOICE_BASE_PATH}/transcribe/stream${query}`)
84
+ socket.binaryType = 'arraybuffer'
85
+
86
+ socket.onmessage = (event: MessageEvent) => {
87
+ if (typeof event.data !== 'string') return
88
+ try {
89
+ options.onResult(JSON.parse(event.data) as TranscriptResult)
90
+ } catch {
91
+ // Ignore malformed frames.
92
+ }
93
+ }
94
+ if (options.onError) socket.onerror = options.onError
95
+ socket.onclose = () => options.onClose?.()
96
+
97
+ const isOpen = () => socket.readyState === WebSocket.OPEN
98
+
99
+ return {
100
+ sendAudio: (chunk) => {
101
+ if (isOpen()) socket.send(chunk)
102
+ },
103
+ finalize: () => {
104
+ if (isOpen()) socket.send(JSON.stringify({ type: 'finalize' }))
105
+ },
106
+ close: () => socket.close(),
107
+ }
108
+ }
109
+ }
110
+
111
+ /** Serializes options into the endpoint's query string (snake_case wire format). */
112
+ function buildQuery(options: TranscribeStreamOptions): string {
113
+ const params = new URLSearchParams()
114
+ if (options.language) params.set('language', options.language)
115
+ if (options.interimResults !== undefined)
116
+ params.set('interim_results', String(options.interimResults))
117
+ if (options.punctuate !== undefined) params.set('punctuate', String(options.punctuate))
118
+ if (options.smartFormat !== undefined) params.set('smart_format', String(options.smartFormat))
119
+ if (options.encoding) params.set('encoding', options.encoding)
120
+ if (options.sampleRate !== undefined) params.set('sample_rate', String(options.sampleRate))
121
+ const queryString = params.toString()
122
+ return queryString ? `?${queryString}` : ''
123
+ }