supafone-labs 0.4.12 → 0.4.14

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 CHANGED
@@ -107,6 +107,31 @@ Supafone Labs has two main features:
107
107
  - **Self-healing watcher**: enable `labs.enabled` to attach the Supafone Labs
108
108
  second mind to a hosted or BYOK agent.
109
109
 
110
+ The daily developer workflow is documented in
111
+ [Developer Workflows](../gitbook/developer-workflows.md): one normalized live
112
+ voice catalog, fixed BCP-47 language selection, automatic voice compatibility
113
+ filtering, structured SecondMind directives, and the same configuration model
114
+ across TypeScript and Python. Fixed language selection does not enable
115
+ mid-call language or voice switching.
116
+
117
+ Agent Factory can opt into managed live language and matching-voice routing
118
+ with one field. It remains absent and disabled for existing agents:
119
+
120
+ ```ts
121
+ const agent = await supafone.labs.agents.createInbound({
122
+ agentKey: "bilingual-intake",
123
+ name: "Bilingual intake",
124
+ languageVoiceRouting: true,
125
+ routingLanguages: ["en-US", "es-MX"], // optional; defaults to English + Spanish
126
+ });
127
+ ```
128
+
129
+ The package sends only these preferences. Supafone's private hosted runtime
130
+ selects compatible live-catalog voices and performs the in-call transition.
131
+ The first configured language owns the opening, and a non-English primary
132
+ greeting is translated during provisioning. See
133
+ [Live Language and Voice Routing](../gitbook/live-language-voice-routing.md).
134
+
110
135
  BYOK is advanced and split into three independent lanes:
111
136
 
112
137
  | Lane | Examples |
@@ -279,6 +304,29 @@ required); and prints the returned widget snippet.
279
304
 
280
305
  ## Hosted voices
281
306
 
