supafone-labs 0.3.1 → 0.3.2
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/README.md +73 -1
- package/dist/cjs/index.d.ts +361 -3
- package/dist/cjs/index.js +441 -1
- package/dist/index.d.ts +361 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +440 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +802 -4
package/src/index.ts
CHANGED
|
@@ -75,11 +75,51 @@ export interface UsageToday {
|
|
|
75
75
|
usage: Record<string, { used: number; cap: number }>;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
export interface LabsLogEntry {
|
|
79
|
+
id: number;
|
|
80
|
+
at: string;
|
|
81
|
+
endpoint: string;
|
|
82
|
+
seconds_billed: number;
|
|
83
|
+
duration_ms: number;
|
|
84
|
+
detail: string;
|
|
85
|
+
meta: Record<string, unknown>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface StreamLogsOptions {
|
|
89
|
+
limit?: number;
|
|
90
|
+
afterId?: number;
|
|
91
|
+
pollMs?: number;
|
|
92
|
+
snapshot?: boolean;
|
|
93
|
+
signal?: AbortSignal;
|
|
94
|
+
}
|
|
95
|
+
|
|
78
96
|
export type LabsAgentType = "phone" | "web" | "campaign";
|
|
79
97
|
export type LabsAgentStyle = "inbound" | "outbound";
|
|
80
98
|
export type LabsRuntimeMode = "multi_stage" | "single_stage";
|
|
81
99
|
export type LabsTelephonyMode = "supafone_managed" | "byok";
|
|
82
|
-
export type LabsTelephonyProvider =
|
|
100
|
+
export type LabsTelephonyProvider =
|
|
101
|
+
| "supafone"
|
|
102
|
+
| "twilio"
|
|
103
|
+
| "telnyx"
|
|
104
|
+
| "plivo"
|
|
105
|
+
| "signalwire"
|
|
106
|
+
| "sip"
|
|
107
|
+
| "custom_sip"
|
|
108
|
+
| "custom"
|
|
109
|
+
| string;
|
|
110
|
+
export type LabsNumberStrategy = "default_pool" | "dedicated" | "premium" | "byok" | string;
|
|
111
|
+
|
|
112
|
+
export interface LabsCallStage {
|
|
113
|
+
key?: string;
|
|
114
|
+
id?: string;
|
|
115
|
+
name: string;
|
|
116
|
+
goal?: string;
|
|
117
|
+
instructions?: string;
|
|
118
|
+
exitCriteria?: string[];
|
|
119
|
+
exit_criteria?: string[];
|
|
120
|
+
tools?: string[];
|
|
121
|
+
metadata?: Record<string, unknown>;
|
|
122
|
+
}
|
|
83
123
|
|
|
84
124
|
export interface LabsVoiceSelection {
|
|
85
125
|
provider?: string;
|
|
@@ -89,9 +129,51 @@ export interface LabsVoiceSelection {
|
|
|
89
129
|
}
|
|
90
130
|
|
|
91
131
|
export interface LabsProviderKeys {
|
|
132
|
+
/** Agent runtime/platform providers. */
|
|
92
133
|
ultravox?: string;
|
|
93
134
|
ultravoxApiKey?: string;
|
|
94
135
|
ultravox_api_key?: string;
|
|
136
|
+
retell?: string;
|
|
137
|
+
retellApiKey?: string;
|
|
138
|
+
retell_api_key?: string;
|
|
139
|
+
vapi?: string;
|
|
140
|
+
vapiApiKey?: string;
|
|
141
|
+
vapi_api_key?: string;
|
|
142
|
+
bland?: string;
|
|
143
|
+
blandApiKey?: string;
|
|
144
|
+
bland_api_key?: string;
|
|
145
|
+
livekit?: string;
|
|
146
|
+
livekitApiKey?: string;
|
|
147
|
+
livekit_api_key?: string;
|
|
148
|
+
livekitApiSecret?: string;
|
|
149
|
+
livekit_api_secret?: string;
|
|
150
|
+
pipecat?: string;
|
|
151
|
+
pipecatApiKey?: string;
|
|
152
|
+
pipecat_api_key?: string;
|
|
153
|
+
/** Telephony/carrier providers. */
|
|
154
|
+
twilio?: string;
|
|
155
|
+
twilioAccountSid?: string;
|
|
156
|
+
twilio_account_sid?: string;
|
|
157
|
+
twilioAuthToken?: string;
|
|
158
|
+
twilio_auth_token?: string;
|
|
159
|
+
twilioApiKeySid?: string;
|
|
160
|
+
twilio_api_key_sid?: string;
|
|
161
|
+
twilioApiKeySecret?: string;
|
|
162
|
+
twilio_api_key_secret?: string;
|
|
163
|
+
telnyx?: string;
|
|
164
|
+
telnyxApiKey?: string;
|
|
165
|
+
telnyx_api_key?: string;
|
|
166
|
+
plivo?: string;
|
|
167
|
+
plivoAuthId?: string;
|
|
168
|
+
plivo_auth_id?: string;
|
|
169
|
+
plivoAuthToken?: string;
|
|
170
|
+
plivo_auth_token?: string;
|
|
171
|
+
signalwire?: string;
|
|
172
|
+
signalwireApiToken?: string;
|
|
173
|
+
signalwire_api_token?: string;
|
|
174
|
+
signalwireProjectId?: string;
|
|
175
|
+
signalwire_project_id?: string;
|
|
176
|
+
/** TTS providers. */
|
|
95
177
|
elevenlabs?: string;
|
|
96
178
|
elevenlabsApiKey?: string;
|
|
97
179
|
elevenlabs_api_key?: string;
|
|
@@ -104,6 +186,65 @@ export interface LabsProviderKeys {
|
|
|
104
186
|
deepgram?: string;
|
|
105
187
|
deepgramApiKey?: string;
|
|
106
188
|
deepgram_api_key?: string;
|
|
189
|
+
/** Brain/STT providers used by Labs watcher or customer BYOK stacks. */
|
|
190
|
+
anthropic?: string;
|
|
191
|
+
anthropicApiKey?: string;
|
|
192
|
+
anthropic_api_key?: string;
|
|
193
|
+
openai?: string;
|
|
194
|
+
openaiApiKey?: string;
|
|
195
|
+
openai_api_key?: string;
|
|
196
|
+
xai?: string;
|
|
197
|
+
xaiApiKey?: string;
|
|
198
|
+
xai_api_key?: string;
|
|
199
|
+
[extra: string]: unknown;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export interface LabsCustomSipConfig {
|
|
203
|
+
sipTrunkUri?: string;
|
|
204
|
+
sip_trunk_uri?: string;
|
|
205
|
+
trunkUri?: string;
|
|
206
|
+
trunk_uri?: string;
|
|
207
|
+
sipHost?: string;
|
|
208
|
+
sip_host?: string;
|
|
209
|
+
fromNumber?: string;
|
|
210
|
+
from_number?: string;
|
|
211
|
+
username?: string;
|
|
212
|
+
password?: string;
|
|
213
|
+
transport?: string;
|
|
214
|
+
headers?: Record<string, string>;
|
|
215
|
+
codecs?: string[];
|
|
216
|
+
dtmfMode?: string;
|
|
217
|
+
dtmf_mode?: string;
|
|
218
|
+
metadata?: Record<string, unknown>;
|
|
219
|
+
[extra: string]: unknown;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export interface LabsProviderByokConfig {
|
|
223
|
+
provider?: string;
|
|
224
|
+
apiKey?: string;
|
|
225
|
+
api_key?: string;
|
|
226
|
+
credentials?: Record<string, unknown>;
|
|
227
|
+
settings?: Record<string, unknown>;
|
|
228
|
+
model?: string;
|
|
229
|
+
voiceId?: string;
|
|
230
|
+
voice_id?: string;
|
|
231
|
+
[extra: string]: unknown;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export interface LabsByokConfig {
|
|
235
|
+
providerKeys?: LabsProviderKeys;
|
|
236
|
+
provider_keys?: LabsProviderKeys;
|
|
237
|
+
agentProvider?: LabsProviderByokConfig;
|
|
238
|
+
agent_provider?: LabsProviderByokConfig;
|
|
239
|
+
runtime?: LabsProviderByokConfig;
|
|
240
|
+
telephony?: LabsTelephonyConfig;
|
|
241
|
+
tts?: LabsProviderByokConfig;
|
|
242
|
+
stt?: LabsProviderByokConfig;
|
|
243
|
+
llm?: LabsProviderByokConfig;
|
|
244
|
+
customSip?: LabsCustomSipConfig;
|
|
245
|
+
custom_sip?: LabsCustomSipConfig;
|
|
246
|
+
sip?: LabsCustomSipConfig;
|
|
247
|
+
[extra: string]: unknown;
|
|
107
248
|
}
|
|
108
249
|
|
|
109
250
|
export interface LabsTelephonyCredentials {
|
|
@@ -119,6 +260,20 @@ export interface LabsTelephonyCredentials {
|
|
|
119
260
|
auth_id?: string;
|
|
120
261
|
connectionId?: string;
|
|
121
262
|
connection_id?: string;
|
|
263
|
+
telnyxConnectionId?: string;
|
|
264
|
+
telnyx_connection_id?: string;
|
|
265
|
+
signalwireSpaceUrl?: string;
|
|
266
|
+
signalwire_space_url?: string;
|
|
267
|
+
projectId?: string;
|
|
268
|
+
project_id?: string;
|
|
269
|
+
applicationId?: string;
|
|
270
|
+
application_id?: string;
|
|
271
|
+
trunkId?: string;
|
|
272
|
+
trunk_id?: string;
|
|
273
|
+
endpointId?: string;
|
|
274
|
+
endpoint_id?: string;
|
|
275
|
+
token?: string;
|
|
276
|
+
secret?: string;
|
|
122
277
|
fromNumber?: string;
|
|
123
278
|
from_number?: string;
|
|
124
279
|
sipTrunkUri?: string;
|
|
@@ -129,6 +284,9 @@ export interface LabsTelephonyCredentials {
|
|
|
129
284
|
password?: string;
|
|
130
285
|
webhookSecret?: string;
|
|
131
286
|
webhook_secret?: string;
|
|
287
|
+
customSip?: LabsCustomSipConfig;
|
|
288
|
+
custom_sip?: LabsCustomSipConfig;
|
|
289
|
+
[extra: string]: unknown;
|
|
132
290
|
}
|
|
133
291
|
|
|
134
292
|
export interface LabsTelephonyConfig {
|
|
@@ -137,9 +295,22 @@ export interface LabsTelephonyConfig {
|
|
|
137
295
|
/** Default is Supafone-managed; developers do not need Twilio for this path. */
|
|
138
296
|
mode?: LabsTelephonyMode;
|
|
139
297
|
provider?: LabsTelephonyProvider;
|
|
298
|
+
/** default_pool reuses idle Supafone numbers; dedicated/premium reserve a number-month. */
|
|
299
|
+
numberStrategy?: LabsNumberStrategy;
|
|
300
|
+
number_strategy?: LabsNumberStrategy;
|
|
301
|
+
numberPool?: string;
|
|
302
|
+
number_pool?: string;
|
|
303
|
+
numberId?: string;
|
|
304
|
+
number_id?: string;
|
|
305
|
+
premium?: boolean;
|
|
140
306
|
label?: string;
|
|
141
307
|
credentials?: LabsTelephonyCredentials;
|
|
308
|
+
providerSettings?: Record<string, unknown>;
|
|
309
|
+
provider_settings?: Record<string, unknown>;
|
|
310
|
+
customSip?: LabsCustomSipConfig;
|
|
311
|
+
custom_sip?: LabsCustomSipConfig;
|
|
142
312
|
metadata?: Record<string, unknown>;
|
|
313
|
+
[extra: string]: unknown;
|
|
143
314
|
}
|
|
144
315
|
|
|
145
316
|
export interface LabsToolsConfig {
|
|
@@ -161,11 +332,61 @@ export interface LabsToolsConfig {
|
|
|
161
332
|
custom_tools?: Array<Record<string, unknown>>;
|
|
162
333
|
}
|
|
163
334
|
|
|
335
|
+
export interface LabsRecordingConfig {
|
|
336
|
+
enabled?: boolean;
|
|
337
|
+
recordAudio?: boolean;
|
|
338
|
+
record_audio?: boolean;
|
|
339
|
+
consentRequired?: boolean;
|
|
340
|
+
consent_required?: boolean;
|
|
341
|
+
announcement?: string;
|
|
342
|
+
retentionDays?: number;
|
|
343
|
+
retention_days?: number;
|
|
344
|
+
storage?: "supafone_managed" | "byok" | string;
|
|
345
|
+
redactPii?: boolean;
|
|
346
|
+
redact_pii?: boolean;
|
|
347
|
+
metadata?: Record<string, unknown>;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export interface LabsTranscriptionConfig {
|
|
351
|
+
enabled?: boolean;
|
|
352
|
+
provider?: string;
|
|
353
|
+
model?: string;
|
|
354
|
+
language?: string;
|
|
355
|
+
redactPii?: boolean;
|
|
356
|
+
redact_pii?: boolean;
|
|
357
|
+
diarization?: boolean;
|
|
358
|
+
timestamps?: boolean;
|
|
359
|
+
metadata?: Record<string, unknown>;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export interface LabsArtifactsConfig {
|
|
363
|
+
recordings?: boolean;
|
|
364
|
+
transcripts?: boolean;
|
|
365
|
+
summaries?: boolean;
|
|
366
|
+
qaReports?: boolean;
|
|
367
|
+
qa_reports?: boolean;
|
|
368
|
+
logs?: boolean;
|
|
369
|
+
webhooks?: boolean;
|
|
370
|
+
retentionDays?: number;
|
|
371
|
+
retention_days?: number;
|
|
372
|
+
metadata?: Record<string, unknown>;
|
|
373
|
+
}
|
|
374
|
+
|
|
164
375
|
export interface LabsWatcherConfig {
|
|
165
376
|
enabled?: boolean;
|
|
166
377
|
voiceWatcher?: boolean;
|
|
167
378
|
voice_watcher?: boolean;
|
|
379
|
+
apiKey?: string;
|
|
380
|
+
api_key?: string;
|
|
168
381
|
model?: string;
|
|
382
|
+
mode?: "supafone_managed" | "byok" | string;
|
|
383
|
+
managedInfrastructure?: boolean;
|
|
384
|
+
managed_infrastructure?: boolean;
|
|
385
|
+
stt?: Record<string, unknown>;
|
|
386
|
+
llm?: Record<string, unknown>;
|
|
387
|
+
tts?: Record<string, unknown>;
|
|
388
|
+
providerKeys?: Record<string, unknown>;
|
|
389
|
+
provider_keys?: Record<string, unknown>;
|
|
169
390
|
label?: string;
|
|
170
391
|
}
|
|
171
392
|
|
|
@@ -211,6 +432,10 @@ export interface LabsUltravoxRuntime {
|
|
|
211
432
|
retention_policy?: string;
|
|
212
433
|
callTemplate?: Record<string, unknown>;
|
|
213
434
|
call_template?: Record<string, unknown>;
|
|
435
|
+
customSip?: LabsCustomSipConfig;
|
|
436
|
+
custom_sip?: LabsCustomSipConfig;
|
|
437
|
+
sip?: LabsCustomSipConfig;
|
|
438
|
+
[extra: string]: unknown;
|
|
214
439
|
}
|
|
215
440
|
|
|
216
441
|
export interface CreateLabsAgentRequest {
|
|
@@ -234,11 +459,22 @@ export interface CreateLabsAgentRequest {
|
|
|
234
459
|
website_url?: string;
|
|
235
460
|
phoneNumber?: string;
|
|
236
461
|
phone_number?: string;
|
|
462
|
+
numberStrategy?: LabsNumberStrategy;
|
|
463
|
+
number_strategy?: LabsNumberStrategy;
|
|
464
|
+
numberPool?: string;
|
|
465
|
+
number_pool?: string;
|
|
466
|
+
premium?: boolean;
|
|
237
467
|
direction?: string;
|
|
238
468
|
presetKey?: string;
|
|
239
469
|
preset_key?: string;
|
|
240
470
|
runtimeMode?: LabsRuntimeMode;
|
|
241
471
|
runtime_mode?: LabsRuntimeMode;
|
|
472
|
+
/** Default true. When true, the SDK creates sensible call stages from prompt metadata. */
|
|
473
|
+
callStages?: boolean | LabsCallStage[];
|
|
474
|
+
call_stages?: boolean | LabsCallStage[];
|
|
475
|
+
stages?: LabsCallStage[];
|
|
476
|
+
autoCallStages?: boolean;
|
|
477
|
+
auto_call_stages?: boolean;
|
|
242
478
|
goal?: string;
|
|
243
479
|
greeting?: string;
|
|
244
480
|
systemPrompt?: string;
|
|
@@ -247,8 +483,15 @@ export interface CreateLabsAgentRequest {
|
|
|
247
483
|
voice?: LabsVoiceSelection;
|
|
248
484
|
providerKeys?: LabsProviderKeys;
|
|
249
485
|
provider_keys?: LabsProviderKeys;
|
|
250
|
-
byok?: LabsProviderKeys;
|
|
486
|
+
byok?: LabsProviderKeys | LabsByokConfig;
|
|
251
487
|
telephony?: LabsTelephonyConfig;
|
|
488
|
+
customSip?: LabsCustomSipConfig;
|
|
489
|
+
custom_sip?: LabsCustomSipConfig;
|
|
490
|
+
sip?: LabsCustomSipConfig;
|
|
491
|
+
recording?: LabsRecordingConfig;
|
|
492
|
+
transcription?: LabsTranscriptionConfig;
|
|
493
|
+
artifacts?: LabsArtifactsConfig;
|
|
494
|
+
compliance?: Record<string, unknown>;
|
|
252
495
|
tools?: LabsToolsConfig;
|
|
253
496
|
labs?: LabsWatcherConfig;
|
|
254
497
|
ultravox?: LabsUltravoxRuntime;
|
|
@@ -267,6 +510,21 @@ export interface ListLabsAgentsOptions {
|
|
|
267
510
|
|
|
268
511
|
export interface GetLabsAgentOptions extends ListLabsAgentsOptions {}
|
|
269
512
|
|
|
513
|
+
export interface DeleteLabsAgentOptions {
|
|
514
|
+
agencyId?: string;
|
|
515
|
+
agency_id?: string;
|
|
516
|
+
releaseNumbers?: boolean;
|
|
517
|
+
release_numbers?: boolean;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
export interface DeleteLabsAgentResponse {
|
|
521
|
+
success?: boolean;
|
|
522
|
+
deleted?: boolean;
|
|
523
|
+
agent_key?: string;
|
|
524
|
+
released_numbers?: unknown[];
|
|
525
|
+
[extra: string]: unknown;
|
|
526
|
+
}
|
|
527
|
+
|
|
270
528
|
export interface LabsCapabilitiesResponse {
|
|
271
529
|
product: string;
|
|
272
530
|
api_namespace: string;
|
|
@@ -299,9 +557,57 @@ export interface LabsVoiceListResponse {
|
|
|
299
557
|
errors?: Record<string, string>;
|
|
300
558
|
}
|
|
301
559
|
|
|
560
|
+
export interface LabsCallListOptions {
|
|
561
|
+
agencyId?: string;
|
|
562
|
+
agentKey?: string;
|
|
563
|
+
agent_key?: string;
|
|
564
|
+
limit?: number;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
export interface LabsCallArtifact {
|
|
568
|
+
id?: string;
|
|
569
|
+
call_id?: string;
|
|
570
|
+
agent_key?: string;
|
|
571
|
+
status?: string;
|
|
572
|
+
started_at?: string;
|
|
573
|
+
duration_seconds?: number;
|
|
574
|
+
recording_url?: string;
|
|
575
|
+
transcript_url?: string;
|
|
576
|
+
[extra: string]: unknown;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
export interface LabsCallListResponse {
|
|
580
|
+
calls: LabsCallArtifact[];
|
|
581
|
+
[extra: string]: unknown;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
export interface LabsRecordingListOptions extends LabsCallListOptions {
|
|
585
|
+
callId?: string;
|
|
586
|
+
call_id?: string;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
export interface LabsRecordingListResponse {
|
|
590
|
+
recordings: Array<Record<string, unknown>>;
|
|
591
|
+
[extra: string]: unknown;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
export interface LabsTranscriptListOptions extends LabsCallListOptions {
|
|
595
|
+
callId?: string;
|
|
596
|
+
call_id?: string;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
export interface LabsTranscriptListResponse {
|
|
600
|
+
transcripts: Array<Record<string, unknown>>;
|
|
601
|
+
[extra: string]: unknown;
|
|
602
|
+
}
|
|
603
|
+
|
|
302
604
|
export interface LabsPhoneNumberSearchOptions {
|
|
303
605
|
agencyId?: string;
|
|
304
606
|
agency_id?: string;
|
|
607
|
+
numberPool?: string;
|
|
608
|
+
number_pool?: string;
|
|
609
|
+
numberStrategy?: LabsNumberStrategy;
|
|
610
|
+
number_strategy?: LabsNumberStrategy;
|
|
305
611
|
countryCode?: string;
|
|
306
612
|
country_code?: string;
|
|
307
613
|
areaCode?: string;
|
|
@@ -376,6 +682,11 @@ export interface LabsPhoneNumberProvisionRequest {
|
|
|
376
682
|
agent_name?: string;
|
|
377
683
|
presetKey?: string;
|
|
378
684
|
preset_key?: string;
|
|
685
|
+
numberStrategy?: LabsNumberStrategy;
|
|
686
|
+
number_strategy?: LabsNumberStrategy;
|
|
687
|
+
numberPool?: string;
|
|
688
|
+
number_pool?: string;
|
|
689
|
+
premium?: boolean;
|
|
379
690
|
style?: LabsAgentStyle;
|
|
380
691
|
agentStyle?: LabsAgentStyle;
|
|
381
692
|
agent_style?: LabsAgentStyle;
|
|
@@ -386,6 +697,15 @@ export interface LabsPhoneNumberProvisionRequest {
|
|
|
386
697
|
|
|
387
698
|
export interface LabsPhoneNumberAssignRequest extends Omit<LabsPhoneNumberProvisionRequest, "phoneNumber" | "phone_number" | "departmentId" | "department_id"> {}
|
|
388
699
|
|
|
700
|
+
export interface LabsPhoneNumberReleaseRequest {
|
|
701
|
+
agencyId?: string;
|
|
702
|
+
agency_id?: string;
|
|
703
|
+
reason?: string;
|
|
704
|
+
returnToPool?: boolean;
|
|
705
|
+
return_to_pool?: boolean;
|
|
706
|
+
metadata?: Record<string, unknown>;
|
|
707
|
+
}
|
|
708
|
+
|
|
389
709
|
export interface LabsPhoneNumberProvisionResponse {
|
|
390
710
|
success: boolean;
|
|
391
711
|
number: LabsPhoneNumberRecord;
|
|
@@ -400,6 +720,14 @@ export interface LabsPhoneNumberAssignResponse {
|
|
|
400
720
|
assignment?: Record<string, unknown>;
|
|
401
721
|
}
|
|
402
722
|
|
|
723
|
+
export interface LabsPhoneNumberReleaseResponse {
|
|
724
|
+
success: boolean;
|
|
725
|
+
number?: LabsPhoneNumberRecord;
|
|
726
|
+
released?: boolean;
|
|
727
|
+
returned_to_pool?: boolean;
|
|
728
|
+
[extra: string]: unknown;
|
|
729
|
+
}
|
|
730
|
+
|
|
403
731
|
export interface LabsPhoneNumberBuyAndAssignRequest extends LabsPhoneNumberProvisionRequest {
|
|
404
732
|
search?: LabsPhoneNumberSearchOptions;
|
|
405
733
|
}
|
|
@@ -685,6 +1013,14 @@ export class SupafoneLabs {
|
|
|
685
1013
|
}
|
|
686
1014
|
}
|
|
687
1015
|
|
|
1016
|
+
/** Convenience alias for voice preview UI/buttons. */
|
|
1017
|
+
previewVoice(
|
|
1018
|
+
voice = "supafone-labs-calm-en",
|
|
1019
|
+
text = "Hi, this is your Supafone agent voice preview.",
|
|
1020
|
+
): Promise<Uint8Array> {
|
|
1021
|
+
return this.tts(text, voice);
|
|
1022
|
+
}
|
|
1023
|
+
|
|
688
1024
|
/** Hosted STT for a finished audio clip — returns transcript + language tags. */
|
|
689
1025
|
async stt(
|
|
690
1026
|
audio: Uint8Array | ArrayBuffer,
|
|
@@ -742,10 +1078,47 @@ export class SupafoneLabs {
|
|
|
742
1078
|
}
|
|
743
1079
|
|
|
744
1080
|
/** The auditable whisper/billing log. */
|
|
745
|
-
logs(limit = 100): Promise<{ logs:
|
|
1081
|
+
logs(limit = 100): Promise<{ logs: LabsLogEntry[] }> {
|
|
746
1082
|
return this.request("GET", `/v1/logs?limit=${limit}`);
|
|
747
1083
|
}
|
|
748
1084
|
|
|
1085
|
+
/** Live audit-log stream. Works in Node 18+ and browsers via fetch streaming. */
|
|
1086
|
+
async *streamLogs(opts: StreamLogsOptions = {}): AsyncGenerator<LabsLogEntry> {
|
|
1087
|
+
const q = new URLSearchParams({
|
|
1088
|
+
limit: String(opts.limit ?? 100),
|
|
1089
|
+
poll_ms: String(opts.pollMs ?? 1000),
|
|
1090
|
+
snapshot: String(opts.snapshot ?? true),
|
|
1091
|
+
});
|
|
1092
|
+
if (opts.afterId !== undefined) q.set("after_id", String(opts.afterId));
|
|
1093
|
+
const res = await fetch(`${this.baseUrl}/v1/logs/stream?${q}`, {
|
|
1094
|
+
method: "GET",
|
|
1095
|
+
signal: opts.signal,
|
|
1096
|
+
headers: { Authorization: `Bearer ${this.apiKey}` },
|
|
1097
|
+
});
|
|
1098
|
+
if (!res.ok) throw new SupafoneLabsError(`streamLogs: ${await res.text()}`, res.status);
|
|
1099
|
+
if (!res.body) throw new SupafoneLabsError("streamLogs: response body is not readable");
|
|
1100
|
+
const reader = res.body.getReader();
|
|
1101
|
+
const decoder = new TextDecoder();
|
|
1102
|
+
let buffer = "";
|
|
1103
|
+
try {
|
|
1104
|
+
for (;;) {
|
|
1105
|
+
const { done, value } = await reader.read();
|
|
1106
|
+
if (done) break;
|
|
1107
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1108
|
+
let split = buffer.indexOf("\n\n");
|
|
1109
|
+
while (split >= 0) {
|
|
1110
|
+
const raw = buffer.slice(0, split);
|
|
1111
|
+
buffer = buffer.slice(split + 2);
|
|
1112
|
+
const parsed = parseSseLog(raw);
|
|
1113
|
+
if (parsed) yield parsed;
|
|
1114
|
+
split = buffer.indexOf("\n\n");
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
} finally {
|
|
1118
|
+
reader.releaseLock();
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
|
|
749
1122
|
/** The structured whisper feed (what the console shows). */
|
|
750
1123
|
nudges(limit = 50): Promise<{ nudges: unknown[] }> {
|
|
751
1124
|
return this.request("GET", `/v1/nudges?limit=${limit}`);
|
|
@@ -780,6 +1153,11 @@ export class SupafoneLabs {
|
|
|
780
1153
|
);
|
|
781
1154
|
return d.voices.map((v) => (typeof v === "string" ? v : (v.voice ?? v.id ?? ""))).filter(Boolean);
|
|
782
1155
|
}
|
|
1156
|
+
|
|
1157
|
+
/** Full hosted voice catalog with provider live/configured flags. */
|
|
1158
|
+
voiceCatalog(): Promise<{ voices: Array<Record<string, unknown>> }> {
|
|
1159
|
+
return this.request("GET", "/v1/voices");
|
|
1160
|
+
}
|
|
783
1161
|
}
|
|
784
1162
|
|
|
785
1163
|
export interface LiveTranscribeOptions {
|
|
@@ -856,6 +1234,9 @@ class LabsNamespace {
|
|
|
856
1234
|
readonly voices: LabsVoicesNamespace;
|
|
857
1235
|
readonly phoneNumbers: LabsPhoneNumbersNamespace;
|
|
858
1236
|
readonly telephony: LabsTelephonyNamespace;
|
|
1237
|
+
readonly calls: LabsCallsNamespace;
|
|
1238
|
+
readonly recordings: LabsRecordingsNamespace;
|
|
1239
|
+
readonly transcripts: LabsTranscriptsNamespace;
|
|
859
1240
|
|
|
860
1241
|
constructor(private sm: SupafoneLabs) {
|
|
861
1242
|
this.agents = new LabsAgentsNamespace(sm);
|
|
@@ -864,6 +1245,9 @@ class LabsNamespace {
|
|
|
864
1245
|
this.voices = new LabsVoicesNamespace(sm);
|
|
865
1246
|
this.phoneNumbers = new LabsPhoneNumbersNamespace(sm);
|
|
866
1247
|
this.telephony = new LabsTelephonyNamespace(sm);
|
|
1248
|
+
this.calls = new LabsCallsNamespace(sm);
|
|
1249
|
+
this.recordings = new LabsRecordingsNamespace(sm);
|
|
1250
|
+
this.transcripts = new LabsTranscriptsNamespace(sm);
|
|
867
1251
|
}
|
|
868
1252
|
|
|
869
1253
|
/** Discover the Supafone convenience layer over Ultravox. */
|
|
@@ -971,6 +1355,20 @@ class LabsAgentsNamespace {
|
|
|
971
1355
|
`/api/v1/labs/agents/${encodeURIComponent(agentKey)}${suffix}`,
|
|
972
1356
|
);
|
|
973
1357
|
}
|
|
1358
|
+
|
|
1359
|
+
/** Delete an agent. Optionally ask the backend to release assigned numbers. */
|
|
1360
|
+
delete(agentKey: string, opts: DeleteLabsAgentOptions = {}): Promise<DeleteLabsAgentResponse> {
|
|
1361
|
+
const q = new URLSearchParams();
|
|
1362
|
+
const agencyId = opts.agency_id ?? opts.agencyId;
|
|
1363
|
+
const releaseNumbers = opts.release_numbers ?? opts.releaseNumbers;
|
|
1364
|
+
if (agencyId) q.set("agency_id", agencyId);
|
|
1365
|
+
if (releaseNumbers !== undefined) q.set("release_numbers", String(releaseNumbers));
|
|
1366
|
+
const suffix = q.toString() ? `?${q}` : "";
|
|
1367
|
+
return this.sm.requestSupafoneApi<DeleteLabsAgentResponse>(
|
|
1368
|
+
"DELETE",
|
|
1369
|
+
`/api/v1/labs/agents/${encodeURIComponent(agentKey)}${suffix}`,
|
|
1370
|
+
);
|
|
1371
|
+
}
|
|
974
1372
|
}
|
|
975
1373
|
|
|
976
1374
|
class LabsPresetsNamespace {
|
|
@@ -1003,6 +1401,69 @@ class LabsVoicesNamespace {
|
|
|
1003
1401
|
}
|
|
1004
1402
|
}
|
|
1005
1403
|
|
|
1404
|
+
class LabsCallsNamespace {
|
|
1405
|
+
constructor(private sm: SupafoneLabs) {}
|
|
1406
|
+
|
|
1407
|
+
list(opts: LabsCallListOptions = {}): Promise<LabsCallListResponse> {
|
|
1408
|
+
const q = hostedListQuery(opts);
|
|
1409
|
+
const suffix = q.toString() ? `?${q}` : "";
|
|
1410
|
+
return this.sm.requestSupafoneApi<LabsCallListResponse>("GET", `/api/v1/labs/calls${suffix}`);
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
get(callId: string, opts: { agencyId?: string } = {}): Promise<Record<string, unknown>> {
|
|
1414
|
+
const q = new URLSearchParams();
|
|
1415
|
+
if (opts.agencyId) q.set("agency_id", opts.agencyId);
|
|
1416
|
+
const suffix = q.toString() ? `?${q}` : "";
|
|
1417
|
+
return this.sm.requestSupafoneApi("GET", `/api/v1/labs/calls/${encodeURIComponent(callId)}${suffix}`);
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
class LabsRecordingsNamespace {
|
|
1422
|
+
constructor(private sm: SupafoneLabs) {}
|
|
1423
|
+
|
|
1424
|
+
list(opts: LabsRecordingListOptions = {}): Promise<LabsRecordingListResponse> {
|
|
1425
|
+
const q = hostedListQuery(opts);
|
|
1426
|
+
const callId = opts.call_id ?? opts.callId;
|
|
1427
|
+
if (callId) q.set("call_id", callId);
|
|
1428
|
+
const suffix = q.toString() ? `?${q}` : "";
|
|
1429
|
+
return this.sm.requestSupafoneApi<LabsRecordingListResponse>("GET", `/api/v1/labs/recordings${suffix}`);
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
get(recordingId: string, opts: { agencyId?: string } = {}): Promise<Record<string, unknown>> {
|
|
1433
|
+
const q = new URLSearchParams();
|
|
1434
|
+
if (opts.agencyId) q.set("agency_id", opts.agencyId);
|
|
1435
|
+
const suffix = q.toString() ? `?${q}` : "";
|
|
1436
|
+
return this.sm.requestSupafoneApi("GET", `/api/v1/labs/recordings/${encodeURIComponent(recordingId)}${suffix}`);
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
delete(recordingId: string, opts: { agencyId?: string; reason?: string } = {}): Promise<Record<string, unknown>> {
|
|
1440
|
+
const q = new URLSearchParams();
|
|
1441
|
+
if (opts.agencyId) q.set("agency_id", opts.agencyId);
|
|
1442
|
+
if (opts.reason) q.set("reason", opts.reason);
|
|
1443
|
+
const suffix = q.toString() ? `?${q}` : "";
|
|
1444
|
+
return this.sm.requestSupafoneApi("DELETE", `/api/v1/labs/recordings/${encodeURIComponent(recordingId)}${suffix}`);
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
class LabsTranscriptsNamespace {
|
|
1449
|
+
constructor(private sm: SupafoneLabs) {}
|
|
1450
|
+
|
|
1451
|
+
list(opts: LabsTranscriptListOptions = {}): Promise<LabsTranscriptListResponse> {
|
|
1452
|
+
const q = hostedListQuery(opts);
|
|
1453
|
+
const callId = opts.call_id ?? opts.callId;
|
|
1454
|
+
if (callId) q.set("call_id", callId);
|
|
1455
|
+
const suffix = q.toString() ? `?${q}` : "";
|
|
1456
|
+
return this.sm.requestSupafoneApi<LabsTranscriptListResponse>("GET", `/api/v1/labs/transcripts${suffix}`);
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
get(transcriptId: string, opts: { agencyId?: string } = {}): Promise<Record<string, unknown>> {
|
|
1460
|
+
const q = new URLSearchParams();
|
|
1461
|
+
if (opts.agencyId) q.set("agency_id", opts.agencyId);
|
|
1462
|
+
const suffix = q.toString() ? `?${q}` : "";
|
|
1463
|
+
return this.sm.requestSupafoneApi("GET", `/api/v1/labs/transcripts/${encodeURIComponent(transcriptId)}${suffix}`);
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1006
1467
|
class LabsPhoneNumbersNamespace {
|
|
1007
1468
|
constructor(private sm: SupafoneLabs) {}
|
|
1008
1469
|
|
|
@@ -1048,6 +1509,42 @@ class LabsPhoneNumbersNamespace {
|
|
|
1048
1509
|
);
|
|
1049
1510
|
}
|
|
1050
1511
|
|
|
1512
|
+
/** Unassign a number from an agent but keep it reserved on the account. */
|
|
1513
|
+
unassign(numberId: string, input: LabsPhoneNumberReleaseRequest = {}): Promise<LabsPhoneNumberReleaseResponse> {
|
|
1514
|
+
return this.sm.requestSupafoneApi<LabsPhoneNumberReleaseResponse>(
|
|
1515
|
+
"POST",
|
|
1516
|
+
`/api/v1/labs/phone-numbers/${encodeURIComponent(numberId)}/unassign`,
|
|
1517
|
+
phoneNumberReleasePayload(input),
|
|
1518
|
+
);
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
/** Give a number back to the shared pool or release the reservation. */
|
|
1522
|
+
release(numberId: string, input: LabsPhoneNumberReleaseRequest = {}): Promise<LabsPhoneNumberReleaseResponse> {
|
|
1523
|
+
return this.sm.requestSupafoneApi<LabsPhoneNumberReleaseResponse>(
|
|
1524
|
+
"POST",
|
|
1525
|
+
`/api/v1/labs/phone-numbers/${encodeURIComponent(numberId)}/release`,
|
|
1526
|
+
phoneNumberReleasePayload({ ...input, returnToPool: input.returnToPool ?? input.return_to_pool ?? true }),
|
|
1527
|
+
);
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
/** Alias for release(numberId, { returnToPool: true }). */
|
|
1531
|
+
returnToPool(numberId: string, input: LabsPhoneNumberReleaseRequest = {}): Promise<LabsPhoneNumberReleaseResponse> {
|
|
1532
|
+
return this.release(numberId, { ...input, returnToPool: true });
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
/** Delete/release a number reservation. Backend policy decides whether this is allowed. */
|
|
1536
|
+
delete(numberId: string, input: LabsPhoneNumberReleaseRequest = {}): Promise<LabsPhoneNumberReleaseResponse> {
|
|
1537
|
+
const q = new URLSearchParams();
|
|
1538
|
+
const agencyId = input.agency_id ?? input.agencyId;
|
|
1539
|
+
if (agencyId) q.set("agency_id", agencyId);
|
|
1540
|
+
const suffix = q.toString() ? `?${q}` : "";
|
|
1541
|
+
return this.sm.requestSupafoneApi<LabsPhoneNumberReleaseResponse>(
|
|
1542
|
+
"DELETE",
|
|
1543
|
+
`/api/v1/labs/phone-numbers/${encodeURIComponent(numberId)}${suffix}`,
|
|
1544
|
+
phoneNumberReleasePayload(input),
|
|
1545
|
+
);
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1051
1548
|
/**
|
|
1052
1549
|
* Search if needed, buy the first matching Supafone-managed number, and assign
|
|
1053
1550
|
* it to the supplied agent. This is the zero-Twilio-account happy path.
|
|
@@ -1159,6 +1656,16 @@ class OptimizerNamespace {
|
|
|
1159
1656
|
standing(agent = "builder"): Promise<{ version: number; text: string }> {
|
|
1160
1657
|
return this.sm.request("GET", `/v1/optimizer/standing?agent=${encodeURIComponent(agent)}`);
|
|
1161
1658
|
}
|
|
1659
|
+
/** SSR grade distribution: five nominal levels folded into a real score distribution. */
|
|
1660
|
+
distribution(agent = "builder", limit = 500): Promise<{
|
|
1661
|
+
agent: string; calls: number; counts: Record<string, number>;
|
|
1662
|
+
mean_score: number; buckets: number[]; bucket_edges: number[];
|
|
1663
|
+
}> {
|
|
1664
|
+
return this.sm.request(
|
|
1665
|
+
"GET",
|
|
1666
|
+
`/v1/objective/distribution?agent=${encodeURIComponent(agent)}&limit=${limit}`,
|
|
1667
|
+
);
|
|
1668
|
+
}
|
|
1162
1669
|
/** List the post-call reports behind the optimizer. */
|
|
1163
1670
|
reports(agent = "builder", limit = 40): Promise<{ reports: unknown[] }> {
|
|
1164
1671
|
return this.sm.request(
|
|
@@ -1180,17 +1687,26 @@ function labsAgentPayload(input: CreateLabsAgentRequest): Record<string, unknown
|
|
|
1180
1687
|
industry: input.industry,
|
|
1181
1688
|
website_url: input.website_url ?? input.websiteUrl,
|
|
1182
1689
|
phone_number: input.phone_number ?? input.phoneNumber,
|
|
1690
|
+
number_strategy: input.number_strategy ?? input.numberStrategy,
|
|
1691
|
+
number_pool: input.number_pool ?? input.numberPool,
|
|
1692
|
+
premium: input.premium,
|
|
1183
1693
|
direction: input.direction,
|
|
1184
1694
|
preset_key: input.preset_key ?? input.presetKey,
|
|
1185
1695
|
runtime_mode: input.runtime_mode ?? input.runtimeMode,
|
|
1696
|
+
call_stages: callStagesPayload(input),
|
|
1186
1697
|
goal: input.goal,
|
|
1187
1698
|
greeting: input.greeting,
|
|
1188
1699
|
system_prompt: input.system_prompt ?? input.systemPrompt,
|
|
1189
1700
|
language: input.language,
|
|
1190
1701
|
voice: input.voice ? voicePayload(input.voice) : undefined,
|
|
1191
1702
|
provider_keys: input.provider_keys ?? (input.providerKeys ? providerKeysPayload(input.providerKeys) : undefined),
|
|
1192
|
-
byok: input.byok ?
|
|
1703
|
+
byok: input.byok ? byokPayload(input.byok) : undefined,
|
|
1193
1704
|
telephony: input.telephony ? telephonyPayload(input.telephony) : undefined,
|
|
1705
|
+
custom_sip: customSipPayload(input.custom_sip ?? input.customSip ?? input.sip),
|
|
1706
|
+
recording: input.recording ? recordingPayload(input.recording) : undefined,
|
|
1707
|
+
transcription: input.transcription ? transcriptionPayload(input.transcription) : undefined,
|
|
1708
|
+
artifacts: input.artifacts ? artifactsPayload(input.artifacts) : undefined,
|
|
1709
|
+
compliance: input.compliance,
|
|
1194
1710
|
tools: input.tools ? toolsPayload(input.tools) : undefined,
|
|
1195
1711
|
labs: input.labs ? labsPayload(input.labs) : undefined,
|
|
1196
1712
|
ultravox: input.ultravox ? ultravoxPayload(input.ultravox) : undefined,
|
|
@@ -1200,13 +1716,28 @@ function labsAgentPayload(input: CreateLabsAgentRequest): Record<string, unknown
|
|
|
1200
1716
|
});
|
|
1201
1717
|
}
|
|
1202
1718
|
|
|
1719
|
+
function hostedListQuery(opts: LabsCallListOptions): URLSearchParams {
|
|
1720
|
+
const q = new URLSearchParams();
|
|
1721
|
+
if (opts.agencyId) q.set("agency_id", opts.agencyId);
|
|
1722
|
+
const agentKey = opts.agent_key ?? opts.agentKey;
|
|
1723
|
+
if (agentKey) q.set("agent_key", agentKey);
|
|
1724
|
+
if (opts.limit !== undefined) q.set("limit", String(opts.limit));
|
|
1725
|
+
return q;
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1203
1728
|
function telephonyPayload(input: LabsTelephonyConfig): Record<string, unknown> {
|
|
1204
1729
|
return compact({
|
|
1205
1730
|
agency_id: input.agency_id ?? input.agencyId,
|
|
1206
1731
|
mode: input.mode,
|
|
1207
1732
|
provider: input.provider,
|
|
1733
|
+
number_strategy: input.number_strategy ?? input.numberStrategy,
|
|
1734
|
+
number_pool: input.number_pool ?? input.numberPool,
|
|
1735
|
+
number_id: input.number_id ?? input.numberId,
|
|
1736
|
+
premium: input.premium,
|
|
1208
1737
|
label: input.label,
|
|
1209
1738
|
credentials: input.credentials ? telephonyCredentialsPayload(input.credentials) : undefined,
|
|
1739
|
+
provider_settings: input.provider_settings ?? input.providerSettings,
|
|
1740
|
+
custom_sip: customSipPayload(input.custom_sip ?? input.customSip),
|
|
1210
1741
|
metadata: input.metadata,
|
|
1211
1742
|
});
|
|
1212
1743
|
}
|
|
@@ -1225,12 +1756,23 @@ function telephonyCredentialsPayload(input: LabsTelephonyCredentials): Record<st
|
|
|
1225
1756
|
username: input.username,
|
|
1226
1757
|
password: input.password,
|
|
1227
1758
|
webhook_secret: input.webhook_secret ?? input.webhookSecret,
|
|
1759
|
+
telnyx_connection_id: input.telnyx_connection_id ?? input.telnyxConnectionId,
|
|
1760
|
+
signalwire_space_url: input.signalwire_space_url ?? input.signalwireSpaceUrl,
|
|
1761
|
+
project_id: input.project_id ?? input.projectId,
|
|
1762
|
+
application_id: input.application_id ?? input.applicationId,
|
|
1763
|
+
trunk_id: input.trunk_id ?? input.trunkId,
|
|
1764
|
+
endpoint_id: input.endpoint_id ?? input.endpointId,
|
|
1765
|
+
token: input.token,
|
|
1766
|
+
secret: input.secret,
|
|
1767
|
+
custom_sip: customSipPayload(input.custom_sip ?? input.customSip),
|
|
1228
1768
|
});
|
|
1229
1769
|
}
|
|
1230
1770
|
|
|
1231
1771
|
function phoneNumberSearchPayload(input: LabsPhoneNumberSearchOptions): Record<string, unknown> {
|
|
1232
1772
|
return compact({
|
|
1233
1773
|
agency_id: input.agency_id ?? input.agencyId,
|
|
1774
|
+
number_pool: input.number_pool ?? input.numberPool,
|
|
1775
|
+
number_strategy: input.number_strategy ?? input.numberStrategy,
|
|
1234
1776
|
country_code: input.country_code ?? input.countryCode,
|
|
1235
1777
|
area_code: input.area_code ?? input.areaCode,
|
|
1236
1778
|
postal_code: input.postal_code ?? input.postalCode,
|
|
@@ -1252,6 +1794,9 @@ function phoneNumberProvisionPayload(input: LabsPhoneNumberProvisionRequest): Re
|
|
|
1252
1794
|
agent_id: input.agent_id ?? input.agentId,
|
|
1253
1795
|
agent_name: input.agent_name ?? input.agentName,
|
|
1254
1796
|
preset_key: input.preset_key ?? input.presetKey,
|
|
1797
|
+
number_strategy: input.number_strategy ?? input.numberStrategy,
|
|
1798
|
+
number_pool: input.number_pool ?? input.numberPool,
|
|
1799
|
+
premium: input.premium,
|
|
1255
1800
|
style: input.agent_style ?? input.agentStyle ?? input.style,
|
|
1256
1801
|
direction: input.direction,
|
|
1257
1802
|
telephony: input.telephony ? telephonyPayload(input.telephony) : undefined,
|
|
@@ -1267,6 +1812,9 @@ function phoneNumberAssignPayload(input: LabsPhoneNumberAssignRequest): Record<s
|
|
|
1267
1812
|
agent_name: input.agent_name ?? input.agentName,
|
|
1268
1813
|
friendly_name: input.friendly_name ?? input.friendlyName,
|
|
1269
1814
|
preset_key: input.preset_key ?? input.presetKey,
|
|
1815
|
+
number_strategy: input.number_strategy ?? input.numberStrategy,
|
|
1816
|
+
number_pool: input.number_pool ?? input.numberPool,
|
|
1817
|
+
premium: input.premium,
|
|
1270
1818
|
style: input.agent_style ?? input.agentStyle ?? input.style,
|
|
1271
1819
|
direction: input.direction,
|
|
1272
1820
|
telephony: input.telephony ? telephonyPayload(input.telephony) : undefined,
|
|
@@ -1274,6 +1822,103 @@ function phoneNumberAssignPayload(input: LabsPhoneNumberAssignRequest): Record<s
|
|
|
1274
1822
|
});
|
|
1275
1823
|
}
|
|
1276
1824
|
|
|
1825
|
+
function phoneNumberReleasePayload(input: LabsPhoneNumberReleaseRequest): Record<string, unknown> {
|
|
1826
|
+
return compact({
|
|
1827
|
+
agency_id: input.agency_id ?? input.agencyId,
|
|
1828
|
+
reason: input.reason,
|
|
1829
|
+
return_to_pool: input.return_to_pool ?? input.returnToPool,
|
|
1830
|
+
metadata: input.metadata,
|
|
1831
|
+
});
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
function callStagesPayload(input: CreateLabsAgentRequest): Record<string, unknown>[] | undefined {
|
|
1835
|
+
const explicit = input.call_stages ?? input.callStages ?? input.stages;
|
|
1836
|
+
const auto = input.auto_call_stages ?? input.autoCallStages;
|
|
1837
|
+
if (Array.isArray(explicit)) return explicit.map(callStagePayload);
|
|
1838
|
+
if (explicit === false || auto === false) return undefined;
|
|
1839
|
+
return generateCallStages(input).map(callStagePayload);
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
function callStagePayload(input: LabsCallStage): Record<string, unknown> {
|
|
1843
|
+
return compact({
|
|
1844
|
+
key: input.key ?? input.id,
|
|
1845
|
+
name: input.name,
|
|
1846
|
+
goal: input.goal,
|
|
1847
|
+
instructions: input.instructions,
|
|
1848
|
+
exit_criteria: input.exit_criteria ?? input.exitCriteria,
|
|
1849
|
+
tools: input.tools,
|
|
1850
|
+
metadata: input.metadata,
|
|
1851
|
+
});
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
export function generateCallStages(input: CreateLabsAgentRequest): LabsCallStage[] {
|
|
1855
|
+
const direction = String(input.direction ?? input.agent_style ?? input.agentStyle ?? input.style ?? "inbound").toLowerCase();
|
|
1856
|
+
const haystack = [
|
|
1857
|
+
input.name,
|
|
1858
|
+
input.assistant_name ?? input.assistantName,
|
|
1859
|
+
input.business_name ?? input.businessName,
|
|
1860
|
+
input.industry,
|
|
1861
|
+
input.goal,
|
|
1862
|
+
input.system_prompt ?? input.systemPrompt,
|
|
1863
|
+
input.preset_key ?? input.presetKey,
|
|
1864
|
+
].filter(Boolean).join(" ").toLowerCase();
|
|
1865
|
+
const meta = { auto_generated: true, source: "supafone-labs-sdk" };
|
|
1866
|
+
|
|
1867
|
+
if (direction === "outbound" || haystack.includes("sales") || haystack.includes("lead")) {
|
|
1868
|
+
return [
|
|
1869
|
+
stage("intro_consent", "Intro and consent", "State who you are, why you are calling, and offer an immediate opt-out.", ["Caller understands purpose", "Opt-out is honored"], meta),
|
|
1870
|
+
stage("qualification", "Qualification", "Confirm fit, urgency, decision process, and the best next step.", ["Need and timeline are clear"], meta),
|
|
1871
|
+
stage("offer", "Offer", "Explain the next step in plain language without unsupported claims.", ["Caller understands the next step"], meta),
|
|
1872
|
+
stage("booking", "Booking", "Book or route the caller only after confirming required details.", ["Next step is confirmed by a tool or human handoff"], meta),
|
|
1873
|
+
stage("close", "Close", "Summarize what will happen next and end politely.", ["Caller knows the follow-up path"], meta),
|
|
1874
|
+
];
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
if (haystack.includes("legal") || haystack.includes("law") || haystack.includes("injury") || haystack.includes("intake")) {
|
|
1878
|
+
return [
|
|
1879
|
+
stage("greeting", "Greeting", "Open warmly and acknowledge the caller before logistics.", ["Caller need is understood"], meta),
|
|
1880
|
+
stage("incident", "Incident details", "Collect what happened, when it happened, injuries, insurance, and contact details.", ["Core facts are collected"], meta),
|
|
1881
|
+
stage("screening", "Screening", "Identify urgency, jurisdiction, conflicts, and whether human escalation is required.", ["Escalation decision is clear"], meta),
|
|
1882
|
+
stage("booking", "Consult booking", "Book the right next step without quoting fees or inventing availability.", ["Booking or handoff is tool-confirmed"], meta),
|
|
1883
|
+
stage("close", "Close", "Summarize the next step and set expectations accurately.", ["Caller knows exactly what happens next"], meta),
|
|
1884
|
+
];
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
if (haystack.includes("medical") || haystack.includes("clinic") || haystack.includes("patient") || haystack.includes("health")) {
|
|
1888
|
+
return [
|
|
1889
|
+
stage("greeting", "Greeting", "Identify the caller need and keep the tone calm and concise.", ["Caller need is understood"], meta),
|
|
1890
|
+
stage("patient_context", "Patient context", "Collect non-sensitive scheduling context and avoid medical advice.", ["Required scheduling context is collected"], meta),
|
|
1891
|
+
stage("routing", "Routing", "Route urgent, billing, clinical, and scheduling requests correctly.", ["Correct route is selected"], meta),
|
|
1892
|
+
stage("appointment", "Appointment", "Book or request the appointment only after confirming details.", ["Appointment path is confirmed"], meta),
|
|
1893
|
+
stage("close", "Close", "Recap next steps and any confirmed timing.", ["Caller knows the next step"], meta),
|
|
1894
|
+
];
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
return [
|
|
1898
|
+
stage("greeting", "Greeting", "Open naturally, identify the caller need, and set a helpful tone.", ["Caller need is understood"], meta),
|
|
1899
|
+
stage("discovery", "Discovery", "Ask one question at a time until the key details are clear.", ["Required details are collected"], meta),
|
|
1900
|
+
stage("resolution", "Resolution", "Answer approved questions or route to the right workflow.", ["Resolution path is selected"], meta),
|
|
1901
|
+
stage("action", "Action", "Use tools for booking, routing, messaging, or handoff before claiming success.", ["Action is confirmed by a tool or handoff"], meta),
|
|
1902
|
+
stage("close", "Close", "Summarize the outcome and next step accurately.", ["Caller knows what happens next"], meta),
|
|
1903
|
+
];
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
function stage(
|
|
1907
|
+
key: string,
|
|
1908
|
+
name: string,
|
|
1909
|
+
instructions: string,
|
|
1910
|
+
exitCriteria: string[],
|
|
1911
|
+
metadata: Record<string, unknown>,
|
|
1912
|
+
): LabsCallStage {
|
|
1913
|
+
return {
|
|
1914
|
+
key,
|
|
1915
|
+
name,
|
|
1916
|
+
instructions,
|
|
1917
|
+
exitCriteria,
|
|
1918
|
+
metadata,
|
|
1919
|
+
};
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1277
1922
|
function voicePayload(input: LabsVoiceSelection): Record<string, unknown> {
|
|
1278
1923
|
return compact({
|
|
1279
1924
|
provider: input.provider,
|
|
@@ -1286,6 +1931,30 @@ function providerKeysPayload(input: LabsProviderKeys): Record<string, unknown> {
|
|
|
1286
1931
|
return compact({
|
|
1287
1932
|
ultravox: input.ultravox,
|
|
1288
1933
|
ultravox_api_key: input.ultravox_api_key ?? input.ultravoxApiKey,
|
|
1934
|
+
retell: input.retell,
|
|
1935
|
+
retell_api_key: input.retell_api_key ?? input.retellApiKey,
|
|
1936
|
+
vapi: input.vapi,
|
|
1937
|
+
vapi_api_key: input.vapi_api_key ?? input.vapiApiKey,
|
|
1938
|
+
bland: input.bland,
|
|
1939
|
+
bland_api_key: input.bland_api_key ?? input.blandApiKey,
|
|
1940
|
+
livekit: input.livekit,
|
|
1941
|
+
livekit_api_key: input.livekit_api_key ?? input.livekitApiKey,
|
|
1942
|
+
livekit_api_secret: input.livekit_api_secret ?? input.livekitApiSecret,
|
|
1943
|
+
pipecat: input.pipecat,
|
|
1944
|
+
pipecat_api_key: input.pipecat_api_key ?? input.pipecatApiKey,
|
|
1945
|
+
twilio: input.twilio,
|
|
1946
|
+
twilio_account_sid: input.twilio_account_sid ?? input.twilioAccountSid,
|
|
1947
|
+
twilio_auth_token: input.twilio_auth_token ?? input.twilioAuthToken,
|
|
1948
|
+
twilio_api_key_sid: input.twilio_api_key_sid ?? input.twilioApiKeySid,
|
|
1949
|
+
twilio_api_key_secret: input.twilio_api_key_secret ?? input.twilioApiKeySecret,
|
|
1950
|
+
telnyx: input.telnyx,
|
|
1951
|
+
telnyx_api_key: input.telnyx_api_key ?? input.telnyxApiKey,
|
|
1952
|
+
plivo: input.plivo,
|
|
1953
|
+
plivo_auth_id: input.plivo_auth_id ?? input.plivoAuthId,
|
|
1954
|
+
plivo_auth_token: input.plivo_auth_token ?? input.plivoAuthToken,
|
|
1955
|
+
signalwire: input.signalwire,
|
|
1956
|
+
signalwire_api_token: input.signalwire_api_token ?? input.signalwireApiToken,
|
|
1957
|
+
signalwire_project_id: input.signalwire_project_id ?? input.signalwireProjectId,
|
|
1289
1958
|
elevenlabs: input.elevenlabs,
|
|
1290
1959
|
elevenlabs_api_key: input.elevenlabs_api_key ?? input.elevenlabsApiKey,
|
|
1291
1960
|
cartesia: input.cartesia,
|
|
@@ -1294,6 +1963,59 @@ function providerKeysPayload(input: LabsProviderKeys): Record<string, unknown> {
|
|
|
1294
1963
|
inworld_api_key: input.inworld_api_key ?? input.inworldApiKey,
|
|
1295
1964
|
deepgram: input.deepgram,
|
|
1296
1965
|
deepgram_api_key: input.deepgram_api_key ?? input.deepgramApiKey,
|
|
1966
|
+
anthropic: input.anthropic,
|
|
1967
|
+
anthropic_api_key: input.anthropic_api_key ?? input.anthropicApiKey,
|
|
1968
|
+
openai: input.openai,
|
|
1969
|
+
openai_api_key: input.openai_api_key ?? input.openaiApiKey,
|
|
1970
|
+
xai: input.xai,
|
|
1971
|
+
xai_api_key: input.xai_api_key ?? input.xaiApiKey,
|
|
1972
|
+
});
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
function byokPayload(input: LabsProviderKeys | LabsByokConfig): Record<string, unknown> {
|
|
1976
|
+
const structured = input as LabsByokConfig;
|
|
1977
|
+
if (
|
|
1978
|
+
structured.agentProvider ||
|
|
1979
|
+
structured.agent_provider ||
|
|
1980
|
+
structured.runtime ||
|
|
1981
|
+
structured.telephony ||
|
|
1982
|
+
structured.tts ||
|
|
1983
|
+
structured.stt ||
|
|
1984
|
+
structured.llm ||
|
|
1985
|
+
structured.providerKeys ||
|
|
1986
|
+
structured.provider_keys ||
|
|
1987
|
+
structured.customSip ||
|
|
1988
|
+
structured.custom_sip ||
|
|
1989
|
+
structured.sip
|
|
1990
|
+
) {
|
|
1991
|
+
return compact({
|
|
1992
|
+
provider_keys: providerKeysPayload(structured.provider_keys ?? structured.providerKeys ?? {}),
|
|
1993
|
+
agent_provider: providerConfigPayload(structured.agent_provider ?? structured.agentProvider ?? structured.runtime),
|
|
1994
|
+
telephony: structured.telephony ? telephonyPayload(structured.telephony) : undefined,
|
|
1995
|
+
tts: providerConfigPayload(structured.tts),
|
|
1996
|
+
stt: providerConfigPayload(structured.stt),
|
|
1997
|
+
llm: providerConfigPayload(structured.llm),
|
|
1998
|
+
custom_sip: customSipPayload(structured.custom_sip ?? structured.customSip ?? structured.sip),
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
2001
|
+
return providerKeysPayload(input as LabsProviderKeys);
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
function providerConfigPayload(input?: LabsProviderByokConfig): Record<string, unknown> | undefined {
|
|
2005
|
+
if (!input) return undefined;
|
|
2006
|
+
const out: Record<string, unknown> = { ...input };
|
|
2007
|
+
delete out.apiKey;
|
|
2008
|
+
delete out.api_key;
|
|
2009
|
+
delete out.voiceId;
|
|
2010
|
+
delete out.voice_id;
|
|
2011
|
+
return compact({
|
|
2012
|
+
...out,
|
|
2013
|
+
provider: input.provider,
|
|
2014
|
+
api_key: input.api_key ?? input.apiKey,
|
|
2015
|
+
credentials: input.credentials,
|
|
2016
|
+
settings: input.settings,
|
|
2017
|
+
model: input.model,
|
|
2018
|
+
voice_id: input.voice_id ?? input.voiceId,
|
|
1297
2019
|
});
|
|
1298
2020
|
}
|
|
1299
2021
|
|
|
@@ -1312,11 +2034,57 @@ function toolsPayload(input: LabsToolsConfig): Record<string, unknown> {
|
|
|
1312
2034
|
});
|
|
1313
2035
|
}
|
|
1314
2036
|
|
|
2037
|
+
function recordingPayload(input: LabsRecordingConfig): Record<string, unknown> {
|
|
2038
|
+
return compact({
|
|
2039
|
+
enabled: input.enabled,
|
|
2040
|
+
record_audio: input.record_audio ?? input.recordAudio,
|
|
2041
|
+
consent_required: input.consent_required ?? input.consentRequired,
|
|
2042
|
+
announcement: input.announcement,
|
|
2043
|
+
retention_days: input.retention_days ?? input.retentionDays,
|
|
2044
|
+
storage: input.storage,
|
|
2045
|
+
redact_pii: input.redact_pii ?? input.redactPii,
|
|
2046
|
+
metadata: input.metadata,
|
|
2047
|
+
});
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
function transcriptionPayload(input: LabsTranscriptionConfig): Record<string, unknown> {
|
|
2051
|
+
return compact({
|
|
2052
|
+
enabled: input.enabled,
|
|
2053
|
+
provider: input.provider,
|
|
2054
|
+
model: input.model,
|
|
2055
|
+
language: input.language,
|
|
2056
|
+
redact_pii: input.redact_pii ?? input.redactPii,
|
|
2057
|
+
diarization: input.diarization,
|
|
2058
|
+
timestamps: input.timestamps,
|
|
2059
|
+
metadata: input.metadata,
|
|
2060
|
+
});
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
function artifactsPayload(input: LabsArtifactsConfig): Record<string, unknown> {
|
|
2064
|
+
return compact({
|
|
2065
|
+
recordings: input.recordings,
|
|
2066
|
+
transcripts: input.transcripts,
|
|
2067
|
+
summaries: input.summaries,
|
|
2068
|
+
qa_reports: input.qa_reports ?? input.qaReports,
|
|
2069
|
+
logs: input.logs,
|
|
2070
|
+
webhooks: input.webhooks,
|
|
2071
|
+
retention_days: input.retention_days ?? input.retentionDays,
|
|
2072
|
+
metadata: input.metadata,
|
|
2073
|
+
});
|
|
2074
|
+
}
|
|
2075
|
+
|
|
1315
2076
|
function labsPayload(input: LabsWatcherConfig): Record<string, unknown> {
|
|
1316
2077
|
return compact({
|
|
1317
2078
|
enabled: input.enabled,
|
|
1318
2079
|
voice_watcher: input.voice_watcher ?? input.voiceWatcher,
|
|
2080
|
+
api_key: input.api_key ?? input.apiKey,
|
|
1319
2081
|
model: input.model,
|
|
2082
|
+
mode: input.mode,
|
|
2083
|
+
managed_infrastructure: input.managed_infrastructure ?? input.managedInfrastructure,
|
|
2084
|
+
stt: input.stt,
|
|
2085
|
+
llm: input.llm,
|
|
2086
|
+
tts: input.tts,
|
|
2087
|
+
provider_keys: input.provider_keys ?? input.providerKeys,
|
|
1320
2088
|
label: input.label,
|
|
1321
2089
|
});
|
|
1322
2090
|
}
|
|
@@ -1346,6 +2114,24 @@ function ultravoxPayload(input: LabsUltravoxRuntime): Record<string, unknown> {
|
|
|
1346
2114
|
voiceOverrides: input.voiceOverrides ?? input.voice_overrides,
|
|
1347
2115
|
retentionPolicy: input.retentionPolicy ?? input.retention_policy,
|
|
1348
2116
|
callTemplate: input.callTemplate ?? input.call_template,
|
|
2117
|
+
custom_sip: customSipPayload(input.custom_sip ?? input.customSip ?? input.sip),
|
|
2118
|
+
});
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
function customSipPayload(input?: LabsCustomSipConfig): Record<string, unknown> | undefined {
|
|
2122
|
+
if (!input) return undefined;
|
|
2123
|
+
return compact({
|
|
2124
|
+
sip_trunk_uri: input.sip_trunk_uri ?? input.sipTrunkUri,
|
|
2125
|
+
trunk_uri: input.trunk_uri ?? input.trunkUri,
|
|
2126
|
+
sip_host: input.sip_host ?? input.sipHost,
|
|
2127
|
+
from_number: input.from_number ?? input.fromNumber,
|
|
2128
|
+
username: input.username,
|
|
2129
|
+
password: input.password,
|
|
2130
|
+
transport: input.transport,
|
|
2131
|
+
headers: input.headers,
|
|
2132
|
+
codecs: input.codecs,
|
|
2133
|
+
dtmf_mode: input.dtmf_mode ?? input.dtmfMode,
|
|
2134
|
+
metadata: input.metadata,
|
|
1349
2135
|
});
|
|
1350
2136
|
}
|
|
1351
2137
|
|
|
@@ -1357,6 +2143,18 @@ function compact(input: Record<string, unknown>): Record<string, unknown> {
|
|
|
1357
2143
|
return out;
|
|
1358
2144
|
}
|
|
1359
2145
|
|
|
2146
|
+
function parseSseLog(raw: string): LabsLogEntry | null {
|
|
2147
|
+
const data: string[] = [];
|
|
2148
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
2149
|
+
if (!line || line.startsWith(":")) continue;
|
|
2150
|
+
if (line.startsWith("data:")) data.push(line.slice(5).trimStart());
|
|
2151
|
+
}
|
|
2152
|
+
if (!data.length) return null;
|
|
2153
|
+
const parsed = safeJson(data.join("\n"));
|
|
2154
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
2155
|
+
return parsed as LabsLogEntry;
|
|
2156
|
+
}
|
|
2157
|
+
|
|
1360
2158
|
function safeJson(text: string): unknown {
|
|
1361
2159
|
try {
|
|
1362
2160
|
return JSON.parse(text);
|