phonic 0.31.8 → 0.31.10

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 (119) hide show
  1. package/README.md +1 -0
  2. package/dist/cjs/BaseClient.js +2 -2
  3. package/dist/cjs/Client.d.ts +9 -1
  4. package/dist/cjs/Client.js +1 -1
  5. package/dist/cjs/api/resources/agents/client/Client.d.ts +3 -0
  6. package/dist/cjs/api/resources/agents/client/Client.js +3 -0
  7. package/dist/cjs/api/resources/agents/client/requests/AgentsCreateRequest.d.ts +3 -0
  8. package/dist/cjs/api/resources/agents/client/requests/UpdateAgentRequest.d.ts +3 -0
  9. package/dist/cjs/api/resources/agents/client/requests/UpsertAgentRequest.d.ts +1 -0
  10. package/dist/cjs/api/resources/conversations/client/Client.d.ts +8 -1
  11. package/dist/cjs/api/resources/conversations/client/Client.js +37 -3
  12. package/dist/cjs/api/resources/conversations/client/Socket.d.ts +2 -1
  13. package/dist/cjs/api/resources/conversations/client/Socket.js +4 -0
  14. package/dist/cjs/api/resources/conversations/client/requests/ConversationsSipOutboundCallRequest.d.ts +2 -0
  15. package/dist/cjs/api/resources/conversations/client/requests/OutboundCallRequest.d.ts +5 -1
  16. package/dist/cjs/api/resources/conversations/types/ConversationsOutboundCallResponse.d.ts +2 -4
  17. package/dist/cjs/api/resources/conversations/types/ConversationsSipOutboundCallResponse.d.ts +2 -6
  18. package/dist/cjs/api/types/Agent.d.ts +2 -0
  19. package/dist/cjs/api/types/ConfigOptions.d.ts +94 -0
  20. package/dist/cjs/api/types/ConfigOptions.js +32 -0
  21. package/dist/cjs/api/types/ConfigPayload.d.ts +2 -88
  22. package/dist/cjs/api/types/ConfigPayload.js +0 -29
  23. package/dist/cjs/api/types/Conversation.d.ts +2 -0
  24. package/dist/cjs/api/types/CreateAgentRequest.d.ts +2 -0
  25. package/dist/cjs/api/types/OutboundCallConfig.d.ts +2 -0
  26. package/dist/cjs/api/types/OutboundCallInitiatedResponse.d.ts +6 -0
  27. package/dist/cjs/api/types/{InterruptedResponsePayload.js → OutboundCallInitiatedResponse.js} +1 -3
  28. package/dist/cjs/api/types/OutboundDryRunResponse.d.ts +6 -0
  29. package/dist/cjs/api/{resources/agents/client/requests/AgentsRemoveCustomPhoneNumberRequest.js → types/OutboundDryRunResponse.js} +1 -3
  30. package/dist/cjs/api/types/ResetPayload.d.ts +5 -0
  31. package/dist/cjs/api/types/{AudioFinishedPayload.js → ResetPayload.js} +1 -3
  32. package/dist/cjs/api/types/SipOutboundCallInitiatedResponse.d.ts +8 -0
  33. package/dist/cjs/api/{resources/agents/types/AgentsRemoveCustomPhoneNumberResponse.js → types/SipOutboundCallInitiatedResponse.js} +1 -3
  34. package/dist/cjs/api/types/SipOutboundDryRunResponse.d.ts +8 -0
  35. package/dist/cjs/api/types/SipOutboundDryRunResponse.js +3 -0
  36. package/dist/cjs/api/types/index.d.ts +6 -0
  37. package/dist/cjs/api/types/index.js +6 -0
  38. package/dist/cjs/custom/ReconnectableConversationsSocket.d.ts +74 -0
  39. package/dist/cjs/custom/ReconnectableConversationsSocket.js +283 -0
  40. package/dist/cjs/custom/index.d.ts +1 -0
  41. package/dist/cjs/custom/index.js +5 -0
  42. package/dist/cjs/index.d.ts +1 -0
  43. package/dist/cjs/index.js +3 -1
  44. package/dist/cjs/version.d.ts +1 -1
  45. package/dist/cjs/version.js +1 -1
  46. package/dist/esm/BaseClient.mjs +2 -2
  47. package/dist/esm/Client.d.mts +9 -1
  48. package/dist/esm/Client.mjs +1 -1
  49. package/dist/esm/api/resources/agents/client/Client.d.mts +3 -0
  50. package/dist/esm/api/resources/agents/client/Client.mjs +3 -0
  51. package/dist/esm/api/resources/agents/client/requests/AgentsCreateRequest.d.mts +3 -0
  52. package/dist/esm/api/resources/agents/client/requests/UpdateAgentRequest.d.mts +3 -0
  53. package/dist/esm/api/resources/agents/client/requests/UpsertAgentRequest.d.mts +1 -0
  54. package/dist/esm/api/resources/conversations/client/Client.d.mts +8 -1
  55. package/dist/esm/api/resources/conversations/client/Client.mjs +37 -3
  56. package/dist/esm/api/resources/conversations/client/Socket.d.mts +2 -1
  57. package/dist/esm/api/resources/conversations/client/Socket.mjs +4 -0
  58. package/dist/esm/api/resources/conversations/client/requests/ConversationsSipOutboundCallRequest.d.mts +2 -0
  59. package/dist/esm/api/resources/conversations/client/requests/OutboundCallRequest.d.mts +5 -1
  60. package/dist/esm/api/resources/conversations/types/ConversationsOutboundCallResponse.d.mts +2 -4
  61. package/dist/esm/api/resources/conversations/types/ConversationsSipOutboundCallResponse.d.mts +2 -6
  62. package/dist/esm/api/types/Agent.d.mts +2 -0
  63. package/dist/esm/api/types/ConfigOptions.d.mts +94 -0
  64. package/dist/esm/api/types/ConfigOptions.mjs +29 -0
  65. package/dist/esm/api/types/ConfigPayload.d.mts +2 -88
  66. package/dist/esm/api/types/ConfigPayload.mjs +1 -28
  67. package/dist/esm/api/types/Conversation.d.mts +2 -0
  68. package/dist/esm/api/types/CreateAgentRequest.d.mts +2 -0
  69. package/dist/esm/api/types/OutboundCallConfig.d.mts +2 -0
  70. package/dist/esm/api/types/OutboundCallInitiatedResponse.d.mts +6 -0
  71. package/dist/esm/api/types/OutboundCallInitiatedResponse.mjs +2 -0
  72. package/dist/esm/api/types/OutboundDryRunResponse.d.mts +6 -0
  73. package/dist/esm/api/types/OutboundDryRunResponse.mjs +2 -0
  74. package/dist/esm/api/types/ResetPayload.d.mts +5 -0
  75. package/dist/esm/api/types/ResetPayload.mjs +2 -0
  76. package/dist/esm/api/types/SipOutboundCallInitiatedResponse.d.mts +8 -0
  77. package/dist/esm/api/types/SipOutboundCallInitiatedResponse.mjs +2 -0
  78. package/dist/esm/api/types/SipOutboundDryRunResponse.d.mts +8 -0
  79. package/dist/esm/api/types/SipOutboundDryRunResponse.mjs +2 -0
  80. package/dist/esm/api/types/index.d.mts +6 -0
  81. package/dist/esm/api/types/index.mjs +6 -0
  82. package/dist/esm/custom/ReconnectableConversationsSocket.d.mts +74 -0
  83. package/dist/esm/custom/ReconnectableConversationsSocket.mjs +246 -0
  84. package/dist/esm/custom/index.d.mts +1 -0
  85. package/dist/esm/custom/index.mjs +1 -0
  86. package/dist/esm/index.d.mts +1 -0
  87. package/dist/esm/index.mjs +1 -0
  88. package/dist/esm/version.d.mts +1 -1
  89. package/dist/esm/version.mjs +1 -1
  90. package/package.json +1 -1
  91. package/reference.md +6 -1
  92. package/dist/cjs/api/resources/agents/client/requests/AgentsRemoveCustomPhoneNumberRequest.d.ts +0 -16
  93. package/dist/cjs/api/resources/agents/types/AgentsRemoveCustomPhoneNumberResponse.d.ts +0 -6
  94. package/dist/cjs/api/types/AudioFinishedPayload.d.ts +0 -6
  95. package/dist/cjs/api/types/InterruptedResponsePayload.d.ts +0 -8
  96. package/dist/cjs/api/types/IsUserSpeakingPayload.d.ts +0 -8
  97. package/dist/cjs/api/types/IsUserSpeakingPayload.js +0 -5
  98. package/dist/cjs/api/types/SetTwilioCallSidPayload.d.ts +0 -8
  99. package/dist/cjs/api/types/SetTwilioCallSidPayload.js +0 -5
  100. package/dist/cjs/core/fetcher/ResponseWithBody.d.ts +0 -4
  101. package/dist/cjs/core/fetcher/ResponseWithBody.js +0 -6
  102. package/dist/esm/api/resources/agents/client/requests/AgentsRemoveCustomPhoneNumberRequest.d.mts +0 -16
  103. package/dist/esm/api/resources/agents/client/requests/AgentsRemoveCustomPhoneNumberRequest.mjs +0 -4
  104. package/dist/esm/api/resources/agents/types/AgentsRemoveCustomPhoneNumberResponse.d.mts +0 -6
  105. package/dist/esm/api/resources/agents/types/AgentsRemoveCustomPhoneNumberResponse.mjs +0 -4
  106. package/dist/esm/api/types/AudioFinishedPayload.d.mts +0 -6
  107. package/dist/esm/api/types/AudioFinishedPayload.mjs +0 -4
  108. package/dist/esm/api/types/InterruptedResponsePayload.d.mts +0 -8
  109. package/dist/esm/api/types/InterruptedResponsePayload.mjs +0 -4
  110. package/dist/esm/api/types/IsUserSpeakingPayload.d.mts +0 -8
  111. package/dist/esm/api/types/IsUserSpeakingPayload.mjs +0 -4
  112. package/dist/esm/api/types/SetTwilioCallSidPayload.d.mts +0 -8
  113. package/dist/esm/api/types/SetTwilioCallSidPayload.mjs +0 -4
  114. package/dist/esm/core/fetcher/ResponseWithBody.d.mts +0 -4
  115. package/dist/esm/core/fetcher/ResponseWithBody.mjs +0 -3
  116. package/dist/index.d.mts +0 -686
  117. package/dist/index.d.ts +0 -686
  118. package/dist/index.js +0 -643
  119. package/dist/index.mjs +0 -606