307
+ Select a current provider voice from plain-language intent:
308
+
309
+ ```ts
310
+ const matches = await supafone.labs.voices.recommend({
311
+ description: "calm Spanish customer-support voice",
312
+ language: "es-MX",
313
+ configuredOnly: true,
314
+ });
315
+
316
+ const voice = matches.matches[0].voice;
317
+ await supafone.labs.agents.createInbound({
318
+ name: "Spanish support",
319
+ voice: supafone.labs.voices.selection(voice),
320
+ });
321
+ ```
322
+
323
+ The hosted catalog refreshes Ultravox, Cartesia, ElevenLabs, and Inworld and
324
+ normalizes names, languages, gender, accent, voice type, model limits, and the
325
+ Ultravox-compatible language intersection. Full reference:
326
+ [Dynamic Voice Catalog and Selection](../gitbook/voice-catalog-and-selection.md).
327
+
328
+ Labs Cloud also exposes direct hosted TTS and STT:
329
+
282
330
  ```ts
283
331
  const wav = await supafone.tts("You're all set — talk soon!", "supafone-labs-calm-en");
284
332
  // wav: Uint8Array
@@ -87,6 +87,56 @@ export interface WhisperOptions {
87
87
  maxTokens?: number;
88
88
  temperature?: number;
89
89
  }
90
+ export type SecondMindDirectiveKind = "empathy" | "tactical" | "guardrail" | "mixed";
91
+ export interface DirectiveTextControl {
92
+ enabled?: boolean;
93
+ instructions?: string;
94
+ maxChars?: number;
95
+ max_chars?: number;
96
+ }
97
+ export interface DirectiveListControl {
98
+ enabled?: boolean;
99
+ instructions?: string;
100
+ maxItems?: number;
101
+ max_items?: number;
102
+ itemMaxChars?: number;
103
+ item_max_chars?: number;
104
+ }
105
+ /** Serializable controls for each field generated by SecondMind. */
106
+ export interface DirectiveContract {
107
+ empathyDirective?: DirectiveTextControl;
108
+ empathy_directive?: DirectiveTextControl;
109
+ tacticalDirective?: DirectiveTextControl;
110
+ tactical_directive?: DirectiveTextControl;
111
+ surfaceFacts?: DirectiveListControl;
112
+ surface_facts?: DirectiveListControl;
113
+ guardrails?: DirectiveListControl;
114
+ languageMode?: "caller" | "model" | "fixed";
115
+ language_mode?: "caller" | "model" | "fixed";
116
+ fixedLanguage?: string;
117
+ fixed_language?: string;
118
+ allowedKinds?: SecondMindDirectiveKind[];
119
+ allowed_kinds?: SecondMindDirectiveKind[];
120
+ confidenceThreshold?: number;
121
+ confidence_threshold?: number;
122
+ operatorGuardrails?: string[];
123
+ operator_guardrails?: string[];
124
+ }
125
+ export interface SecondMindDirective {
126
+ empathy_directive: string;
127
+ tactical_directive: string;
128
+ surface_facts: string[];
129
+ guardrails: string[];
130
+ language: string;
131
+ confidence: number;
132
+ kind: SecondMindDirectiveKind;
133
+ }
134
+ export interface StructuredWhisperOptions extends WhisperOptions {
135
+ directiveContract?: DirectiveContract;
136
+ directive_contract?: DirectiveContract;
137
+ /** Local final say: revise or suppress the generated directive before use. */
138
+ transform?: (directive: SecondMindDirective) => SecondMindDirective | null | Promise<SecondMindDirective | null>;
139
+ }
90
140
  export interface Balance {
91
141
  plan: string;
92
142
  seconds_remaining: number;
@@ -160,6 +210,120 @@ export interface LabsVoiceSelection {
160
210
  voice_id?: string;
161
211
  model?: string;
162
212
  }
213
+ /** Public Agent Factory preference for one routed language. */
214
+ export interface LabsLanguageVoiceProfile {
215
+ language: string;
216
+ languageHint?: string;
217
+ language_hint?: string;
218
+ voice?: LabsVoiceSelection;
219
+ }
220
+ export type LabsVoiceGender = "female" | "male" | "neutral";
221
+ export interface LabsVoiceLanguage {
222
+ code: string;
223
+ locale: string;
224
+ name: string;
225
+ native_name: string;
226
+ aliases?: string[];
227
+ routing_supported?: boolean;
228
+ }
229
+ export interface LabsVoiceLanguageSupport {
230
+ provider: string;
231
+ model?: string | null;
232
+ known: boolean;
233
+ language_codes: string[];
234
+ /** Number of language codes Supafone can enumerate from provider docs. */
235
+ enumerated_language_count: number;
236
+ generally_available_language_codes: string[];
237
+ experimental_language_codes: string[];
238
+ documented_language_count: number;
239
+ documented_language_count_is_minimum: boolean;
240
+ support_tier: string;
241
+ cross_lingual: boolean | null;
242
+ documentation_url?: string | null;
243
+ verified_at: string;
244
+ native_language_codes: string[];
245
+ ultravox_routing_language_codes: string[];
246
+ primary_language_support_tier: "generally_available" | "experimental" | "unknown";
247
+ }
248
+ export interface LabsVoiceProviderTraits {
249
+ countries: string[];
250
+ accents: string[];
251
+ age_groups: string[];
252
+ categories: string[];
253
+ use_cases: string[];
254
+ descriptors: string[];
255
+ native_locales: string[];
256
+ created_at?: string | number | null;
257
+ is_public?: boolean | null;
258
+ is_owner?: boolean | null;
259
+ }
260
+ export interface LabsVoiceCatalogItem {
261
+ /** Stable runtime reference, including provider prefix when required. */
262
+ id: string;
263
+ voice_id: string;
264
+ /** Human-readable provider display name. */
265
+ provider: string;
266
+ /** Canonical SDK/runtime provider key. */
267
+ provider_key: string;
268
+ /** Runtime adapter used to place the voice on an Ultravox call. */
269
+ runtime_provider_key: string;
270
+ /** Actual TTS engine behind the voice (can differ for Ultravox built-ins). */
271
+ synthesis_provider_key: string;
272
+ /** Raw identifier used by the provider API. */
273
+ provider_voice_id: string;
274
+ name: string;
275
+ label: string;
276
+ description: string;
277
+ style: string;
278
+ model?: string | null;
279
+ language: string;
280
+ language_code: string;
281
+ language_locale: string;
282
+ language_name: string;
283
+ native_language_name: string;
284
+ languages: LabsVoiceLanguage[];
285
+ native_language_codes: string[];
286
+ model_language_codes: string[];
287
+ runtime_supported_language_codes: string[];
288
+ routing_supported: boolean;
289
+ language_support: LabsVoiceLanguageSupport;
290
+ gender: LabsVoiceGender;
291
+ accent: string;
292
+ age: string;
293
+ provider_traits: LabsVoiceProviderTraits;
294
+ voice_types: string[];
295
+ primary_voice_type: string;
296
+ tags: string[];
297
+ /** Sanitized provider-native fields retained for forward-compatible filtering. */
298
+ provider_metadata: Record<string, unknown>;
299
+ provider_metadata_fields: string[];
300
+ preview_url?: string | null;
301
+ preview_available: boolean;
302
+ source: string;
303
+ ownership?: string | null;
304
+ configured: boolean;
305
+ recommended: boolean;
306
+ premium?: boolean;
307
+ is_custom: boolean;
308
+ runtime: {
309
+ provider: string;
310
+ voice_id: string;
311
+ model?: string;
312
+ };
313
+ [extra: string]: unknown;
314
+ }
315
+ export interface LabsVoicePreference {
316
+ description: string;
317
+ language?: string;
318
+ provider?: string;
319
+ gender?: LabsVoiceGender;
320
+ voiceType?: string;
321
+ voice_type?: string;
322
+ model?: string;
323
+ configuredOnly?: boolean;
324
+ configured_only?: boolean;
325
+ premium?: boolean;
326
+ }
163
327
  export interface LabsProviderKeys {
164
328
  /** Agent runtime/platform providers. */
165
329
  ultravox?: string;
@@ -507,8 +671,23 @@ export interface CreateLabsAgentRequest {
507
671
  greeting?: string;
508
672
  systemPrompt?: string;
509
673
  system_prompt?: string;
674
+ /** Fixed language for the full call. Does not enable mid-call switching. */
510
675
  language?: string;
676
+ preferredLanguage?: string;
677
+ preferred_language?: string;
678
+ /** Opt in to managed live language and matching-voice routing. Defaults to false. */
679
+ languageVoiceRouting?: boolean;
680
+ language_voice_routing?: boolean;
681
+ /** Optional ordered language list. The first language controls the greeting. */
682
+ routingLanguages?: string[];
683
+ routing_languages?: string[];
684
+ /** Optional per-language voice preferences. Supports two to four profiles. */
685
+ languageProfiles?: LabsLanguageVoiceProfile[];
686
+ language_profiles?: LabsLanguageVoiceProfile[];
511
687
  voice?: LabsVoiceSelection;
688
+ /** Resolve a real current catalog voice from this plain-language preference. */
689
+ voicePreference?: LabsVoicePreference;
690
+ voice_preference?: LabsVoicePreference;
512
691
  providerKeys?: LabsProviderKeys;
513
692
  provider_keys?: LabsProviderKeys;
514
693
  byok?: LabsProviderKeys | LabsByokConfig;
@@ -569,16 +748,98 @@ export interface LabsToolListResponse {
569
748
  export interface LabsVoiceListOptions {
570
749
  provider?: string;
571
750
  search?: string;
751
+ /** Native/accent language advertised for the individual voice. */
572
752
  language?: string;
753
+ /** Language that the provider model and Ultravox can both run live. */
754
+ compatibleLanguage?: string;
755
+ compatible_language?: string;
756
+ gender?: LabsVoiceGender;
757
+ voiceType?: string;
758
+ voice_type?: string;
759
+ model?: string;
760
+ runtimeProvider?: string;
761
+ runtime_provider?: string;
762
+ configuredOnly?: boolean;
763
+ configured_only?: boolean;
573
764
  cursor?: number;
574
765
  limit?: number;
766
+ agencyId?: string;
767
+ agency_id?: string;
575
768
  }
576
769
  export interface LabsVoiceListResponse {
577
- voices: Array<Record<string, unknown>>;
770
+ account_id?: string;
771
+ voices: LabsVoiceCatalogItem[];
578
772
  total: number;
579
- providers: Array<Record<string, unknown>>;
773
+ cursor?: number;
774
+ next_cursor?: number | null;
775
+ providers: Array<{
776
+ id: string;
777
+ label: string;
778
+ configured: boolean;
779
+ voice_count: number;
780
+ error?: string | null;
781
+ }>;
580
782
  provider_accounts?: Record<string, unknown>;
581
783
  errors?: Record<string, string>;
784
+ catalog?: {
785
+ dynamic: boolean;
786
+ source: string;
787
+ normalization_schema_version: number;
788
+ cache_ttl_seconds: number;
789
+ capabilities_url?: string;
790
+ };
791
+ }
792
+ export interface LabsVoiceModelCapability {
793
+ provider: string;
794
+ model?: string | null;
795
+ known: boolean;
796
+ language_codes: string[];
797
+ enumerated_language_count: number;
798
+ generally_available_language_codes: string[];
799
+ experimental_language_codes: string[];
800
+ documented_language_count: number;
801
+ documented_language_count_is_minimum: boolean;
802
+ support_tier: string;
803
+ cross_lingual: boolean | null;
804
+ documentation_url?: string | null;
805
+ verified_at: string;
806
+ ultravox_routing_language_codes: string[];
807
+ ultravox_routing_language_count: number;
808
+ }
809
+ export interface LabsVoiceProviderCapability {
810
+ provider: string;
811
+ label: string;
812
+ ultravox_integration: "native" | "named_external" | string;
813
+ default_model?: string | null;
814
+ models: LabsVoiceModelCapability[];
815
+ }
816
+ export interface LabsVoiceCapabilitiesResponse {
817
+ runtime: "ultravox" | string;
818
+ runtime_spoken_languages: LabsVoiceLanguage[];
819
+ runtime_spoken_language_count: number;
820
+ providers: LabsVoiceProviderCapability[];
821
+ selection_rule: Record<string, string>;
822
+ normalization_schema_version: number;
823
+ }
824
+ export interface LabsVoiceRecommendOptions extends LabsVoicePreference {
825
+ limit?: number;
826
+ agencyId?: string;
827
+ agency_id?: string;
828
+ }
829
+ export interface LabsVoiceRecommendation {
830
+ voice: LabsVoiceCatalogItem;
831
+ score: number;
832
+ reasons: string[];
833
+ }
834
+ export interface LabsVoiceRecommendResponse {
835
+ account_id?: string;
836
+ description: string;
837
+ matches: LabsVoiceRecommendation[];
838
+ total_considered: number;
839
+ }
840
+ export interface LabsVoicePreview {
841
+ content: ArrayBuffer;
842
+ mediaType: string;
582
843
  }
583
844
  export interface LabsRuntimeResponse {
584
845
  account_id: string;
@@ -590,9 +851,11 @@ export interface LabsRuntimeResponse {
590
851
  }
591
852
  export interface LabsCallListOptions {
592
853
  agencyId?: string;
854
+ agency_id?: string;
593
855
  agentKey?: string;
594
856
  agent_key?: string;
595
857
  limit?: number;
858
+ offset?: number;
596
859
  }
597
860
  export interface LabsCallArtifact {
598
861
  id?: string;
@@ -602,7 +865,11 @@ export interface LabsCallArtifact {
602
865
  started_at?: string;
603
866
  duration_seconds?: number;
604
867
  recording_url?: string;
868
+ recording_download_url?: string;
869
+ recording_archived?: boolean;
605
870
  transcript_url?: string;
871
+ watcher_events?: LabsDeveloperActivityEvent[];
872
+ watcher_event_count?: number;
606
873
  [extra: string]: unknown;
607
874
  }
608
875
  export interface LabsCallListResponse {
@@ -625,6 +892,37 @@ export interface LabsTranscriptListResponse {
625
892
  transcripts: Array<Record<string, unknown>>;
626
893
  [extra: string]: unknown;
627
894
  }
895
+ export interface LabsDeveloperActivityEvent {
896
+ id: string;
897
+ account_id: string;
898
+ event_type: string;
899
+ resource_type: string;
900
+ resource_id: string;
901
+ source?: string;
902
+ detail?: Record<string, unknown>;
903
+ created_at: string;
904
+ [extra: string]: unknown;
905
+ }
906
+ export interface LabsActivityListOptions {
907
+ accountId?: string;
908
+ account_id?: string;
909
+ agencyId?: string;
910
+ agency_id?: string;
911
+ eventType?: string;
912
+ event_type?: string;
913
+ resourceType?: string;
914
+ resource_type?: string;
915
+ resourceId?: string;
916
+ resource_id?: string;
917
+ limit?: number;
918
+ offset?: number;
919
+ }
920
+ export interface LabsActivityListResponse {
921
+ events: LabsDeveloperActivityEvent[];
922
+ count: number;
923
+ next_offset?: number | null;
924
+ account_id?: string;
925
+ }
628
926
  export interface LabsPhoneNumberSearchOptions {
629
927
  agencyId?: string;
630
928
  agency_id?: string;
@@ -784,6 +1082,16 @@ export interface CreateLabsAgentResponse {
784
1082
  [extra: string]: unknown;
785
1083
  };
786
1084
  call_plan?: LabsCallPlan;
1085
+ language_voice_routing?: {
1086
+ enabled: boolean;
1087
+ voice_routing_enabled: boolean;
1088
+ profiles: Array<Record<string, unknown>>;
1089
+ greeting_translation?: {
1090
+ language: string;
1091
+ language_hint: string;
1092
+ status: "not_needed" | "translated";
1093
+ };
1094
+ };
787
1095
  [extra: string]: unknown;
788
1096
  }
789
1097
  export interface ListLabsAgentsResponse {
@@ -1086,6 +1394,8 @@ export declare class SupafoneLabs {
1086
1394
  request<T>(method: string, path: string, body?: unknown, useSession?: boolean): Promise<T>;
1087
1395
  /** @internal Authenticated JSON request to the Supafone app API (`/api/v1/labs/*`). */
