supafone-labs 0.5.2 → 0.5.3

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/src/index.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * A dependency-free TypeScript client for creating hosted Supafone agents
5
5
  * through the Supafone API, including managed phone numbers, voices, stages,
6
- * tools, recordings, transcripts, widgets, and Supafone Pro watcher. It also
6
+ * tools, recordings, transcripts, widgets, and Supafone Supervisor. It also
7
7
  * includes the Labs cloud sidecar oracle, hosted TTS/STT, live multilingual
8
8
  * transcription, telemetry, agent builder, and objective-driven optimizer.
9
9
  *
@@ -54,15 +54,13 @@ export interface SupafoneLabsOptions {
54
54
  * fall back to the plain zero-billed report.
55
55
  */
56
56
  postCallAnalysis?: boolean;
57
- /**
58
- * Run provisioned agents under Supafone's Voice Watcher framework — live
59
- * supervision, QA, and call scoring (default true). Set false for a raw
60
- * agent with no watcher. `voice_watcher` (snake) and the deprecated `labs`
61
- * are accepted aliases, resolved voiceWatcher > voice_watcher > labs > true.
62
- */
57
+ /** Enable Supafone Supervisor live guidance, QA, and scoring (default true). */
58
+ supervisor?: boolean;
59
+ /** @deprecated Use supervisor. */
63
60
  voiceWatcher?: boolean;
61
+ /** @deprecated Use supervisor. */
64
62
  voice_watcher?: boolean;
65
- /** @deprecated alias for voiceWatcher. */
63
+ /** @deprecated Use supervisor. */
66
64
  labs?: boolean;
67
65
  }
68
66
 
@@ -93,7 +91,10 @@ export interface WhisperOptions {
93
91
  temperature?: number;
94
92
  }
95
93
 
96
- export type SecondMindDirectiveKind = "empathy" | "tactical" | "guardrail" | "mixed";
94
+ export type SupervisorDirectiveKind = "empathy" | "tactical" | "guardrail" | "mixed";
95
+
96
+ /** @deprecated Use SupervisorDirectiveKind. */
97
+ export type SecondMindDirectiveKind = SupervisorDirectiveKind;
97
98
 