@@ -0,0 +1,8 @@
1
+ export interface SipOutboundCallInitiatedResponse {
2
+ /** The ID of the created conversation. */
3
+ conversation_id: string;
4
+ /** The Twilio Call SID. */
5
+ twilio_call_sid: string;
6
+ /** Always false when a call was placed. */
7
+ dry_run: false;
8
+ }
@@ -1,5 +1,3 @@
1
1
  "use strict";
2
- /**
3
- * This file was auto-generated by Fern from our API Definition.
4
- */
2
+ // This file was auto-generated by Fern from our API Definition.
5
3
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,8 @@
1
+ export interface SipOutboundDryRunResponse {
2
+ /** Always null when `dry_run` is true. */
3
+ conversation_id: unknown | null;
4
+ /** Always null when `dry_run` is true. */
5
+ twilio_call_sid: unknown | null;
6
+ /** Always true for this response. */
7
+ dry_run: true;
8
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ // This file was auto-generated by Fern from our API Definition.
3
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -8,6 +8,7 @@ export * from "./AudioChunkPayload.js";
8
8
  export * from "./AudioChunkResponsePayload.js";
9
9
  export * from "./BadRequestErrorBody.js";
10
10
  export * from "./BasicError.js";
11
+ export * from "./ConfigOptions.js";
11
12
  export * from "./ConfigPayload.js";
12
13
  export * from "./Conversation.js";
13
14
  export * from "./ConversationAnalysis.js";
@@ -29,10 +30,15 @@ export * from "./InputCancelledPayload.js";
29
30
  export * from "./InputTextPayload.js";
30
31
  export * from "./LanguageCode.js";
31
32
  export * from "./OutboundCallConfig.js";
33
+ export * from "./OutboundCallInitiatedResponse.js";
34
+ export * from "./OutboundDryRunResponse.js";
32
35
  export * from "./Project.js";
33
36
  export * from "./ReadyToStartConversationPayload.js";
37
+ export * from "./ResetPayload.js";
34
38
  export * from "./SayPayload.js";
35
39
  export * from "./SetExternalIdPayload.js";
40
+ export * from "./SipOutboundCallInitiatedResponse.js";
41
+ export * from "./SipOutboundDryRunResponse.js";
36
42
  export * from "./Task.js";
37
43
  export * from "./Tool.js";
38
44
  export * from "./ToolCallInterruptedPayload.js";
@@ -24,6 +24,7 @@ __exportStar(require("./AudioChunkPayload.js"), exports);
24
24
  __exportStar(require("./AudioChunkResponsePayload.js"), exports);
25
25
  __exportStar(require("./BadRequestErrorBody.js"), exports);
26
26
  __exportStar(require("./BasicError.js"), exports);
27
+ __exportStar(require("./ConfigOptions.js"), exports);
27
28
  __exportStar(require("./ConfigPayload.js"), exports);
28
29
  __exportStar(require("./Conversation.js"), exports);
29
30
  __exportStar(require("./ConversationAnalysis.js"), exports);
@@ -45,10 +46,15 @@ __exportStar(require("./InputCancelledPayload.js"), exports);
45
46
  __exportStar(require("./InputTextPayload.js"), exports);
46
47
  __exportStar(require("./LanguageCode.js"), exports);
47
48
  __exportStar(require("./OutboundCallConfig.js"), exports);
49
+ __exportStar(require("./OutboundCallInitiatedResponse.js"), exports);
50
+ __exportStar(require("./OutboundDryRunResponse.js"), exports);
48
51
  __exportStar(require("./Project.js"), exports);
49
52
  __exportStar(require("./ReadyToStartConversationPayload.js"), exports);
53
+ __exportStar(require("./ResetPayload.js"), exports);
50
54
  __exportStar(require("./SayPayload.js"), exports);
51
55
  __exportStar(require("./SetExternalIdPayload.js"), exports);
56
+ __exportStar(require("./SipOutboundCallInitiatedResponse.js"), exports);
57
+ __exportStar(require("./SipOutboundDryRunResponse.js"), exports);
52
58
  __exportStar(require("./Task.js"), exports);
53
59
  __exportStar(require("./Tool.js"), exports);
54
60
  __exportStar(require("./ToolCallInterruptedPayload.js"), exports);
@@ -0,0 +1,74 @@
1
+ import * as core from "../core/index.js";
2
+ import type * as Phonic from "../api/index.js";
3
+ import { ConversationsSocket } from "../api/resources/conversations/client/Socket.js";
4
+ export interface ReconnectableConversationsSocketArgs {
5
+ /** Called on 1006 to create a new socket with reconnect_conv_id. May be async (e.g. fresh auth). */
6
+ createReconnectSocket: (conversationId: string) => core.ReconnectingWebSocket | Promise<core.ReconnectingWebSocket>;
7
+ /** Initial socket for the first connection. */
8
+ socket: core.ReconnectingWebSocket;
9
+ /** If provided, reconnection stops when the signal is aborted. */
10
+ abortSignal?: AbortSignal;
11
+ }
12
+ type EventHandlers = {
13
+ open?: () => void;
14
+ message?: (message: ConversationsSocket.Response) => void;
15
+ close?: (event: core.CloseEvent) => void;
16
+ error?: (error: Error) => void;
17
+ };
18
+ /**
19
+ * Wraps ConversationsSocket with automatic reconnection on 1006.
20
+ *
21
+ * On abnormal closure, creates a brand new ReconnectingWebSocket (via the
22
+ * createReconnectSocket factory) and wraps it in a fresh ConversationsSocket,
23
+ * forwarding all events to user-registered handlers.
24
+ *
25
+ * Retries reconnection with exponential backoff until the server responds
26
+ * with a terminal close code (4800 session expired, 4801 invalid state),
27
+ * the safety cap is reached, or the user calls close().
28
+ *
29
+ * Uses composition rather than inheritance to avoid coupling to the parent's
30
+ * private event handler registration or ReconnectingWebSocket internals.
31
+ */
32
+ export declare class ReconnectableConversationsSocket {
33
+ private _conversationId;
34
+ private _inner;
35
+ private readonly _createReconnectSocket;
36
+ private readonly _handlers;
37
+ private _reconnectAttempts;
38
+ private _isClosed;
39
+ private readonly _abortSignal;
40
+ private _cleanupWireListeners;
41
+ private _pendingReconnect;
42
+ private _pendingReplacement;
43
+ constructor(args: ReconnectableConversationsSocketArgs);
44
+ /** The conversation ID captured from the server's conversation_created message. */
45
+ get conversationId(): string | null;
46
+ get socket(): core.ReconnectingWebSocket;
47
+ get readyState(): number;
48
+ on<T extends keyof EventHandlers>(event: T, callback: EventHandlers[T]): void;
49
+ /** Drop outbound sends when we cannot talk to a live socket (no queue). */
50
+ private _safeSend;
51
+ sendConfig(message: Phonic.ConfigPayload): void;
52
+ sendAudioChunk(message: Phonic.AudioChunkPayload): void;
53
+ sendToolCallOutput(message: Phonic.ToolCallOutputPayload): void;
54
+ sendUpdateSystemPrompt(message: Phonic.UpdateSystemPromptPayload): void;
55
+ sendAddSystemMessage(message: Phonic.AddSystemMessagePayload): void;
56
+ sendSetExternalId(message: Phonic.SetExternalIdPayload): void;
57
+ sendGenerateReply(message: Phonic.GenerateReplyPayload): void;
58
+ sendSay(message: Phonic.SayPayload): void;
59
+ sendReset(message: Phonic.ResetPayload): void;
60
+ /**
61
+ * Not supported — reconnection after 1006 is handled automatically.
62
+ * To start a new conversation, create a new socket via client.conversations.connect().
63
+ */
64
+ connect(): never;
65
+ close(): void;
66
+ waitForOpen(): Promise<core.ReconnectingWebSocket>;
67
+ private _getReconnectDelay;
68
+ /** Schedule a reconnection attempt after backoff delay. */
69
+ private _scheduleReconnect;
70
+ /** Perform the actual reconnection attempt. */
71
+ private _doReconnect;
72
+ private _wireInner;
73
+ }
74
+ export {};
@@ -0,0 +1,283 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.ReconnectableConversationsSocket = void 0;
46
+ const core = __importStar(require("../core/index.js"));
47
+ const Socket_js_1 = require("../api/resources/conversations/client/Socket.js");
48
+ const json_js_1 = require("../core/json.js");
49
+ /** 1006 is the only close code that indicates an unexpected disconnect
50
+ * worth reconnecting for. All other codes (1000, 4000, 4800, etc.)
51
+ * are intentional server-side closes. */
52
+ const ABNORMAL_CLOSURE = 1006;
53
+ const BASE_RECONNECT_DELAY_MS = 500;
54
+ const MAX_RECONNECT_DELAY_MS = 5000;
55
+ /** Safety cap: stop retrying if the server is completely unreachable.
56
+ * In normal operation the server's terminal codes (4800/4801) stop
57
+ * retries much sooner (within the 10s grace period). */
58
+ const MAX_RECONNECT_ATTEMPTS = 10;
59
+ /**
60
+ * Wraps ConversationsSocket with automatic reconnection on 1006.
61
+ *
62
+ * On abnormal closure, creates a brand new ReconnectingWebSocket (via the
63
+ * createReconnectSocket factory) and wraps it in a fresh ConversationsSocket,
64
+ * forwarding all events to user-registered handlers.
65
+ *
66
+ * Retries reconnection with exponential backoff until the server responds
67
+ * with a terminal close code (4800 session expired, 4801 invalid state),
68
+ * the safety cap is reached, or the user calls close().
69
+ *
70
+ * Uses composition rather than inheritance to avoid coupling to the parent's
71
+ * private event handler registration or ReconnectingWebSocket internals.
72
+ */
73
+ class ReconnectableConversationsSocket {
74
+ constructor(args) {
75
+ this._conversationId = null;
76
+ this._handlers = {};
77
+ this._reconnectAttempts = 0;
78
+ this._isClosed = false;
79
+ this._cleanupWireListeners = null;
80
+ this._pendingReconnect = null;
81
+ this._pendingReplacement = false;
82
+ this._createReconnectSocket = args.createReconnectSocket;
83
+ this._abortSignal = args.abortSignal != undefined ? args.abortSignal : null;
84
+ this._inner = new Socket_js_1.ConversationsSocket({ socket: args.socket });
85
+ this._wireInner(this._inner, args.socket);
86
+ }
87
+ /** The conversation ID captured from the server's conversation_created message. */
88
+ get conversationId() {
89
+ return this._conversationId;
90
+ }
91
+ get socket() {
92
+ return this._inner.socket;
93
+ }
94
+ get readyState() {
95
+ return this._inner.readyState;
96
+ }
97
+ on(event, callback) {
98
+ this._handlers[event] = callback;
99
+ }
100
+ /** Drop outbound sends when we cannot talk to a live socket (no queue). */
101
+ _safeSend(op) {
102
+ if (this._isClosed || this._pendingReplacement) {
103
+ return;
104
+ }
105
+ if (this._inner.readyState !== core.ReconnectingWebSocket.ReadyState.OPEN) {
106
+ return;
107
+ }
108
+ op(this._inner);
109
+ }
110
+ sendConfig(message) {
111
+ this._safeSend((inner) => inner.sendConfig(message));
112
+ }
113
+ sendAudioChunk(message) {
114
+ this._safeSend((inner) => inner.sendAudioChunk(message));
115
+ }
116
+ sendToolCallOutput(message) {
117
+ this._safeSend((inner) => inner.sendToolCallOutput(message));
118
+ }
119
+ sendUpdateSystemPrompt(message) {
120
+ this._safeSend((inner) => inner.sendUpdateSystemPrompt(message));
121
+ }
122
+ sendAddSystemMessage(message) {
123
+ this._safeSend((inner) => inner.sendAddSystemMessage(message));
124
+ }
125
+ sendSetExternalId(message) {
126
+ this._safeSend((inner) => inner.sendSetExternalId(message));
127
+ }
128
+ sendGenerateReply(message) {
129
+ this._safeSend((inner) => inner.sendGenerateReply(message));
130
+ }
131
+ sendSay(message) {
132
+ this._safeSend((inner) => inner.sendSay(message));
133
+ }
134
+ sendReset(message) {
135
+ this._safeSend((inner) => inner.sendReset(message));
136
+ }
137
+ /**
138
+ * Not supported — reconnection after 1006 is handled automatically.
139
+ * To start a new conversation, create a new socket via client.conversations.connect().
140
+ */
141
+ connect() {
142
+ throw new Error("connect() is not supported on ReconnectableConversationsSocket. "
143
+ + "Reconnection after 1006 is automatic. To start a new conversation, "
144
+ + "call client.conversations.connect() again.");
145
+ }
146
+ close() {
147
+ var _a;
148
+ this._isClosed = true;
149
+ this._pendingReplacement = false;
150
+ if (this._pendingReconnect != null) {
151
+ clearTimeout(this._pendingReconnect);
152
+ this._pendingReconnect = null;
153
+ }
154
+ (_a = this._cleanupWireListeners) === null || _a === void 0 ? void 0 : _a.call(this);
155
+ this._cleanupWireListeners = null;
156
+ this._inner.close();
157
+ }
158
+ waitForOpen() {
159
+ return __awaiter(this, void 0, void 0, function* () {
160
+ return this._inner.waitForOpen();
161
+ });
162
+ }
163
+ _getReconnectDelay() {
164
+ // Exponential backoff: 500ms, 1s, 2s, 4s, capped at 5s
165
+ const delay = BASE_RECONNECT_DELAY_MS * Math.pow(2, this._reconnectAttempts - 1);
166
+ return Math.min(delay, MAX_RECONNECT_DELAY_MS);
167
+ }
168
+ /** Schedule a reconnection attempt after backoff delay. */
169
+ _scheduleReconnect() {
170
+ var _a, _b, _c;
171
+ if (this._isClosed || this._conversationId === null || ((_a = this._abortSignal) === null || _a === void 0 ? void 0 : _a.aborted)) {
172
+ return;
173
+ }
174
+ if (this._reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
175
+ this._pendingReplacement = false;
176
+ (_c = (_b = this._handlers).error) === null || _c === void 0 ? void 0 : _c.call(_b, new Error("Max reconnect attempts reached"));
177
+ return;
178
+ }
179
+ // Clear any existing timer to prevent orphaned timeouts
180
+ if (this._pendingReconnect != null) {
181
+ clearTimeout(this._pendingReconnect);
182
+ }
183
+ this._reconnectAttempts++;
184
+ const delay = this._getReconnectDelay();
185
+ this._pendingReplacement = true;
186
+ this._pendingReconnect = setTimeout(() => {
187
+ this._pendingReconnect = null;
188
+ if (this._isClosed) {
189
+ this._pendingReplacement = false;
190
+ return;
191
+ }
192
+ void this._doReconnect();
193
+ }, delay);
194
+ }
195
+ /** Perform the actual reconnection attempt. */
196
+ _doReconnect() {
197
+ return __awaiter(this, void 0, void 0, function* () {
198
+ var _a, _b;
199
+ try {
200
+ const created = this._createReconnectSocket(this._conversationId);
201
+ const newRawSocket = created instanceof Promise ? yield created : created;
202
+ if (this._isClosed || ((_a = this._abortSignal) === null || _a === void 0 ? void 0 : _a.aborted)) {
203
+ this._pendingReplacement = false;
204
+ newRawSocket.close();
205
+ return;
206
+ }
207
+ // Clean up the old socket: remove our custom listeners and close
208
+ // the ConversationsSocket wrapper (which removes its own listeners).
209
+ (_b = this._cleanupWireListeners) === null || _b === void 0 ? void 0 : _b.call(this);
210
+ this._cleanupWireListeners = null;
211
+ try {
212
+ this._inner.close();
213
+ }
214
+ catch ( /* already closed from 1006 */_c) { /* already closed from 1006 */ }
215
+ const newInner = new Socket_js_1.ConversationsSocket({ socket: newRawSocket });
216
+ this._inner = newInner;
217
+ this._wireInner(newInner, newRawSocket);
218
+ }
219
+ catch (_d) {
220
+ this._pendingReplacement = false;
221
+ // Connection failed — schedule another attempt.
222
+ // The server's grace period (10s) is the natural limit;
223
+ // once it expires, the next attempt will get 4800 and stop.
224
+ this._scheduleReconnect();
225
+ }
226
+ });
227
+ }
228
+ _wireInner(inner, rawSocket) {
229
+ // Forward events from the inner ConversationsSocket to user handlers.
230
+ // Clear _pendingReplacement before calling the user's open handler
231
+ // so that sends inside the handler are not silently dropped.
232
+ inner.on("open", () => {
233
+ var _a, _b;
234
+ this._pendingReplacement = false;
235
+ (_b = (_a = this._handlers).open) === null || _b === void 0 ? void 0 : _b.call(_a);
236
+ });
237
+ inner.on("message", (msg) => { var _a, _b; return (_b = (_a = this._handlers).message) === null || _b === void 0 ? void 0 : _b.call(_a, msg); });
238
+ inner.on("close", (ev) => { var _a, _b; return (_b = (_a = this._handlers).close) === null || _b === void 0 ? void 0 : _b.call(_a, ev); });
239
+ inner.on("error", (err) => { var _a, _b; return (_b = (_a = this._handlers).error) === null || _b === void 0 ? void 0 : _b.call(_a, err); });
240
+ // Intercept raw messages to capture conversation_id and reset reconnect counter
241
+ const onMessage = (event) => {
242
+ try {
243
+ const data = (0, json_js_1.fromJson)(event.data);
244
+ if (data && typeof data === "object" && "type" in data) {
245
+ const type = data.type;
246
+ if (type === "conversation_created") {
247
+ this._conversationId = data.conversation_id;
248
+ }
249
+ if (type === "conversation_reconnected") {
250
+ this._reconnectAttempts = 0;
251
+ }
252
+ }
253
+ }
254
+ catch (_a) {
255
+ // ignore — inner socket handles parse errors
256
+ }
257
+ };
258
+ const onClose = (event) => {
259
+ if (this._isClosed) {
260
+ return;
261
+ }
262
+ if (event.code === ABNORMAL_CLOSURE && this._conversationId !== null) {
263
+ // We have a conversation to resume — cancel RWS's built-in
264
+ // auto-reconnect and handle it ourselves with reconnect_conv_id.
265
+ // _handleClose calls _connect() before notifying listeners,
266
+ // but _connect() awaits _wait() which is async. Calling
267
+ // close() synchronously sets _closeCalled = true, which
268
+ // _connect() checks before opening the new socket.
269
+ rawSocket.close();
270
+ this._scheduleReconnect();
271
+ }
272
+ // 1006 without conversationId: let RWS handle transport-level
273
+ // reconnect normally (starts a fresh conversation).
274
+ };
275
+ rawSocket.addEventListener("message", onMessage);
276
+ rawSocket.addEventListener("close", onClose);
277
+ this._cleanupWireListeners = () => {
278
+ rawSocket.removeEventListener("message", onMessage);
279
+ rawSocket.removeEventListener("close", onClose);
280
+ };
281
+ }
282
+ }
283
+ exports.ReconnectableConversationsSocket = ReconnectableConversationsSocket;
@@ -0,0 +1 @@
1
+ export { ReconnectableConversationsSocket } from "./ReconnectableConversationsSocket.js";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ReconnectableConversationsSocket = void 0;
4
+ var ReconnectableConversationsSocket_js_1 = require("./ReconnectableConversationsSocket.js");
5
+ Object.defineProperty(exports, "ReconnectableConversationsSocket", { enumerable: true, get: function () { return ReconnectableConversationsSocket_js_1.ReconnectableConversationsSocket; } });
@@ -4,3 +4,4 @@ export { PhonicClient } from "./Client.js";
4
4
  export { PhonicEnvironment, type PhonicEnvironmentUrls } from "./environments.js";
5
5
  export { PhonicError, PhonicTimeoutError } from "./errors/index.js";
6
6
  export * from "./exports.js";
7
+ export { ReconnectableConversationsSocket } from "./custom/index.js";
package/dist/cjs/index.js CHANGED
@@ -36,7 +36,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
36
36
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.PhonicTimeoutError = exports.PhonicError = exports.PhonicEnvironment = exports.PhonicClient = exports.Phonic = void 0;
39
+ exports.ReconnectableConversationsSocket = exports.PhonicTimeoutError = exports.PhonicError = exports.PhonicEnvironment = exports.PhonicClient = exports.Phonic = void 0;
40
40
  exports.Phonic = __importStar(require("./api/index.js"));
41
41
  var Client_js_1 = require("./Client.js");
42
42
  Object.defineProperty(exports, "PhonicClient", { enumerable: true, get: function () { return Client_js_1.PhonicClient; } });
@@ -46,3 +46,5 @@ var index_js_1 = require("./errors/index.js");
46
46
  Object.defineProperty(exports, "PhonicError", { enumerable: true, get: function () { return index_js_1.PhonicError; } });
47
47
  Object.defineProperty(exports, "PhonicTimeoutError", { enumerable: true, get: function () { return index_js_1.PhonicTimeoutError; } });
48
48
  __exportStar(require("./exports.js"), exports);
49
+ var index_js_2 = require("./custom/index.js");
50
+ Object.defineProperty(exports, "ReconnectableConversationsSocket", { enumerable: true, get: function () { return index_js_2.ReconnectableConversationsSocket; } });
@@ -1 +1 @@
1
- export declare const SDK_VERSION = "0.31.8";
1
+ export declare const SDK_VERSION = "0.31.10";
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SDK_VERSION = void 0;
4
- exports.SDK_VERSION = "0.31.8";
4
+ exports.SDK_VERSION = "0.31.10";
@@ -6,8 +6,8 @@ export function normalizeClientOptions(options) {
6
6
  const headers = mergeHeaders({
7
7
  "X-Fern-Language": "JavaScript",
8
8
  "X-Fern-SDK-Name": "phonic",
9
- "X-Fern-SDK-Version": "0.31.8",
10
- "User-Agent": "phonic/0.31.8",
9
+ "X-Fern-SDK-Version": "0.31.10",
10
+ "User-Agent": "phonic/0.31.10",
11
11
  "X-Fern-Runtime": core.RUNTIME.type,
12
12
  "X-Fern-Runtime-Version": core.RUNTIME.version,
13
13
  }, options === null || options === void 0 ? void 0 : options.headers);
@@ -9,7 +9,15 @@ import type { BaseClientOptions, BaseRequestOptions } from "./BaseClient.mjs";
9
9
  import { type NormalizedClientOptionsWithAuth } from "./BaseClient.mjs";
10
10
  import * as core from "./core/index.mjs";
11
11
  export declare namespace PhonicClient {
12
- type Options = BaseClientOptions;
12
+ type Options = BaseClientOptions & {
13
+ /**
14
+ * When `true`, conversation WebSockets automatically reconnect after an
15
+ * abnormal disconnect (WebSocket close code 1006) using `reconnect_conv_id`.
16
+ * Defaults to `false` until the behavior is broadly validated in production;
17
+ * set to `true` to opt in early.
18
+ */
19
+ reconnectConversationOnAbnormalDisconnect?: boolean;
20
+ };
13
21
  interface RequestOptions extends BaseRequestOptions {
14
22
  }
15
23
  }
@@ -1,4 +1,4 @@
1
- // This file was auto-generated by Fern from our API Definition.
1
+ // Maintained manually (listed in .fernignore). Fern does not overwrite this file.
2
2
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
3
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
4
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -63,6 +63,7 @@ export declare class AgentsClient {
63
63
  * additional_languages: ["es"],
64
64
  * multilingual_mode: "request",
65
65
  * boosted_keywords: ["Load ID", "dispatch"],
66
+ * min_words_to_interrupt: 1,
66
67
  * configuration_endpoint: {
67
68
  * url: "https://api.example.com/config",
68
69
  * headers: {
@@ -111,6 +112,7 @@ export declare class AgentsClient {
111
112
  * additional_languages: ["es"],
112
113
  * multilingual_mode: "request",
113
114
  * boosted_keywords: ["Load ID", "dispatch"],
115
+ * min_words_to_interrupt: 1,
114
116
  * configuration_endpoint: {
115
117
  * url: "https://api.example.com/config",
116
118
  * headers: {
@@ -195,6 +197,7 @@ export declare class AgentsClient {
195
197
  * additional_languages: ["es"],
196
198
  * multilingual_mode: "request",
197
199
  * boosted_keywords: ["Load ID", "dispatch"],
200
+ * min_words_to_interrupt: 1,
198
201
  * configuration_endpoint: {
199
202
  * url: "https://api.example.com/config",
200
203
  * headers: {
@@ -125,6 +125,7 @@ export class AgentsClient {
125
125
  * additional_languages: ["es"],
126
126
  * multilingual_mode: "request",
127
127
  * boosted_keywords: ["Load ID", "dispatch"],
128
+ * min_words_to_interrupt: 1,
128
129
  * configuration_endpoint: {
129
130
  * url: "https://api.example.com/config",
130
131
  * headers: {
@@ -222,6 +223,7 @@ export class AgentsClient {
222
223
  * additional_languages: ["es"],
223
224
  * multilingual_mode: "request",
224
225
  * boosted_keywords: ["Load ID", "dispatch"],
226
+ * min_words_to_interrupt: 1,
225
227
  * configuration_endpoint: {
226
228
  * url: "https://api.example.com/config",
227
229
  * headers: {
@@ -435,6 +437,7 @@ export class AgentsClient {
435
437
  * additional_languages: ["es"],
436
438
  * multilingual_mode: "request",
437
439
  * boosted_keywords: ["Load ID", "dispatch"],
440
+ * min_words_to_interrupt: 1,
438
441
  * configuration_endpoint: {
439
442
  * url: "https://api.example.com/config",
440
443
  * headers: {
@@ -28,6 +28,7 @@ import type * as Phonic from "../../../../index.mjs";
28
28
  * additional_languages: ["es"],
29
29
  * multilingual_mode: "request",
30
30
  * boosted_keywords: ["Load ID", "dispatch"],
31
+ * min_words_to_interrupt: 1,
31
32
  * configuration_endpoint: {
32
33
  * url: "https://api.example.com/config",
33
34
  * headers: {
@@ -90,6 +91,8 @@ export interface AgentsCreateRequest {
90
91
  multilingual_mode?: Phonic.CreateAgentRequest.MultilingualMode;
91
92
  /** These words, or short phrases, will be more accurately recognized by the agent. */
92
93
  boosted_keywords?: string[];
94
+ /** Minimum number of words required to interrupt the assistant. */
95
+ min_words_to_interrupt?: number;
93
96
  /** When not `null`, at the beginning of the conversation the agent will make a POST request to this endpoint to get configuration options. */
94
97
  configuration_endpoint?: Phonic.CreateAgentRequest.ConfigurationEndpoint | null;
95
98
  /** Float between 0.0 and 1.0 representing the percentage of inbound calls handled by Agent. Defaults to `1.0`. Requires `phone_number` to be set when less than 1.0. */
@@ -28,6 +28,7 @@ import type * as Phonic from "../../../../index.mjs";
28
28
  * additional_languages: ["es"],
29
29
  * multilingual_mode: "request",
30
30
  * boosted_keywords: ["Load ID", "dispatch"],
31
+ * min_words_to_interrupt: 1,
31
32
  * configuration_endpoint: {
32
33
  * url: "https://api.example.com/config",
33
34
  * headers: {
@@ -90,6 +91,8 @@ export interface UpdateAgentRequest {
90
91
  multilingual_mode?: UpdateAgentRequest.MultilingualMode;
91
92
  /** These words, or short phrases, will be more accurately recognized by the agent. */
92
93
  boosted_keywords?: string[];
94
+ /** Minimum number of words required to interrupt the assistant. */
95
+ min_words_to_interrupt?: number;
93
96
  /** When not `null`, at the beginning of the conversation the agent will make a POST request to this endpoint to get configuration options. */
94
97
  configuration_endpoint?: UpdateAgentRequest.ConfigurationEndpoint | null;
95
98
  /** Float between 0.0 and 1.0 representing the percentage of inbound calls handled by Agent. Requires `phone_number` to be set when less than 1.0. */
@@ -28,6 +28,7 @@ import type * as Phonic from "../../../../index.mjs";
28
28
  * additional_languages: ["es"],
29
29
  * multilingual_mode: "request",
30
30
  * boosted_keywords: ["Load ID", "dispatch"],
31
+ * min_words_to_interrupt: 1,
31
32
  * configuration_endpoint: {
32
33
  * url: "https://api.example.com/config",
33
34
  * headers: {
@@ -4,7 +4,14 @@ import * as core from "../../../../core/index.mjs";
4
4
  import * as Phonic from "../../../index.mjs";
5
5
  import { ConversationsSocket } from "./Socket.mjs";
6
6
  export declare namespace ConversationsClient {
7
- type Options = BaseClientOptions;
7
+ type Options = BaseClientOptions & {
8
+ /**
9
+ * When `true`, `connect()` uses session-aware reconnection on abnormal
10
+ * disconnect (1006). Set via `PhonicClient` options as
11
+ * `reconnectConversationOnAbnormalDisconnect`.
12
+ */
13
+ reconnectConversationOnAbnormalDisconnect?: boolean;
14
+ };
8
15
  interface RequestOptions extends BaseRequestOptions {
9
16
  }
10
17
  interface ConnectArgs {