phonic 0.31.9 → 0.31.11
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/LICENSE +21 -0
- package/dist/cjs/BaseClient.js +2 -2
- package/dist/cjs/Client.d.ts +9 -1
- package/dist/cjs/Client.js +1 -1
- package/dist/cjs/api/resources/conversations/client/Client.d.ts +8 -1
- package/dist/cjs/api/resources/conversations/client/Client.js +37 -3
- package/dist/cjs/api/resources/conversations/client/Socket.d.ts +2 -1
- package/dist/cjs/api/resources/conversations/client/Socket.js +4 -0
- package/dist/cjs/api/types/ConfigOptions.d.ts +94 -0
- package/dist/cjs/api/types/ConfigOptions.js +32 -0
- package/dist/cjs/api/types/ConfigPayload.d.ts +2 -90
- package/dist/cjs/api/types/ConfigPayload.js +0 -29
- package/dist/cjs/api/types/ResetPayload.d.ts +5 -0
- package/dist/cjs/api/types/ResetPayload.js +3 -0
- package/dist/cjs/api/types/index.d.ts +2 -0
- package/dist/cjs/api/types/index.js +2 -0
- package/dist/cjs/custom/ReconnectableConversationsSocket.d.ts +74 -0
- package/dist/cjs/custom/ReconnectableConversationsSocket.js +283 -0
- package/dist/cjs/custom/index.d.ts +1 -0
- package/dist/cjs/custom/index.js +5 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/BaseClient.mjs +2 -2
- package/dist/esm/Client.d.mts +9 -1
- package/dist/esm/Client.mjs +1 -1
- package/dist/esm/api/resources/conversations/client/Client.d.mts +8 -1
- package/dist/esm/api/resources/conversations/client/Client.mjs +37 -3
- package/dist/esm/api/resources/conversations/client/Socket.d.mts +2 -1
- package/dist/esm/api/resources/conversations/client/Socket.mjs +4 -0
- package/dist/esm/api/types/ConfigOptions.d.mts +94 -0
- package/dist/esm/api/types/ConfigOptions.mjs +29 -0
- package/dist/esm/api/types/ConfigPayload.d.mts +2 -90
- package/dist/esm/api/types/ConfigPayload.mjs +1 -28
- package/dist/esm/api/types/ResetPayload.d.mts +5 -0
- package/dist/esm/api/types/ResetPayload.mjs +2 -0
- package/dist/esm/api/types/index.d.mts +2 -0
- package/dist/esm/api/types/index.mjs +2 -0
- package/dist/esm/custom/ReconnectableConversationsSocket.d.mts +74 -0
- package/dist/esm/custom/ReconnectableConversationsSocket.mjs +246 -0
- package/dist/esm/custom/index.d.mts +1 -0
- package/dist/esm/custom/index.mjs +1 -0
- package/dist/esm/index.d.mts +1 -0
- package/dist/esm/index.mjs +1 -0
- package/dist/esm/version.d.mts +1 -1
- package/dist/esm/version.mjs +1 -1
- package/package.json +2 -1
|
@@ -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; } });
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -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; } });
|
package/dist/cjs/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "0.31.
|
|
1
|
+
export declare const SDK_VERSION = "0.31.11";
|
package/dist/cjs/version.js
CHANGED
package/dist/esm/BaseClient.mjs
CHANGED
|
@@ -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.
|
|
10
|
-
"User-Agent": "phonic/0.31.
|
|
9
|
+
"X-Fern-SDK-Version": "0.31.11",
|
|
10
|
+
"User-Agent": "phonic/0.31.11",
|
|
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);
|
package/dist/esm/Client.d.mts
CHANGED
|
@@ -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
|
}
|
package/dist/esm/Client.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
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) {
|
|
@@ -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 {
|
|
@@ -26,6 +26,7 @@ import * as environments from "../../../../environments.mjs";
|
|
|
26
26
|
import { handleNonStatusCodeError } from "../../../../errors/handleNonStatusCodeError.mjs";
|
|
27
27
|
import * as errors from "../../../../errors/index.mjs";
|
|
28
28
|
import * as Phonic from "../../../index.mjs";
|
|
29
|
+
import { ReconnectableConversationsSocket } from "../../../../custom/ReconnectableConversationsSocket.mjs";
|
|
29
30
|
import { ConversationsSocket } from "./Socket.mjs";
|
|
30
31
|
export class ConversationsClient {
|
|
31
32
|
constructor(options = {}) {
|
|
@@ -714,11 +715,44 @@ export class ConversationsClient {
|
|
|
714
715
|
const _queryParams = {
|
|
715
716
|
downstream_websocket_url: downstreamWebsocketUrl,
|
|
716
717
|
};
|
|
718
|
+
const baseWsUrl = core.url.join((_a = (yield core.Supplier.get(this._options.baseUrl))) !== null && _a !== void 0 ? _a : ((_b = (yield core.Supplier.get(this._options.environment))) !== null && _b !== void 0 ? _b : environments.PhonicEnvironment.Default)
|
|
719
|
+
.production, "/v1/sts/ws");
|
|
720
|
+
if (this._options.reconnectConversationOnAbnormalDisconnect) {
|
|
721
|
+
const connectionTimeoutMs = connectionTimeoutInSeconds != null ? connectionTimeoutInSeconds * 1000 : undefined;
|
|
722
|
+
const createSocket = (reconnectConvId) => __awaiter(this, void 0, void 0, function* () {
|
|
723
|
+
var _a, _b, _c;
|
|
724
|
+
const freshAuth = yield this._options.authProvider.getAuthRequest();
|
|
725
|
+
const mergedHeaders = Object.assign(Object.assign(Object.assign({}, ((_a = freshAuth.headers) !== null && _a !== void 0 ? _a : {})), ((_c = (_b = this._options) === null || _b === void 0 ? void 0 : _b.headers) !== null && _c !== void 0 ? _c : {})), headers);
|
|
726
|
+
const isSessionReconnect = reconnectConvId != null;
|
|
727
|
+
return new core.ReconnectingWebSocket({
|
|
728
|
+
url: baseWsUrl,
|
|
729
|
+
protocols: protocols !== null && protocols !== void 0 ? protocols : [],
|
|
730
|
+
queryParameters: Object.assign(Object.assign(Object.assign({}, _queryParams), queryParams), (reconnectConvId ? { reconnect_conv_id: reconnectConvId } : {})),
|
|
731
|
+
headers: mergedHeaders,
|
|
732
|
+
options: {
|
|
733
|
+
debug: debug !== null && debug !== void 0 ? debug : false,
|
|
734
|
+
// Initial connection keeps transport retries; replacement sockets use 0 so only
|
|
735
|
+
// ReconnectableConversationsSocket performs session-level reconnect.
|
|
736
|
+
maxRetries: isSessionReconnect ? 0 : reconnectAttempts !== null && reconnectAttempts !== void 0 ? reconnectAttempts : 30,
|
|
737
|
+
connectionTimeout: connectionTimeoutMs,
|
|
738
|
+
},
|
|
739
|
+
// Only pass abortSignal to the initial socket. Reconnect sockets
|
|
740
|
+
// don't get it — each would register a new listener on the signal
|
|
741
|
+
// that's never removed, leaking memory over many reconnects.
|
|
742
|
+
abortSignal: isSessionReconnect ? undefined : abortSignal,
|
|
743
|
+
});
|
|
744
|
+
});
|
|
745
|
+
const initialSocket = yield createSocket();
|
|
746
|
+
return new ReconnectableConversationsSocket({
|
|
747
|
+
socket: initialSocket,
|
|
748
|
+
createReconnectSocket: (conversationId) => createSocket(conversationId),
|
|
749
|
+
abortSignal,
|
|
750
|
+
});
|
|
751
|
+
}
|
|
717
752
|
const _authRequest = yield this._options.authProvider.getAuthRequest();
|
|
718
|
-
const _headers = Object.assign(Object.assign(Object.assign({}, ((
|
|
753
|
+
const _headers = Object.assign(Object.assign(Object.assign({}, ((_c = _authRequest.headers) !== null && _c !== void 0 ? _c : {})), ((_e = (_d = this._options) === null || _d === void 0 ? void 0 : _d.headers) !== null && _e !== void 0 ? _e : {})), headers);
|
|
719
754
|
const socket = new core.ReconnectingWebSocket({
|
|
720
|
-
url:
|
|
721
|
-
.production, "/v1/sts/ws"),
|
|
755
|
+
url: baseWsUrl,
|
|
722
756
|
protocols: protocols !== null && protocols !== void 0 ? protocols : [],
|
|
723
757
|
queryParameters: Object.assign(Object.assign({}, _queryParams), queryParams),
|
|
724
758
|
headers: _headers,
|
|
@@ -41,6 +41,7 @@ export declare class ConversationsSocket {
|
|
|
41
41
|
sendToolCallOutput(message: Phonic.ToolCallOutputPayload): void;
|
|
42
42
|
sendGenerateReply(message: Phonic.GenerateReplyPayload): void;
|
|
43
43
|
sendSay(message: Phonic.SayPayload): void;
|
|
44
|
+
sendReset(message: Phonic.ResetPayload): void;
|
|
44
45
|
/** Connect to the websocket and register event handlers. */
|
|
45
46
|
connect(): ConversationsSocket;
|
|
46
47
|
/** Close the websocket and unregister event handlers. */
|
|
@@ -52,5 +53,5 @@ export declare class ConversationsSocket {
|
|
|
52
53
|
/** Send a binary payload to the websocket. */
|
|
53
54
|
protected sendBinary(payload: ArrayBuffer | Blob | ArrayBufferView): void;
|
|
54
55
|
/** Send a JSON payload to the websocket. */
|
|
55
|
-
protected sendJson(payload: Phonic.ConfigPayload | Phonic.AudioChunkPayload | Phonic.UpdateSystemPromptPayload | Phonic.AddSystemMessagePayload | Phonic.SetExternalIdPayload | Phonic.ToolCallOutputPayload | Phonic.GenerateReplyPayload | Phonic.SayPayload): void;
|
|
56
|
+
protected sendJson(payload: Phonic.ConfigPayload | Phonic.AudioChunkPayload | Phonic.UpdateSystemPromptPayload | Phonic.AddSystemMessagePayload | Phonic.SetExternalIdPayload | Phonic.ToolCallOutputPayload | Phonic.GenerateReplyPayload | Phonic.SayPayload | Phonic.ResetPayload): void;
|
|
56
57
|
}
|
|
@@ -86,6 +86,10 @@ export class ConversationsSocket {
|
|
|
86
86
|
this.assertSocketIsOpen();
|
|
87
87
|
this.sendJson(message);
|
|
88
88
|
}
|
|
89
|
+
sendReset(message) {
|
|
90
|
+
this.assertSocketIsOpen();
|
|
91
|
+
this.sendJson(message);
|
|
92
|
+
}
|
|
89
93
|
/** Connect to the websocket and register event handlers. */
|
|
90
94
|
connect() {
|
|
91
95
|
this.socket.reconnect();
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration fields for the initial `config` message.
|
|
3
|
+
*/
|
|
4
|
+
export interface ConfigOptions {
|
|
5
|
+
/** Agent name to use for conversation */
|
|
6
|
+
agent?: string | undefined;
|
|
7
|
+
/** Project name */
|
|
8
|
+
project?: string | undefined;
|
|
9
|
+
/** STS model to use */
|
|
10
|
+
model?: "merritt" | undefined;
|
|
11
|
+
/** System prompt for AI assistant */
|
|
12
|
+
system_prompt?: string | undefined;
|
|
13
|
+
/** Audio playback speed */
|
|
14
|
+
audio_speed?: number | undefined;
|
|
15
|
+
/** Background noise level for the conversation */
|
|
16
|
+
background_noise_level?: number | undefined;
|
|
17
|
+
/** Background noise type for the conversation */
|
|
18
|
+
background_noise?: (ConfigOptions.BackgroundNoise | null) | undefined;
|
|
19
|
+
/** When `true`, the welcome message will be automatically generated and the `welcome_message` field will be ignored. */
|
|
20
|
+
generate_welcome_message?: boolean | undefined;
|
|
21
|
+
/** Message to play when conversation starts. Ignored when `generate_welcome_message` is `true`. */
|
|
22
|
+
welcome_message?: (string | null) | undefined;
|
|
23
|
+
/** Voice ID to use for speech synthesis */
|
|
24
|
+
voice_id?: string | undefined;
|
|
25
|
+
/** Audio input format */
|
|
26
|
+
input_format?: ConfigOptions.InputFormat | undefined;
|
|
27
|
+
/** Audio output format */
|
|
28
|
+
output_format?: ConfigOptions.OutputFormat | undefined;
|
|
29
|
+
/** Voice activity detection prebuffer duration */
|
|
30
|
+
vad_prebuffer_duration_ms?: number | undefined;
|
|
31
|
+
/** Minimum speech duration for VAD */
|
|
32
|
+
vad_min_speech_duration_ms?: number | undefined;
|
|
33
|
+
/** Minimum silence duration for VAD */
|
|
34
|
+
vad_min_silence_duration_ms?: number | undefined;
|
|
35
|
+
/** Voice activity detection threshold */
|
|
36
|
+
vad_threshold?: number | undefined;
|
|
37
|
+
/** Minimum number of words required to interrupt the assistant. */
|
|
38
|
+
min_words_to_interrupt?: number | undefined;
|
|
39
|
+
/** Whether to have the no-input poke text be generated by AI */
|
|
40
|
+
generate_no_input_poke_text?: boolean | undefined;
|
|
41
|
+
/** Seconds of silence before poke message */
|
|
42
|
+
no_input_poke_sec?: (number | null) | undefined;
|
|
43
|
+
/** Poke message text. Ignored when generate_no_input_poke_text is true. */
|
|
44
|
+
no_input_poke_text?: string | undefined;
|
|
45
|
+
/** Seconds of silence before ending conversation */
|
|
46
|
+
no_input_end_conversation_sec?: number | undefined;
|
|
47
|
+
/** ISO 639-1 language code that sets the agent's default language to recognize and speak. Welcome message and no input poke text should be in this language. */
|
|
48
|
+
default_language?: string | undefined;
|
|
49
|
+
/** Array of additional ISO 639-1 language codes that the agent should be able to recognize and speak. Should not include `default_language`. */
|
|
50
|
+
additional_languages?: string[] | undefined;
|
|
51
|
+
/** If `"auto"`, each user audio is automatically identified for the language to respond in. If `"request"`, user must request to change language (recommended). */
|
|
52
|
+
multilingual_mode?: ConfigOptions.MultilingualMode | undefined;
|
|
53
|
+
/** Keywords to boost in speech recognition */
|
|
54
|
+
boosted_keywords?: string[] | undefined;
|
|
55
|
+
/** Names of tools available to the assistant. */
|
|
56
|
+
tools?: ConfigOptions.Tools.Item[] | undefined;
|
|
57
|
+
/** Template variables for system prompt and welcome message */
|
|
58
|
+
template_variables?: Record<string, string> | undefined;
|
|
59
|
+
}
|
|
60
|
+
export declare namespace ConfigOptions {
|
|
61
|
+
/** Background noise type for the conversation */
|
|
62
|
+
const BackgroundNoise: {
|
|
63
|
+
readonly Office: "office";
|
|
64
|
+
readonly CallCenter: "call-center";
|
|
65
|
+
readonly CoffeeShop: "coffee-shop";
|
|
66
|
+
};
|
|
67
|
+
type BackgroundNoise = (typeof BackgroundNoise)[keyof typeof BackgroundNoise];
|
|
68
|
+
/** Audio input format */
|
|
69
|
+
const InputFormat: {
|
|
70
|
+
readonly Pcm44100: "pcm_44100";
|
|
71
|
+
readonly Pcm16000: "pcm_16000";
|
|
72
|
+
readonly Pcm8000: "pcm_8000";
|
|
73
|
+
readonly Mulaw8000: "mulaw_8000";
|
|
74
|
+
};
|
|
75
|
+
type InputFormat = (typeof InputFormat)[keyof typeof InputFormat];
|
|
76
|
+
/** Audio output format */
|
|
77
|
+
const OutputFormat: {
|
|
78
|
+
readonly Pcm44100: "pcm_44100";
|
|
79
|
+
readonly Pcm16000: "pcm_16000";
|
|
80
|
+
readonly Pcm8000: "pcm_8000";
|
|
81
|
+
readonly Mulaw8000: "mulaw_8000";
|
|
82
|
+
};
|
|
83
|
+
type OutputFormat = (typeof OutputFormat)[keyof typeof OutputFormat];
|
|
84
|
+
/** If `"auto"`, each user audio is automatically identified for the language to respond in. If `"request"`, user must request to change language (recommended). */
|
|
85
|
+
const MultilingualMode: {
|
|
86
|
+
readonly Auto: "auto";
|
|
87
|
+
readonly Request: "request";
|
|
88
|
+
};
|
|
89
|
+
type MultilingualMode = (typeof MultilingualMode)[keyof typeof MultilingualMode];
|
|
90
|
+
type Tools = Tools.Item[];
|
|
91
|
+
namespace Tools {
|
|
92
|
+
type Item = string | Record<string, unknown>;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
export var ConfigOptions;
|
|
3
|
+
(function (ConfigOptions) {
|
|
4
|
+
/** Background noise type for the conversation */
|
|
5
|
+
ConfigOptions.BackgroundNoise = {
|
|
6
|
+
Office: "office",
|
|
7
|
+
CallCenter: "call-center",
|
|
8
|
+
CoffeeShop: "coffee-shop",
|
|
9
|
+
};
|
|
10
|
+
/** Audio input format */
|
|
11
|
+
ConfigOptions.InputFormat = {
|
|
12
|
+
Pcm44100: "pcm_44100",
|
|
13
|
+
Pcm16000: "pcm_16000",
|
|
14
|
+
Pcm8000: "pcm_8000",
|
|
15
|
+
Mulaw8000: "mulaw_8000",
|
|
16
|
+
};
|
|
17
|
+
/** Audio output format */
|
|
18
|
+
ConfigOptions.OutputFormat = {
|
|
19
|
+
Pcm44100: "pcm_44100",
|
|
20
|
+
Pcm16000: "pcm_16000",
|
|
21
|
+
Pcm8000: "pcm_8000",
|
|
22
|
+
Mulaw8000: "mulaw_8000",
|
|
23
|
+
};
|
|
24
|
+
/** If `"auto"`, each user audio is automatically identified for the language to respond in. If `"request"`, user must request to change language (recommended). */
|
|
25
|
+
ConfigOptions.MultilingualMode = {
|
|
26
|
+
Auto: "auto",
|
|
27
|
+
Request: "request",
|
|
28
|
+
};
|
|
29
|
+
})(ConfigOptions || (ConfigOptions = {}));
|