@vogent/vogent-web-client 0.1.5 → 0.1.6

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/src/VogentCall.ts DELETED
@@ -1,350 +0,0 @@
1
- /**
2
- * @fileoverview VogentCall provides the main interface for managing voice calls with Vogent's AI system.
3
- *
4
- * This class handles:
5
- * - Call lifecycle management (start, pause, hangup)
6
- * - Audio connection setup
7
- * - Real-time transcript monitoring
8
- * - Status event handling
9
- *
10
- * Basic usage:
11
- * ```typescript
12
- * const call = new VogentCall({
13
- * sessionId: "session_id",
14
- * dialId: "dial_id",
15
- * token: "auth_token"
16
- * });
17
- *
18
- * // Start the call
19
- * await call.start();
20
- *
21
- * // Connect audio
22
- * const audioConn = await call.connectAudio();
23
- *
24
- * // Monitor transcripts
25
- * const unsubscribe = call.monitorTranscript((transcript) => {
26
- * console.log(transcript);
27
- * });
28
- *
29
- * // Monitor status changes
30
- * call.on('status', (status) => {
31
- * console.log('Call status:', status);
32
- * });
33
- *
34
- * // Later: cleanup
35
- * unsubscribe();
36
- * await call.hangup();
37
- * ```
38
- *
39
- * @see {@link https://docs.vogent.ai} for complete server documentation
40
- * @module VogentCall
41
- */
42
-
43
- import {
44
- ApolloClient,
45
- createHttpLink,
46
- InMemoryCache,
47
- NormalizedCacheObject,
48
- split,
49
- } from '@apollo/client/core';
50
- import { setContext } from '@apollo/client/link/context';
51
- import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
52
- import { getMainDefinition, ObservableSubscription } from '@apollo/client/utilities';
53
- import {
54
- BrowserDialTokenType,
55
- Dial,
56
- DialsUpdatedMessage,
57
- SessionMessageType,
58
- } from './__generated__/graphql';
59
- import {
60
- AI_CONNECT_SESSION,
61
- AI_GET_TOKEN,
62
- AI_HANGUP_CALL,
63
- AI_START_DIAL_SESSION,
64
- AI_SET_PAUSED,
65
- REFRESH_TRANSCRIPT,
66
- } from './queries';
67
- import { createClient } from 'graphql-ws';
68
- import { VogentAudioConn, VogentDevice } from './devices/VogentDevice';
69
- import { VonageDevice } from './devices/VonageDevice';
70
- import { dialStatusIsComplete } from './utils';
71
- import { LivekitDevice } from './devices/LivekitDevice';
72
-
73
- export type Transcript = {
74
- /** The text of the transcript */
75
- text: string;
76
- /** The speaker of the transcript currently either 'HUMAN' or 'AI', or 'IVR' if IVR detection is enabled */
77
- speaker: string;
78
- }[];
79
-
80
- /**
81
- * VogentCall manages the lifecycle and state of a voice call session
82
- */
83
- export class VogentCall {
84
- /** Apollo GraphQL client instance for API communication */
85
- private client: ApolloClient<NormalizedCacheObject>;
86
-
87
- /** Unique identifier for the current session */
88
- private sessionId: string;
89
-
90
- /** Unique identifier for the current dial/call */
91
- private dialId: string;
92
-
93
- /** GraphQL subscription handle */
94
- private subscription?: ObservableSubscription;
95
-
96
- /** Base URL for the API endpoints */
97
- private baseUrl: string;
98
-
99
- /** Current dial/call state */
100
- private dial?: Dial;
101
-
102
- /** Array of event handlers for status changes */
103
- private _handlers: {
104
- ev: 'status';
105
- fn: (...args: any[]) => void;
106
- }[];
107
-
108
- /**
109
- * Creates a new VogentCall instance
110
- * @param dialDetails - Object containing session details and authentication, retrieved from the Vogent server API
111
- * @param dialDetails.sessionId - Unique session identifier
112
- * @param dialDetails.dialId - Unique dial/call identifier
113
- * @param dialDetails.token - Authentication token
114
- * @param config - Configuration options
115
- * @param config.baseUrl - API base URL (defaults to 'https://api.vogent.ai')
116
- */
117
- constructor(
118
- dialDetails: {
119
- sessionId: string;
120
- dialId: string;
121
- token: string;
122
- },
123
- config: {
124
- baseUrl: string;
125
- } = {
126
- baseUrl: 'https://api.vogent.ai',
127
- }
128
- ) {
129
- this._handlers = [];
130
- this.sessionId = dialDetails.sessionId;
131
- this.dialId = dialDetails.dialId;
132
- const token = dialDetails.token;
133
-
134
- const authLink = setContext((_, { headers }) => {
135
- return {
136
- headers: {
137
- ...headers,
138
- Authorization: `Bearer ${token}`,
139
- },
140
- };
141
- });
142
-
143
- this.baseUrl = config.baseUrl;
144
-
145
- const httpLink = createHttpLink({
146
- uri: `${this.baseUrl}/query`,
147
- headers: {
148
- Authorization: `Bearer ${token}`,
149
- },
150
- });
151
-
152
- const wsBaseUrl = this.baseUrl.replace('https://', 'wss://').replace('http://', 'ws://');
153
-
154
- const wsLink = new GraphQLWsLink(
155
- createClient({
156
- url: `${wsBaseUrl}/query`,
157
- connectionParams: () => ({
158
- authToken: token,
159
- }),
160
- })
161
- );
162
-
163
- const splitLink = split(
164
- ({ query }) => {
165
- const definition = getMainDefinition(query);
166
- return definition.kind === 'OperationDefinition' && definition.operation === 'subscription';
167
- },
168
- wsLink,
169
- // @ts-ignore
170
- authLink.concat(httpLink)
171
- );
172
-
173
- this.client = new ApolloClient({
174
- cache: new InMemoryCache(),
175
- link: splitLink,
176
- });
177
- }
178
-
179
- /**
180
- * Registers an event handler for status changes
181
- * @param ev - Event type ('status')
182
- * - status: called when the dial status changes, see docs.vogent.ai for more details
183
- * @param fn - Callback function to handle the event
184
- */
185
- on(ev: 'status', fn: (...args: any[]) => void) {
186
- this._handlers.push({
187
- ev,
188
- fn,
189
- });
190
- }
191
-
192
- /**
193
- * Subscribes to transcript updates for the current call
194
- * @param fn - Callback function that receives transcript updates
195
- * @returns Function to unsubscribe from transcript updates
196
- */
197
- monitorTranscript(fn: (transcript: Transcript) => void): () => void {
198
- const subscription = this.client
199
- .subscribe({
200
- query: REFRESH_TRANSCRIPT,
201
- variables: {
202
- dialId: this.dialId,
203
- },
204
- })
205
- .subscribe(({ data }) => {
206
- console.log('monitorTranscript', data);
207
-
208
- if (!data?.watchTranscript) {
209
- return;
210
- }
211
-
212
- fn(
213
- data.watchTranscript.map((t) => ({
214
- text: t.text,
215
- speaker: t.speaker,
216
- }))
217
- );
218
- });
219
-
220
- return () => {
221
- subscription.unsubscribe();
222
- };
223
- }
224
-
225
- /**
226
- * Internal method to update dial state and trigger status handlers
227
- * @param dial - Updated dial information
228
- */
229
- private updateDial(dial: Dial) {
230
- if (!this.dial || dial.status !== this.dial.status) {
231
- this._handlers.forEach((h) => {
232
- h.fn(dial.status);
233
- });
234
- } else {
235
- return;
236
- }
237
-
238
- if (dialStatusIsComplete(dial.status)) {
239
- this.subscription?.unsubscribe();
240
- }
241
-
242
- this.dial = {
243
- ...this.dial,
244
- ...dial,
245
- };
246
- }
247
-
248
- /**
249
- * Establishes audio connection for the call
250
- * @param liveListen - Whether to enable live listening mode. This should be set to true for monitoring legs (e.g. humans that are listening
251
- * to the call who the AI should not interact with.)
252
- * @returns Promise resolving to audio connection handle
253
- */
254
- async connectAudio(liveListen = false): Promise<VogentAudioConn> {
255
- const token = await this.client.mutate({
256
- mutation: AI_GET_TOKEN,
257
- variables: {
258
- input: {
259
- type: BrowserDialTokenType.DialSession,
260
- dialSessionId: this.sessionId,
261
- liveListen: liveListen,
262
- },
263
- },
264
- });
265
-
266
- let d: VogentDevice;
267
- if (token.data!.browserDialToken.telephonyProvider === 'livekit') {
268
- d = await LivekitDevice.getDevice(
269
- token.data!.browserDialToken.token,
270
- token.data!.browserDialToken.url ?? ''
271
- );
272
- } else {
273
- d = await VonageDevice.getDevice(token.data!.browserDialToken.token, true);
274
- }
275
-
276
- const c = await d.connect({
277
- params: { EltoDialSessionID: this.sessionId, LiveListen: liveListen, DialID: this.dialId },
278
- });
279
-
280
- return c;
281
- }
282
-
283
- /**
284
- * Starts the call session. Does not connect audio, you must call connectAudio() to do so.
285
- */
286
- async start() {
287
- this.subscription = this.client
288
- .subscribe({
289
- query: AI_CONNECT_SESSION,
290
- variables: {
291
- sessionId: this.sessionId,
292
- },
293
- })
294
- .subscribe(({ data }) => {
295
- switch (data?.connectSession.messageType) {
296
- case SessionMessageType.GlobalCallConnect:
297
- this.client.mutate({
298
- mutation: AI_START_DIAL_SESSION,
299
- variables: {
300
- sessionId: this.sessionId,
301
- },
302
- });
303
-
304
- break;
305
- case SessionMessageType.SessionContactUpdate: {
306
- const content = data?.connectSession.content as DialsUpdatedMessage;
307
- if (content.dials.length != 1) {
308
- break;
309
- }
310
-
311
- this.updateDial(content.dials[0]);
312
- }
313
- }
314
- });
315
- }
316
-
317
- /**
318
- * Sets the pause state of the AI
319
- * @param paused - Whether to pause the AI or not.
320
- */
321
- async setPaused(paused: boolean) {
322
- if (!this.dialId) {
323
- return;
324
- }
325
-
326
- await this.client.mutate({
327
- mutation: AI_SET_PAUSED,
328
- variables: {
329
- dialId: this.dialId,
330
- pauseStatus: paused,
331
- },
332
- });
333
- }
334
-
335
- /**
336
- * Ends the current call
337
- */
338
- async hangup() {
339
- if (!this.dialId) {
340
- return;
341
- }
342
-
343
- await this.client.mutate({
344
- mutation: AI_HANGUP_CALL,
345
- variables: {
346
- dialId: this.dialId,
347
- },
348
- });
349
- }
350
- }
@@ -1,68 +0,0 @@
1
- /* eslint-disable */
2
- import * as types from './graphql';
3
- import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
4
-
5
- /**
6
- * Map of all GraphQL operations in the project.
7
- *
8
- * This map has several performance disadvantages:
9
- * 1. It is not tree-shakeable, so it will include all operations in the project.
10
- * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle.
11
- * 3. It does not support dead code elimination, so it will add unused operations.
12
- *
13
- * Therefore it is highly recommended to use the babel or swc plugin for production.
14
- * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size
15
- */
16
- const documents = {
17
- "\n mutation StartDialSession($sessionId: ID!) {\n startDialSession(dialSessionId: $sessionId)\n }\n": types.StartDialSessionDocument,
18
- "\n mutation HangupCall($dialId: ID!, $dropVoicemail: Boolean, $transferNumber: String) {\n hangupCall(dialId: $dialId, dropVoicemail: $dropVoicemail, transferNumber: $transferNumber)\n }\n": types.HangupCallDocument,
19
- "\n mutation SetPaused($dialId: ID!, $pauseStatus: Boolean!) {\n pauseAI(dialId: $dialId, pauseStatus: $pauseStatus) {\n id\n }\n }\n": types.SetPausedDocument,
20
- "\n subscription RefreshTranscript($dialId: ID!) {\n watchTranscript(dialId: $dialId) {\n speaker\n text\n detailType\n }\n }\n": types.RefreshTranscriptDocument,
21
- "\n mutation BrowserDialToken($input: BrowserDialTokenInput!) {\n browserDialToken(input: $input) {\n token\n iceConfig\n telephonyProvider\n url\n }\n }\n": types.BrowserDialTokenDocument,
22
- "\n subscription ConnectSession($sessionId: ID!) {\n connectSession(sessionId: $sessionId) {\n messageType\n content {\n __typename\n ... on DialsUpdatedMessage {\n contactId\n dials {\n id\n status\n answerType\n callDispositionId\n systemResultType\n toNumber\n }\n contactComplete\n }\n ... on DialConnectMessage {\n dialId\n }\n ... on SessionUpdatedMessage {\n dialSession {\n id\n status\n }\n reason\n }\n }\n }\n }\n": types.ConnectSessionDocument,
23
- };
24
-
25
- /**
26
- * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
27
- *
28
- *
29
- * @example
30
- * ```ts
31
- * const query = gql(`query GetUser($id: ID!) { user(id: $id) { name } }`);
32
- * ```
33
- *
34
- * The query argument is unknown!
35
- * Please regenerate the types.
36
- */
37
- export function gql(source: string): unknown;
38
-
39
- /**
40
- * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
41
- */
42
- export function gql(source: "\n mutation StartDialSession($sessionId: ID!) {\n startDialSession(dialSessionId: $sessionId)\n }\n"): (typeof documents)["\n mutation StartDialSession($sessionId: ID!) {\n startDialSession(dialSessionId: $sessionId)\n }\n"];
43
- /**
44
- * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
45
- */
46
- export function gql(source: "\n mutation HangupCall($dialId: ID!, $dropVoicemail: Boolean, $transferNumber: String) {\n hangupCall(dialId: $dialId, dropVoicemail: $dropVoicemail, transferNumber: $transferNumber)\n }\n"): (typeof documents)["\n mutation HangupCall($dialId: ID!, $dropVoicemail: Boolean, $transferNumber: String) {\n hangupCall(dialId: $dialId, dropVoicemail: $dropVoicemail, transferNumber: $transferNumber)\n }\n"];
47
- /**
48
- * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
49
- */
50
- export function gql(source: "\n mutation SetPaused($dialId: ID!, $pauseStatus: Boolean!) {\n pauseAI(dialId: $dialId, pauseStatus: $pauseStatus) {\n id\n }\n }\n"): (typeof documents)["\n mutation SetPaused($dialId: ID!, $pauseStatus: Boolean!) {\n pauseAI(dialId: $dialId, pauseStatus: $pauseStatus) {\n id\n }\n }\n"];
51
- /**
52
- * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
53
- */
54
- export function gql(source: "\n subscription RefreshTranscript($dialId: ID!) {\n watchTranscript(dialId: $dialId) {\n speaker\n text\n detailType\n }\n }\n"): (typeof documents)["\n subscription RefreshTranscript($dialId: ID!) {\n watchTranscript(dialId: $dialId) {\n speaker\n text\n detailType\n }\n }\n"];
55
- /**
56
- * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
57
- */
58
- export function gql(source: "\n mutation BrowserDialToken($input: BrowserDialTokenInput!) {\n browserDialToken(input: $input) {\n token\n iceConfig\n telephonyProvider\n url\n }\n }\n"): (typeof documents)["\n mutation BrowserDialToken($input: BrowserDialTokenInput!) {\n browserDialToken(input: $input) {\n token\n iceConfig\n telephonyProvider\n url\n }\n }\n"];
59
- /**
60
- * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
61
- */
62
- export function gql(source: "\n subscription ConnectSession($sessionId: ID!) {\n connectSession(sessionId: $sessionId) {\n messageType\n content {\n __typename\n ... on DialsUpdatedMessage {\n contactId\n dials {\n id\n status\n answerType\n callDispositionId\n systemResultType\n toNumber\n }\n contactComplete\n }\n ... on DialConnectMessage {\n dialId\n }\n ... on SessionUpdatedMessage {\n dialSession {\n id\n status\n }\n reason\n }\n }\n }\n }\n"): (typeof documents)["\n subscription ConnectSession($sessionId: ID!) {\n connectSession(sessionId: $sessionId) {\n messageType\n content {\n __typename\n ... on DialsUpdatedMessage {\n contactId\n dials {\n id\n status\n answerType\n callDispositionId\n systemResultType\n toNumber\n }\n contactComplete\n }\n ... on DialConnectMessage {\n dialId\n }\n ... on SessionUpdatedMessage {\n dialSession {\n id\n status\n }\n reason\n }\n }\n }\n }\n"];
63
-
64
- export function gql(source: string) {
65
- return (documents as any)[source] ?? {};
66
- }
67
-
68
- export type DocumentType<TDocumentNode extends DocumentNode<any, any>> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;