98
99
  export interface DirectiveTextControl {
99
100
  enabled?: boolean;
@@ -111,7 +112,7 @@ export interface DirectiveListControl {
111
112
  item_max_chars?: number;
112
113
  }
113
114
 
114
- /** Serializable controls for each field generated by SecondMind. */
115
+ /** Serializable controls for each field generated by Supafone Supervisor. */
115
116
  export interface DirectiveContract {
116
117
  empathyDirective?: DirectiveTextControl;
117
118
  empathy_directive?: DirectiveTextControl;
@@ -124,31 +125,34 @@ export interface DirectiveContract {
124
125
  language_mode?: "caller" | "model" | "fixed";
125
126
  fixedLanguage?: string;
126
127
  fixed_language?: string;
127
- allowedKinds?: SecondMindDirectiveKind[];
128
- allowed_kinds?: SecondMindDirectiveKind[];
128
+ allowedKinds?: SupervisorDirectiveKind[];
129
+ allowed_kinds?: SupervisorDirectiveKind[];
129
130
  confidenceThreshold?: number;
130
131
  confidence_threshold?: number;
131
132
  operatorGuardrails?: string[];
132
133
  operator_guardrails?: string[];
133
134
  }
134
135
 
135
- export interface SecondMindDirective {
136
+ export interface SupervisorDirective {
136
137
  empathy_directive: string;
137
138
  tactical_directive: string;
138
139
  surface_facts: string[];
139
140
  guardrails: string[];
140
141
  language: string;
141
142
  confidence: number;
142
- kind: SecondMindDirectiveKind;
143
+ kind: SupervisorDirectiveKind;
143
144
  }
144
145
 
146
+ /** @deprecated Use SupervisorDirective. */
147
+ export type SecondMindDirective = SupervisorDirective;
148
+
145
149
  export interface StructuredWhisperOptions extends WhisperOptions {
146
150
  directiveContract?: DirectiveContract;
147
151
  directive_contract?: DirectiveContract;
148
152
  /** Local final say: revise or suppress the generated directive before use. */
149
153
  transform?: (
150
- directive: SecondMindDirective,
151
- ) => SecondMindDirective | null | Promise<SecondMindDirective | null>;
154
+ directive: SupervisorDirective,
155
+ ) => SupervisorDirective | null | Promise<SupervisorDirective | null>;
152
156
  }
153
157
 
154
158
  export interface Balance {
@@ -618,9 +622,12 @@ export interface LabsArtifactsConfig {
618
622
  metadata?: Record<string, unknown>;
619
623
  }
620
624
 
621
- export interface LabsWatcherConfig {
625
+ export interface LabsSupervisorConfig {
622
626
  enabled?: boolean;
627
+ supervisor?: boolean;
628
+ /** @deprecated Use supervisor. */
623
629
  voiceWatcher?: boolean;
630
+ /** @deprecated Use supervisor. */
624
631
  voice_watcher?: boolean;
625
632
  apiKey?: string;
626
633
  api_key?: string;
@@ -636,6 +643,9 @@ export interface LabsWatcherConfig {
636
643
  label?: string;
637
644
  }
638
645
 
646
+ /** @deprecated Use LabsSupervisorConfig. */
647
+ export type LabsWatcherConfig = LabsSupervisorConfig;
648
+
639
649
  export interface LabsUltravoxRuntime {
640
650
  model?: string;
641
651
  temperature?: number;
@@ -948,9 +958,12 @@ export interface CreateLabsAgentRequest {
948
958
  artifacts?: LabsArtifactsConfig;
949
959
  compliance?: Record<string, unknown>;
950
960
  tools?: LabsToolsConfig;
951
- labs?: LabsWatcherConfig;
961
+ labs?: LabsSupervisorConfig;
952
962
  ultravox?: LabsUltravoxRuntime;
963
+ supervisor?: boolean;
964
+ /** @deprecated Use supervisor. */
953
965
  voiceWatcher?: boolean;
966
+ /** @deprecated Use supervisor. */
954
967
  voice_watcher?: boolean;
955
968
  voiceWatcherModel?: string;
956
969
  voice_watcher_model?: string;
@@ -1722,13 +1735,13 @@ const DEFAULT_BASE = "https://api.labs.supafone.ai";
1722
1735
  const DEFAULT_SUPAFONE_API_BASE = "https://api.supafone.ai";
1723
1736
 
1724
1737
  const COACH_SYSTEM =
1725
- "You are the coaching core of a second mind for a live voice agent. Read the " +
1738
+ "You are the coaching core of a supervisor for a live voice agent. Read the " +
1726
1739
  "conversation and return ONE short, silent directive the agent reads but never " +
1727
1740
  "speaks aloud — a correction or nudge, phrased imperatively. If nothing needs " +
1728
1741
  "correcting, return an empty string.";
1729
1742
 
1730
1743
  const STRUCTURED_COACH_SYSTEM =
1731
- "You are the coaching core of a second mind for a live voice agent. Read the " +
1744
+ "You are the coaching core of a supervisor for a live voice agent. Read the " +
1732
1745
  "conversation and return ONLY one JSON object with exactly these keys: " +
1733
1746
  "empathy_directive (string), tactical_directive (string), surface_facts (string[]), " +
1734
1747
  "guardrails (string[]), language (short code), confidence (0-1), and kind " +
@@ -1747,7 +1760,7 @@ interface NormalizedDirectiveContract {
1747
1760
  };
1748
1761
  language_mode: "caller" | "model" | "fixed";
1749
1762
  fixed_language: string;
1750
- allowed_kinds: SecondMindDirectiveKind[];
1763
+ allowed_kinds: SupervisorDirectiveKind[];
1751
1764
  confidence_threshold: number;
1752
1765
  operator_guardrails: string[];
1753
1766
  }
@@ -1787,7 +1800,7 @@ function normalizeDirectiveContract(input: DirectiveContract = {}): NormalizedDi
1787
1800
  guardrails: listControl(input.guardrails),
1788
1801
  language_mode: languageMode,
1789
1802
  fixed_language: String(input.fixed_language ?? input.fixedLanguage ?? "").trim(),
1790
- allowed_kinds: allowed.filter((kind): kind is SecondMindDirectiveKind =>
1803
+ allowed_kinds: allowed.filter((kind): kind is SupervisorDirectiveKind =>
1791
1804
  ["empathy", "tactical", "guardrail", "mixed"].includes(kind),
1792
1805
  ),
1793
1806
  confidence_threshold: Number.isFinite(threshold) ? Math.max(0, Math.min(1, threshold)) : 0.5,
@@ -1832,8 +1845,8 @@ function clipList(value: unknown, maxItems: number, itemMaxChars: number): strin
1832
1845
  function normalizeStructuredDirective(
1833
1846
  raw: Record<string, unknown>,
1834
1847
  contract: NormalizedDirectiveContract,
1835
- ): SecondMindDirective | null {
1836
- const kind = String(raw.kind ?? "mixed") as SecondMindDirectiveKind;
1848
+ ): SupervisorDirective | null {
1849
+ const kind = String(raw.kind ?? "mixed") as SupervisorDirectiveKind;
1837
1850
  if (!["empathy", "tactical", "guardrail", "mixed"].includes(kind)) return null;
1838
1851
  const parsedConfidence = Number(raw.confidence ?? 0);
1839
1852
  const confidence = Number.isFinite(parsedConfidence) ? Math.max(0, Math.min(1, parsedConfidence)) : 0;
@@ -1869,7 +1882,9 @@ export class SupafoneLabs {
1869
1882
  private readonly supafoneApiKey: string;
1870
1883
  private readonly timeoutMs: number;
1871
1884
  private readonly postCallAnalysis: boolean;
1872
- /** Client default for the Voice Watcher framework (supervision + QA + scoring). */
1885
+ /** Client default for Supafone Supervisor (live guidance + QA + scoring). */
1886
+ readonly supervisor: boolean;
1887
+ /** @deprecated Use supervisor. */
1873
1888
  readonly voiceWatcher: boolean;
1874
1889
  private sessionToken?: string;
1875
1890
  private accountToken?: string;
@@ -1898,8 +1913,9 @@ export class SupafoneLabs {
1898
1913
  this.appUrl = (opts.appUrl ?? "https://app.supafone.ai").replace(/\/$/, "");
1899
1914
  this.timeoutMs = opts.timeoutMs ?? 30_000;
1900
1915
  this.postCallAnalysis = opts.postCallAnalysis ?? false;
1901
- // Precedence: explicit voiceWatcher > voice_watcher (snake) > labs (deprecated) > true.
1902
- this.voiceWatcher = opts.voiceWatcher ?? opts.voice_watcher ?? opts.labs ?? true;
1916
+ // Precedence: supervisor > legacy aliases > true.
1917
+ this.supervisor = opts.supervisor ?? opts.voiceWatcher ?? opts.voice_watcher ?? opts.labs ?? true;
1918
+ this.voiceWatcher = this.supervisor;
1903
1919
  this.sessionToken = opts.sessionToken;
1904
1920
  this.accountToken = opts.accountToken;
1905
1921
  this.accountEmail = opts.accountEmail;
@@ -2259,14 +2275,14 @@ export class SupafoneLabs {
2259
2275
  }
2260
2276
 
2261
2277
  /**
2262
- * Structured SecondMind guidance with developer-controlled field policy.
2278
+ * Structured Supafone Supervisor guidance with developer-controlled field policy.
2263
2279
  * Returns null when JSON is invalid, evidence misses the confidence gate,
2264
2280
  * the generated kind is disallowed, or the local transform suppresses it.
2265
2281
  */
2266
2282
  async whisperStructured(
2267
2283
  transcript: string,
2268
2284
  opts: StructuredWhisperOptions = {},
2269
- ): Promise<SecondMindDirective | null> {
2285
+ ): Promise<SupervisorDirective | null> {
2270
2286
  const contract = normalizeDirectiveContract(
2271
2287
  opts.directive_contract ?? opts.directiveContract ?? {},
2272
2288
  );
@@ -2300,7 +2316,7 @@ export class SupafoneLabs {
2300
2316
  directive(
2301
2317
  transcript: string,
2302
2318
  opts: StructuredWhisperOptions = {},
2303
- ): Promise<SecondMindDirective | null> {
2319
+ ): Promise<SupervisorDirective | null> {
2304
2320
  return this.whisperStructured(transcript, opts);
2305
2321
  }
2306
2322
 
@@ -3097,7 +3113,7 @@ class LabsAgentsNamespace {
3097
3113
  return this.sm.requestSupafoneApi<CreateLabsAgentResponse>(
3098
3114
  "POST",
3099
3115
  "/api/v1/labs/agents",
3100
- labsAgentPayload(this.withVoiceWatcher(input)),
3116
+ labsAgentPayload(this.withSupervisor(input)),
3101
3117
  );
3102
3118
  }
3103
3119
 
@@ -3114,17 +3130,16 @@ class LabsAgentsNamespace {
3114
3130
  return this.plan(input);
3115
3131
  }
3116
3132
 
3117
- /** Default the agent onto the client's Voice Watcher setting (live supervision
3118
- * + QA + scoring) unless the caller set it explicitly; mirror into
3119
- * labs.voice_watcher when a labs block exists. Never overwrites a caller value. */
3120
- private withVoiceWatcher(input: CreateLabsAgentRequest): CreateLabsAgentRequest {
3133
+ /** Default the agent onto the client's Supafone Supervisor setting unless the
3134
+ * caller set it explicitly. Legacy wire fields remain unchanged. */
3135
+ private withSupervisor(input: CreateLabsAgentRequest): CreateLabsAgentRequest {
3121
3136
  const out: CreateLabsAgentRequest = { ...input };
3122
- if (out.voice_watcher === undefined && out.voiceWatcher === undefined) {
3123
- out.voice_watcher = this.sm.voiceWatcher;
3137
+ if (out.supervisor === undefined && out.voice_watcher === undefined && out.voiceWatcher === undefined) {
3138
+ out.supervisor = this.sm.supervisor;
3124
3139
  }
3125
3140
  const labs = out.labs;
3126
- if (labs && labs.voice_watcher === undefined && labs.voiceWatcher === undefined) {
3127
- out.labs = { ...labs, voice_watcher: this.sm.voiceWatcher };
3141
+ if (labs && labs.supervisor === undefined && labs.voice_watcher === undefined && labs.voiceWatcher === undefined) {
3142
+ out.labs = { ...labs, supervisor: this.sm.supervisor };
3128
3143
  }
3129
3144
  return out;
3130
3145
  }
@@ -4101,7 +4116,7 @@ function labsAgentPayload(input: CreateLabsAgentRequest): Record<string, unknown
4101
4116
  tools: input.tools ? toolsPayload(input.tools) : undefined,
4102
4117
  labs: input.labs ? labsPayload(input.labs) : undefined,
4103
4118
  ultravox: input.ultravox ? ultravoxPayload(input.ultravox) : undefined,
4104
- voice_watcher: input.voice_watcher ?? input.voiceWatcher,
4119
+ voice_watcher: input.supervisor ?? input.voice_watcher ?? input.voiceWatcher,
4105
4120
  voice_watcher_model: input.voice_watcher_model ?? input.voiceWatcherModel,
4106
4121
  metadata: labsAgentMetadataPayload(input),
4107
4122
  });
@@ -4533,10 +4548,10 @@ function artifactsPayload(input: LabsArtifactsConfig): Record<string, unknown> {
4533
4548
  });
4534
4549
  }
4535
4550
 
4536
- function labsPayload(input: LabsWatcherConfig): Record<string, unknown> {
4551
+ function labsPayload(input: LabsSupervisorConfig): Record<string, unknown> {
4537
4552
  return compact({
4538
4553
  enabled: input.enabled,
4539
- voice_watcher: input.voice_watcher ?? input.voiceWatcher,
4554
+ voice_watcher: input.supervisor ?? input.voice_watcher ?? input.voiceWatcher,
4540
4555
  api_key: input.api_key ?? input.apiKey,
4541
4556
  model: input.model,
4542
4557
  mode: input.mode,