phonic 0.32.13 → 0.32.15

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 (47) hide show
  1. package/dist/cjs/BaseClient.js +2 -2
  2. package/dist/cjs/api/resources/agents/client/requests/UpdateAgentRequest.d.ts +1 -1
  3. package/dist/cjs/api/resources/tools/client/requests/CreateToolRequest.d.ts +2 -0
  4. package/dist/cjs/api/resources/tools/client/requests/UpdateToolRequest.d.ts +2 -0
  5. package/dist/cjs/api/resources/tts/client/requests/StreamTtsRequest.d.ts +6 -0
  6. package/dist/cjs/api/types/Agent.d.ts +1 -1
  7. package/dist/cjs/api/types/BuiltInToolConfig.d.ts +1 -1
  8. package/dist/cjs/api/types/BuiltInToolConfigs.d.ts +5 -2
  9. package/dist/cjs/api/types/BuiltInToolDefinition.d.ts +8 -2
  10. package/dist/cjs/api/types/BuiltInToolDefinition.js +1 -0
  11. package/dist/cjs/api/types/ChooseNotToRespondToolConfig.d.ts +7 -0
  12. package/dist/cjs/api/types/ChooseNotToRespondToolConfig.js +3 -0
  13. package/dist/cjs/api/types/CreateAgentRequest.d.ts +1 -1
  14. package/dist/cjs/api/types/OutboundCallConfig.d.ts +1 -1
  15. package/dist/cjs/api/types/Tool.d.ts +2 -0
  16. package/dist/cjs/api/types/index.d.ts +1 -0
  17. package/dist/cjs/api/types/index.js +1 -0
  18. package/dist/cjs/custom/ReconnectableConversationsSocket.d.ts +16 -0
  19. package/dist/cjs/custom/ReconnectableConversationsSocket.js +127 -11
  20. package/dist/cjs/version.d.ts +1 -1
  21. package/dist/cjs/version.js +1 -1
  22. package/dist/esm/BaseClient.mjs +2 -2
  23. package/dist/esm/api/resources/agents/client/requests/UpdateAgentRequest.d.mts +1 -1
  24. package/dist/esm/api/resources/tools/client/requests/CreateToolRequest.d.mts +2 -0
  25. package/dist/esm/api/resources/tools/client/requests/UpdateToolRequest.d.mts +2 -0
  26. package/dist/esm/api/resources/tts/client/requests/StreamTtsRequest.d.mts +6 -0
  27. package/dist/esm/api/types/Agent.d.mts +1 -1
  28. package/dist/esm/api/types/BuiltInToolConfig.d.mts +1 -1
  29. package/dist/esm/api/types/BuiltInToolConfigs.d.mts +5 -2
  30. package/dist/esm/api/types/BuiltInToolDefinition.d.mts +8 -2
  31. package/dist/esm/api/types/BuiltInToolDefinition.mjs +1 -0
  32. package/dist/esm/api/types/ChooseNotToRespondToolConfig.d.mts +7 -0
  33. package/dist/esm/api/types/ChooseNotToRespondToolConfig.mjs +2 -0
  34. package/dist/esm/api/types/CreateAgentRequest.d.mts +1 -1
  35. package/dist/esm/api/types/OutboundCallConfig.d.mts +1 -1
  36. package/dist/esm/api/types/Tool.d.mts +2 -0
  37. package/dist/esm/api/types/index.d.mts +1 -0
  38. package/dist/esm/api/types/index.mjs +1 -0
  39. package/dist/esm/custom/ReconnectableConversationsSocket.d.mts +16 -0
  40. package/dist/esm/custom/ReconnectableConversationsSocket.mjs +127 -11
  41. package/dist/esm/version.d.mts +1 -1
  42. package/dist/esm/version.mjs +1 -1
  43. package/package.json +1 -1
  44. package/dist/index.d.mts +0 -240
  45. package/dist/index.d.ts +0 -240
  46. package/dist/index.js +0 -347
  47. package/dist/index.mjs +0 -310
@@ -97,7 +97,7 @@ export declare namespace OutboundCallConfig {
97
97
  }
98
98
  type Tools = Tools.Item[];