1088
1396
  requestSupafoneApi<T>(method: string, path: string, body?: unknown): Promise<T>;
1397
+ /** @internal Authenticated binary request to the Supafone app API. */
1398
+ requestSupafoneBinary(path: string): Promise<LabsVoicePreview>;
1089
1399
  /**
1090
1400
  * Exchange the account email/password for a product-API JWT (the same login
1091
1401
  * as app.supafone.ai). Called lazily by campaigns/calls — call directly only
@@ -1154,6 +1464,14 @@ export declare class SupafoneLabs {
1154
1464
  * (empty string when the agent is doing fine).
1155
1465
  */
1156
1466
  whisper(transcript: string, opts?: WhisperOptions): Promise<string>;
1467
+ /**
1468
+ * Structured SecondMind guidance with developer-controlled field policy.
1469
+ * Returns null when JSON is invalid, evidence misses the confidence gate,
1470
+ * the generated kind is disallowed, or the local transform suppresses it.
1471
+ */
1472
+ whisperStructured(transcript: string, opts?: StructuredWhisperOptions): Promise<SecondMindDirective | null>;
1473
+ /** Alias that reads naturally in applications building their own watcher loop. */
1474
+ directive(transcript: string, opts?: StructuredWhisperOptions): Promise<SecondMindDirective | null>;
1157
1475
  /** Hosted TTS — returns raw audio bytes (WAV/PCM per voice). */