99
99
  namespace Tools {
100
- type Item = "keypad_input" | "natural_conversation_ending"
100
+ type Item = "keypad_input" | "natural_conversation_ending" | "choose_not_to_respond"
101
101
  /**
102
102
  * Custom tool */
103
103
  | string;
@@ -48,6 +48,8 @@ export interface Tool {
48
48
  require_speech_before_tool_call?: boolean | undefined;
49
49
  /** For built_in_natural_conversation_ending and built_in_keypad_input tools. Whether the agent must speak before calling the tool ("required"), the model decides ("optional"), or the agent must stay silent ("suppressed"). Not used by other tool types. */
50
50
  speech_before_tool_call?: Tool.SpeechBeforeToolCall | undefined;
51
+ /** For built_in_choose_not_to_respond tools. Number of seconds to wait after the tool fires before the agent speaks a follow-up if the user stays silent. When null, the agent stays silent (default). Not used by other tool types. */
52
+ respond_after_sec?: (number | null) | undefined;
51
53
  /** If true, the agent will wait to finish speaking before executing the tool. This is only available for custom_webhook and custom_websocket tools. */
52
54
  wait_for_speech_before_tool_call?: boolean | undefined;
53
55
  /** When true, forbids the agent from speaking after executing the tool. Available for custom_context, custom_webhook and custom_websocket tools. */
@@ -13,6 +13,7 @@ export * from "./BasicError.mjs";
13
13
  export * from "./BuiltInToolConfig.mjs";
14
14
  export * from "./BuiltInToolConfigs.mjs";
15
15
  export * from "./BuiltInToolDefinition.mjs";
16
+ export * from "./ChooseNotToRespondToolConfig.mjs";
16
17
  export * from "./ConfigOptions.mjs";
17
18
  export * from "./ConfigPayload.mjs";
18
19
  export * from "./Conversation.mjs";
@@ -13,6 +13,7 @@ export * from "./BasicError.mjs";
13
13
  export * from "./BuiltInToolConfig.mjs";
14
14
  export * from "./BuiltInToolConfigs.mjs";
15
15
  export * from "./BuiltInToolDefinition.mjs";
16
+ export * from "./ChooseNotToRespondToolConfig.mjs";
16
17
  export * from "./ConfigOptions.mjs";
17
18
  export * from "./ConfigPayload.mjs";
18
19
  export * from "./Conversation.mjs";
@@ -27,6 +27,11 @@ type EventHandlers = {
27
27
  * with a terminal close code (4800 session expired, 4801 invalid state),
28
28
  * the safety cap is reached, or the user calls close().
29
29
  *
30
+ * A reconnectable close is not surfaced to the user's close handler while the
31
+ * reconnect is in flight. The close is emitted only when reconnection has
32
+ * failed, meaning the conversation is closing. Closes that are not
33
+ * reconnectable (1000, 4000, etc) are not affected and will pass through.
34
+ *
30
35
  * Uses composition rather than inheritance to avoid coupling to the parent's
31
36
  * private event handler registration or ReconnectingWebSocket internals.
32
37
  */
@@ -41,6 +46,8 @@ export declare class ReconnectableConversationsSocket {
41
46
  private _cleanupWireListeners;
42
47
  private _pendingReconnect;
43
48
  private _pendingReplacement;
49
+ private _lastSuppressedClose;
50
+ private _gaveUp;
44
51
  constructor(args: ReconnectableConversationsSocketArgs);
45
52
  /** The conversation ID captured from the server's conversation_created message. */
46
53
  get conversationId(): string | null;
@@ -67,9 +74,18 @@ export declare class ReconnectableConversationsSocket {
67
74
  connect(): never;
68
75
  close(): void;
69
76
  waitForOpen(): Promise<core.ReconnectingWebSocket>;
77
+ private _willReconnectAfter;
78
+ private _giveUp;
70
79
  private _getReconnectDelay;
71
80
  /** Schedule a reconnection attempt after backoff delay. */
72
81
  private _scheduleReconnect;
82
+ /** Settle as soon as the abort signal fires rather than waiting on the
83
+ * factory, whose promise is caller-supplied (it awaits fresh auth) and
84
+ * may never settle — the suppressed close would stay hidden forever.
85
+ * Resolves null when aborted; a socket arriving afterwards is closed
86
+ * rather than leaked. The listener is removed once the factory settles,
87
+ * so a long-lived conversation does not accumulate them on the signal. */
88
+ private _createSocketOrAbort;
73
89
  /** Perform the actual reconnection attempt. */
74
90
  private _doReconnect;
75
91
  private _wireInner;
@@ -44,6 +44,11 @@ const MAX_RECONNECT_ATTEMPTS = 10;
44
44
  * with a terminal close code (4800 session expired, 4801 invalid state),
45
45
  * the safety cap is reached, or the user calls close().
46
46
  *
47
+ * A reconnectable close is not surfaced to the user's close handler while the
48
+ * reconnect is in flight. The close is emitted only when reconnection has
49
+ * failed, meaning the conversation is closing. Closes that are not
50
+ * reconnectable (1000, 4000, etc) are not affected and will pass through.
51
+ *
47
52
  * Uses composition rather than inheritance to avoid coupling to the parent's
48
53
  * private event handler registration or ReconnectingWebSocket internals.
49
54
  */
@@ -56,6 +61,8 @@ export class ReconnectableConversationsSocket {
56
61
  this._cleanupWireListeners = null;
57
62
  this._pendingReconnect = null;
58
63
  this._pendingReplacement = false;
64
+ this._lastSuppressedClose = null;
65
+ this._gaveUp = false;
59
66
  this._createReconnectSocket = args.createReconnectSocket;
60
67
  this._abortSignal = args.abortSignal != undefined ? args.abortSignal : null;
61
68
  this._inner = new ConversationsSocket({ socket: args.socket });
@@ -134,15 +141,36 @@ export class ReconnectableConversationsSocket {
134
141
  clearTimeout(this._pendingReconnect);
135
142
  this._pendingReconnect = null;
136
143
  }
144
+ // Close before detaching: ConversationsSocket.close() synthesizes a
145
+ // 1000 close event, and a user-initiated close should still surface one.
146
+ this._inner.close();
137
147
  (_a = this._cleanupWireListeners) === null || _a === void 0 ? void 0 : _a.call(this);
138
148
  this._cleanupWireListeners = null;
139
- this._inner.close();
140
149
  }
141
150
  waitForOpen() {
142
151
  return __awaiter(this, void 0, void 0, function* () {
143
152
  return this._inner.waitForOpen();
144
153
  });
145
154
  }
155
+ _willReconnectAfter(event) {
156
+ return (!this._isClosed
157
+ && !this._gaveUp
158
+ && this._conversationId !== null
159
+ && isReconnectableClose(event.code, event.reason));
160
+ }
161
+ _giveUp() {
162
+ var _a, _b;
163
+ this._pendingReplacement = false;
164
+ if (this._gaveUp || this._isClosed) {
165
+ return;
166
+ }
167
+ this._gaveUp = true;
168
+ const suppressed = this._lastSuppressedClose;
169
+ this._lastSuppressedClose = null;
170
+ if (suppressed !== null) {
171
+ (_b = (_a = this._handlers).close) === null || _b === void 0 ? void 0 : _b.call(_a, suppressed);
172
+ }
173
+ }
146
174
  _getReconnectDelay() {
147
175
  // Exponential backoff: 500ms, 1s, 2s, 4s, capped at 5s
148
176
  const delay = BASE_RECONNECT_DELAY_MS * Math.pow(2, this._reconnectAttempts - 1);
@@ -151,12 +179,18 @@ export class ReconnectableConversationsSocket {
151
179
  /** Schedule a reconnection attempt after backoff delay. */
152
180
  _scheduleReconnect() {
153
181
  var _a, _b, _c;
154
- if (this._isClosed || this._conversationId === null || ((_a = this._abortSignal) === null || _a === void 0 ? void 0 : _a.aborted)) {
182
+ // With no conversation the close was never suppressed, so unlike the
183
+ // branches below there is nothing to emit.
184
+ if (this._isClosed || this._conversationId === null) {
185
+ return;
186
+ }
187
+ if ((_a = this._abortSignal) === null || _a === void 0 ? void 0 : _a.aborted) {
188
+ this._giveUp();
155
189
  return;
156
190
  }
157
191
  if (this._reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
158
- this._pendingReplacement = false;
159
192
  (_c = (_b = this._handlers).error) === null || _c === void 0 ? void 0 : _c.call(_b, new Error("Max reconnect attempts reached"));
193
+ this._giveUp();
160
194
  return;
161
195
  }
162
196
  // Clear any existing timer to prevent orphaned timeouts
@@ -167,24 +201,70 @@ export class ReconnectableConversationsSocket {
167
201
  const delay = this._getReconnectDelay();
168
202
  this._pendingReplacement = true;
169
203
  this._pendingReconnect = setTimeout(() => {
204
+ var _a;
170
205
  this._pendingReconnect = null;
171
206
  if (this._isClosed) {
172
207
  this._pendingReplacement = false;
173
208
  return;
174
209
  }
210
+ if ((_a = this._abortSignal) === null || _a === void 0 ? void 0 : _a.aborted) {
211
+ this._giveUp();
212
+ return;
213
+ }
175
214
  void this._doReconnect();
176
215
  }, delay);
177
216
  }
217
+ /** Settle as soon as the abort signal fires rather than waiting on the
218
+ * factory, whose promise is caller-supplied (it awaits fresh auth) and
219
+ * may never settle — the suppressed close would stay hidden forever.
220
+ * Resolves null when aborted; a socket arriving afterwards is closed
221
+ * rather than leaked. The listener is removed once the factory settles,
222
+ * so a long-lived conversation does not accumulate them on the signal. */
223
+ _createSocketOrAbort(created) {
224
+ const signal = this._abortSignal;
225
+ if (signal === null) {
226
+ return created;
227
+ }
228
+ const discardLate = () => {
229
+ void created.then((socket) => socket.close()).catch(() => undefined);
230
+ };
231
+ if (signal.aborted) {
232
+ discardLate();
233
+ return Promise.resolve(null);
234
+ }
235
+ return new Promise((resolve, reject) => {
236
+ const onAbort = () => {
237
+ discardLate();
238
+ resolve(null);
239
+ };
240
+ signal.addEventListener("abort", onAbort, { once: true });
241
+ created.then((socket) => {
242
+ signal.removeEventListener("abort", onAbort);
243
+ resolve(socket);
244
+ }, (error) => {
245
+ signal.removeEventListener("abort", onAbort);
246
+ reject(error);
247
+ });
248
+ });
249
+ }
178
250
  /** Perform the actual reconnection attempt. */
179
251
  _doReconnect() {
180
252
  return __awaiter(this, void 0, void 0, function* () {
181
253
  var _a, _b;
182
254
  try {
183
255
  const created = this._createReconnectSocket(this._conversationId);
184
- const newRawSocket = created instanceof Promise ? yield created : created;
256
+ const newRawSocket = created instanceof Promise ? yield this._createSocketOrAbort(created) : created;
257
+ if (newRawSocket === null) {
258
+ // Aborted while the factory was still in flight.
259
+ this._giveUp();
260
+ return;
261
+ }
185
262
  if (this._isClosed || ((_a = this._abortSignal) === null || _a === void 0 ? void 0 : _a.aborted)) {
186
263
  this._pendingReplacement = false;
187
264
  newRawSocket.close();
265
+ if (!this._isClosed) {
266
+ this._giveUp();
267
+ }
188
268
  return;
189
269
  }
190
270
  // Clean up the old socket: remove our custom listeners and close
@@ -197,7 +277,7 @@ export class ReconnectableConversationsSocket {
197
277
  catch ( /* already closed from 1006 */_c) { /* already closed from 1006 */ }
198
278
  const newInner = new ConversationsSocket({ socket: newRawSocket });
199
279
  this._inner = newInner;
200
- this._wireInner(newInner, newRawSocket);
280
+ this._wireInner(newInner, newRawSocket, true);
201
281
  }
202
282
  catch (_d) {
203
283
  this._pendingReplacement = false;
@@ -208,17 +288,41 @@ export class ReconnectableConversationsSocket {
208
288
  }
209
289
  });
210
290
  }
211
- _wireInner(inner, rawSocket) {
212
- // Forward events from the inner ConversationsSocket to user handlers.
213
- // Clear _pendingReplacement before calling the user's open handler
214
- // so that sends inside the handler are not silently dropped.
291
+ _wireInner(inner, rawSocket, isReplacement = false) {
292
+ // A replacement that closes before ever opening failed at the transport
293
+ // level, and its code says nothing about why: ReconnectingWebSocket
294
+ // synthesizes 1000 for connect errors and timeouts (_handleError ->
295
+ // _disconnect). Read it as a failed attempt rather than as a close.
296
+ // _isClosed excluded: close() also reaches this via the synthesized
297
+ // 1000, and a user-initiated close is a close, not a failed attempt.
298
+ let opened = false;
299
+ const isFailedAttempt = () => isReplacement && !opened && !this._isClosed;
300
+ // Clearing _pendingReplacement before the user's open handler keeps
301
+ // sends made inside that handler from being dropped.
215
302
  inner.on("open", () => {
216
303
  var _a, _b;
304
+ opened = true;
217
305
  this._pendingReplacement = false;
306
+ this._lastSuppressedClose = null;
218
307
  (_b = (_a = this._handlers).open) === null || _b === void 0 ? void 0 : _b.call(_a);
219
308
  });
220
309
  inner.on("message", (msg) => { var _a, _b; return (_b = (_a = this._handlers).message) === null || _b === void 0 ? void 0 : _b.call(_a, msg); });
221
- inner.on("close", (ev) => { var _a, _b; return (_b = (_a = this._handlers).close) === null || _b === void 0 ? void 0 : _b.call(_a, ev); });
310
+ // ConversationsSocket registers this in its constructor, so it runs
311
+ // before the rawSocket close listener below that schedules the
312
+ // reconnect — the decision cannot be read off reconnect state here.
313
+ inner.on("close", (ev) => {
314
+ var _a, _b;
315
+ // Leave _lastSuppressedClose holding the original drop, so _giveUp
316
+ // reports what went wrong rather than this attempt's code.
317
+ if (isFailedAttempt()) {
318
+ return;
319
+ }
320
+ if (this._willReconnectAfter(ev)) {
321
+ this._lastSuppressedClose = ev;
322
+ return;
323
+ }
324
+ (_b = (_a = this._handlers).close) === null || _b === void 0 ? void 0 : _b.call(_a, ev);
325
+ });
222
326
  inner.on("error", (err) => { var _a, _b; return (_b = (_a = this._handlers).error) === null || _b === void 0 ? void 0 : _b.call(_a, err); });
223
327
  // Intercept raw messages to capture conversation_id and reset reconnect counter
224
328
  const onMessage = (event) => {
@@ -238,8 +342,15 @@ export class ReconnectableConversationsSocket {
238
342
  // ignore — inner socket handles parse errors
239
343
  }
240
344
  };
345
+ // After giving up this is a plain pass-through: the close was already
346
+ // forwarded above, and retrying would repeat the give-up error.
241
347
  const onClose = (event) => {
242
- if (this._isClosed) {
348
+ if (this._isClosed || this._gaveUp) {
349
+ return;
350
+ }
351
+ if (isFailedAttempt()) {
352
+ rawSocket.close();
353
+ this._scheduleReconnect();
243
354
  return;
244
355
  }
245
356
  if (isReconnectableClose(event.code, event.reason) && this._conversationId !== null) {
@@ -258,6 +369,11 @@ export class ReconnectableConversationsSocket {
258
369
  rawSocket.addEventListener("message", onMessage);
259
370
  rawSocket.addEventListener("close", onClose);
260
371
  this._cleanupWireListeners = () => {
372
+ // ConversationsSocket.close() synthesizes a 1000 close event, so a
373
+ // discarded socket would otherwise report a spurious normal closure.
374
+ for (const event of ["open", "message", "close", "error"]) {
375
+ inner.on(event, undefined);
376
+ }
261
377
  rawSocket.removeEventListener("message", onMessage);
262
378
  rawSocket.removeEventListener("close", onClose);
263
379
  };
@@ -1 +1 @@
1
- export declare const SDK_VERSION = "0.32.13";
1
+ export declare const SDK_VERSION = "0.32.15";
@@ -1 +1 @@
1
- export const SDK_VERSION = "0.32.13";
1
+ export const SDK_VERSION = "0.32.15";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phonic",
3
- "version": "0.32.13",
3
+ "version": "0.32.15",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
package/dist/index.d.mts DELETED
@@ -1,240 +0,0 @@
1
- import WebSocket from 'ws';
2
-
3
- type PhonicConfig = {
4
- baseUrl?: string;
5
- headers?: Record<string, string>;
6
- __downstreamWebSocketUrl?: string;
7
- };
8
- type FetchOptions = {
9
- method: "GET";
10
- headers?: Record<string, string>;
11
- } | {
12
- method: "POST";
13
- headers?: Record<string, string>;
14
- body: string;
15
- };
16
- type DataOrError<T> = Promise<{
17
- data: T;
18
- error: null;
19
- } | {
20
- data: null;
21
- error: {
22
- message: string;
23
- code?: string;
24
- };
25
- }>;
26
- type ISODate = `${string}-${string}-${string}`;
27
- type ISODateTime$1 = `${string}Z`;
28
-
29
- type ISODateTime = `${string}Z`;
30
- type ConversationItem = {
31
- role: "user";
32
- item_idx: number;
33
- text: string;
34
- duration_ms: number;
35
- started_at: string;
36
- } | {
37
- role: "assistant";
38
- item_idx: number;
39
- text: string;
40
- voice_id: string;
41
- system_prompt: string;
42
- output_audio_speed: number;
43
- duration_ms: number;
44
- started_at: string;
45
- };
46
- type Conversation = {
47
- id: string;
48
- external_id: string | null;
49
- model: string;
50
- welcome_message: string | null;
51
- input_format: "pcm_44100" | "mulaw_8000";
52
- output_format: "pcm_44100" | "mulaw_8000";
53
- text: string;
54
- duration_ms: number;
55
- started_at: ISODateTime;
56
- ended_at: ISODateTime;
57
- items: Array<ConversationItem>;
58
- };
59
- type ConversationSuccessResponse = {
60
- conversation: Conversation;
61
- };
62
- type ConversationsSuccessResponse = {
63
- conversations: Array<Conversation>;
64
- };
65
-
66
- declare class Conversations {
67
- private readonly phonic;
68
- constructor(phonic: Phonic);
69
- get(id: string): DataOrError<ConversationSuccessResponse>;
70
- getByExternalId({ project, externalId, }: {
71
- project?: string;
72
- externalId: string;
73
- }): DataOrError<ConversationSuccessResponse>;
74
- list({ project, durationMin, durationMax, startedAtMin, startedAtMax, }: {
75
- project?: string;
76
- durationMin?: number;
77
- durationMax?: number;
78
- startedAtMin?: ISODate | ISODateTime$1;
79
- startedAtMax?: ISODate | ISODateTime$1;
80
- }): DataOrError<ConversationsSuccessResponse>;
81
- }
82
-
83
- type PhonicSTSConfig = {
84
- project: string;
85
- input_format: "pcm_44100" | "mulaw_8000";
86
- system_prompt?: string;
87
- welcome_message?: string;
88
- voice_id?: string;
89
- output_format?: "pcm_44100" | "mulaw_8000";
90
- enable_silent_audio_fallback?: boolean;
91
- experimental_params?: Record<string, unknown>;
92
- tools?: string[];
93
- vad_prebuffer_duration_ms?: number;
94
- vad_min_speech_duration_ms?: number;
95
- vad_min_silence_duration_ms?: number;
96
- vad_threshold?: number;
97
- };
98
- type PhonicSTSWebSocketResponseMessage = {
99
- type: "ready_to_start_conversation";
100
- } | {
101
- type: "input_text";
102
- text: string;
103
- } | {
104
- type: "audio_chunk";
105
- text: string;
106
- audio: string;
107
- } | {
108
- type: "is_user_speaking";
109
- isUserSpeaking: boolean;
110
- } | {
111
- type: "interrupted_response";
112
- interruptedResponse: string;
113
- } | {
114
- type: "assistant_ended_conversation";
115
- } | {
116
- type: "error";
117
- error: {
118
- message: string;
119
- code?: string;
120
- };
121
- param_errors?: {
122
- input_format?: string;
123
- system_prompt?: string;
124
- welcome_message?: string;
125
- voice_id?: string;
126
- output_format?: string;
127
- };
128
- };
129
- type OnMessageCallback = (message: PhonicSTSWebSocketResponseMessage) => void;
130
- type OnCloseCallback = (event: WebSocket.CloseEvent) => void;
131
- type OnErrorCallback = (event: WebSocket.ErrorEvent) => void;
132
- type PhonicSTSOutboundCallConfig = Omit<PhonicSTSConfig, "input_format" | "output_format">;
133
- type OutboundCallSuccessResponse = {
134
- success: true;
135
- };
136
-
137
- type PhonicSTSTwilioOutboundCallParams = {
138
- account_sid: string;
139
- api_key_sid: string;
140
- api_key_secret: string;
141
- from_phone_number: string;
142
- to_phone_number: string;
143
- };
144
- type PhonicSTSTwilioOutboundCallConfig = PhonicSTSOutboundCallConfig;
145
- type TwilioOutboundCallSuccessResponse = {
146
- success: true;
147
- callSid: string;
148
- };
149
-
150
- declare class Twilio {
151
- private readonly phonic;
152
- constructor(phonic: Phonic);
153
- outboundCall(params: PhonicSTSTwilioOutboundCallParams, config: PhonicSTSTwilioOutboundCallConfig): DataOrError<TwilioOutboundCallSuccessResponse>;
154
- }
155
-
156
- declare class PhonicSTSWebSocket {
157
- private readonly ws;
158
- private readonly config;
159
- private onMessageCallback;
160
- private onCloseCallback;
161
- private onErrorCallback;
162
- private buffer;
163
- private isOpen;
164
- constructor(ws: WebSocket, config: PhonicSTSConfig);
165
- onMessage(callback: OnMessageCallback): void;
166
- onClose(callback: OnCloseCallback): void;
167
- onError(callback: OnErrorCallback): void;
168
- audioChunk({ audio }: {
169
- audio: string;
170
- }): void;
171
- updateSystemPrompt({ systemPrompt }: {
172
- systemPrompt: string;
173
- }): void;
174
- setExternalId({ externalId }: {
175
- externalId: string;
176
- }): void;
177
- close(code?: number): void;
178
- }
179
-
180
- declare class SpeechToSpeech {
181
- private readonly phonic;
182
- readonly twilio: Twilio;
183
- constructor(phonic: Phonic);
184
- websocket(config: PhonicSTSConfig): PhonicSTSWebSocket;
185
- outboundCall(toPhoneNumber: string, config: PhonicSTSOutboundCallConfig): DataOrError<OutboundCallSuccessResponse>;
186
- }
187
-
188
- type Voice = {
189
- id: string;
190
- name: string;
191
- };
192
- type VoicesSuccessResponse = {
193
- voices: Array<Voice>;
194
- };
195
- type VoiceSuccessResponse = {
196
- voice: Voice;
197
- };
198
-
199
- declare class Voices {
200
- private readonly phonic;
201
- constructor(phonic: Phonic);
202
- list({ model }: {
203
- model: string;
204
- }): DataOrError<VoicesSuccessResponse>;
205
- get(id: string): DataOrError<VoiceSuccessResponse>;
206
- }
207
-
208
- declare class Phonic {
209
- readonly apiKey: string;
210
- readonly baseUrl: string;
211
- readonly __downstreamWebSocketUrl: string | null;
212
- readonly headers: Record<string, string>;
213
- readonly conversations: Conversations;
214
- readonly voices: Voices;
215
- readonly sts: SpeechToSpeech;
216
- constructor(apiKey: string, config?: PhonicConfig);
217
- fetchRequest<T>(path: string, options: FetchOptions): DataOrError<T>;
218
- get<T>(path: string): Promise<{
219
- data: null;
220
- error: {
221
- message: string;
222
- code?: string;
223
- };
224
- } | {
225
- data: T;
226
- error: null;
227
- }>;
228
- post<T>(path: string, body: Record<string, unknown>, headers?: Record<string, string>): Promise<{
229
- data: null;
230
- error: {
231
- message: string;
232
- code?: string;
233
- };
234
- } | {
235
- data: T;
236
- error: null;
237
- }>;
238
- }
239
-
240
- export { Phonic, type PhonicSTSConfig, PhonicSTSWebSocket };