1158
1476
  tts(text: string, voice?: string): Promise<Uint8Array>;
1159
1477
  /** Convenience alias for voice preview UI/buttons. */
@@ -1513,6 +1831,8 @@ declare class LabsNamespace {
1513
1831
  readonly phoneNumbers: LabsPhoneNumbersNamespace;
1514
1832
  readonly telephony: LabsTelephonyNamespace;
1515
1833
  readonly calls: LabsCallsNamespace;
1834
+ readonly activity: LabsActivityNamespace;
1835
+ readonly plans: LabsPlansNamespace;
1516
1836
  readonly recordings: LabsRecordingsNamespace;
1517
1837
  readonly transcripts: LabsTranscriptsNamespace;
1518
1838
  constructor(sm: SupafoneLabs);
@@ -1610,8 +1930,24 @@ declare class LabsToolsNamespace {
1610
1930
  declare class LabsVoicesNamespace {
1611
1931
  private sm;
1612
1932
  constructor(sm: SupafoneLabs);
1613
- /** Supafone-managed Cartesia voices. Other TTS engines remain explicit BYOK choices. */
1933
+ /** Live normalized catalog from every connected/managed TTS provider. */
1614
1934
  list(opts?: LabsVoiceListOptions): Promise<LabsVoiceListResponse>;
1935
+ /** Provider/model language limits and their Ultravox-compatible intersection. */
1936
+ capabilities(): Promise<LabsVoiceCapabilitiesResponse>;
1937
+ /** Page through the complete normalized catalog. */
1938
+ listAll(opts?: Omit<LabsVoiceListOptions, "cursor" | "limit"> & {
1939
+ pageSize?: number;
1940
+ maxPages?: number;
1941
+ }): Promise<LabsVoiceListResponse>;
1942
+ /** Rank real current voices from a plain-language description. */
1943
+ recommend(opts: LabsVoiceRecommendOptions): Promise<LabsVoiceRecommendResponse>;
1944
+ /** Download an authenticated voice preview. */
1945
+ preview(voiceId: string, opts?: {
1946
+ agencyId?: string;
1947
+ agency_id?: string;
1948
+ }): Promise<LabsVoicePreview>;
1949
+ /** Convert a catalog row into the exact Agent Factory voice field. */
1950
+ selection(voice: LabsVoiceCatalogItem): LabsVoiceSelection;
1615
1951
  }
1616
1952
  declare class LabsRuntimeNamespace {
1617
1953
  private sm;
@@ -1638,8 +1974,25 @@ declare class LabsCallsNamespace {
1638
1974
  list(opts?: LabsCallListOptions): Promise<LabsCallListResponse>;
1639
1975
  get(callId: string, opts?: {
1640
1976
  agencyId?: string;
1977
+ agency_id?: string;
1978
+ }): Promise<{
1979
+ call: LabsCallArtifact;
1980
+ }>;
1981
+ delete(callId: string, opts?: {
1982
+ agencyId?: string;
1983
+ agency_id?: string;
1641
1984
  }): Promise<Record<string, unknown>>;
1642
1985
  }
1986
+ declare class LabsActivityNamespace {
1987
+ private sm;
1988
+ constructor(sm: SupafoneLabs);
1989
+ list(opts?: LabsActivityListOptions): Promise<LabsActivityListResponse>;
1990
+ }
1991
+ declare class LabsPlansNamespace {
1992
+ private sm;
1993
+ constructor(sm: SupafoneLabs);
1994
+ list(opts?: Omit<LabsActivityListOptions, "eventType" | "event_type" | "resourceType" | "resource_type">): Promise<LabsActivityListResponse>;
1995
+ }
1643
1996
  declare class LabsRecordingsNamespace {
1644
1997
  private sm;
1645
1998
  constructor(sm: SupafoneLabs);