supafone-labs 0.6.1 → 0.6.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
@@ -1,3 +1,6 @@
1
+ export { SupafoneS2S, UltravoxS2S, OpenAIS2S, GeminiS2S, GrokS2S, HydraS2S } from "./s2s.js";
2
+ export type { S2SProviderName, S2SModelOptions, S2SOptions } from "./s2s.js";
3
+
1
4
  /**
2
5
  * Supafone Labs — the agent framework behind Supafone.
3
6
  *
@@ -385,7 +388,7 @@ export interface LabsVoicePreference {
385
388
 
386
389
  /** Direct speech-to-speech configuration for browser previews and carrier phone calls. */
387
390
  export interface LabsRealtimeSelection {
388
- provider: "openai" | "google" | "xai";
391
+ provider: "openai" | "google" | "xai" | "smallest";
389
392
  model?: string;
390
393
  voice?: string;
391
394
  }
@@ -402,10 +405,21 @@ export interface LabsBrowserTestSession {
402
405
  provider: string;
403
406
  transport: "ultravox" | "supafone_realtime";
404
407
  join_url?: string | null;
405
- websocket_url?: string;
406
- token?: string;
408
+ websocket_url?: string | null;
409
+ token?: string | null;
407
410
  input_sample_rate?: number;
408
411
  output_sample_rate?: number;
412
+ capabilities?: {
413
+ stages?: boolean;
414
+ tools?: boolean;
415
+ transcripts?: boolean;
416
+ recording?: boolean;
417
+ supervisor?: boolean;
418
+ transfer?: boolean;
419
+ mutable_instructions?: boolean;
420
+ stage_update_mode?: string;
421
+ languages?: string[];
422
+ };
409
423
  };
410
424
  }
411
425
 
@@ -483,6 +497,9 @@ export interface LabsProviderKeys {
483
497
  xai?: string;
484
498
  xaiApiKey?: string;
485
499
  xai_api_key?: string;
500
+ smallest?: string;
501
+ smallestApiKey?: string;
502
+ smallest_api_key?: string;
486
503
  [extra: string]: unknown;
487
504
  }
488
505
 
@@ -1123,7 +1140,10 @@ export interface LabsAgentReadiness {
1123
1140
  [extra: string]: unknown;
1124
1141
  }
1125
1142
 
1126
- export type UpdateLabsAgentRequest = Partial<CreateLabsAgentRequest>;
1143
+ export type UpdateLabsAgentRequest = Omit<Partial<CreateLabsAgentRequest>, "realtime"> & {
1144
+ /** Select another native model, or null to return to the default Ultravox runtime. */
1145
+ realtime?: LabsRealtimeSelection | null;
1146
+ };
1127
1147
 
1128
1148
  export interface LabsAgentLifecycleResponse {
1129
1149
  success?: boolean;
@@ -3340,7 +3360,7 @@ class LabsBillingNamespace {
3340
3360
  class LabsAgentsNamespace {
3341
3361
  constructor(private sm: SupafoneLabs) {}
3342
3362
 
3343
- /** Spawn a durable hosted Supafone agent backed by Ultravox and Supafone-managed providers. */
3363
+ /** Create a hosted Supafone agent with the default Ultravox runtime or a selected native S2S model. */
3344
3364
  create(input: CreateLabsAgentRequest): Promise<CreateLabsAgentResponse> {
3345
3365
  return this.sm.requestSupafoneApi<CreateLabsAgentResponse>(
3346
3366
  "POST",
@@ -4351,7 +4371,9 @@ function labsAgentMetadataPayload(input: CreateLabsAgentRequest): Record<string,
4351
4371
  }
4352
4372
 
4353
4373
  function labsAgentUpdatePayload(input: UpdateLabsAgentRequest): Record<string, unknown> {
4354
- return labsAgentPayload(input as CreateLabsAgentRequest);
4374
+ const payload = labsAgentPayload(input as CreateLabsAgentRequest);
4375
+ if (input.realtime === null) payload.realtime = null;
4376
+ return payload;
4355
4377
  }
4356
4378
 
4357
4379
  function campaignSettingsPayload(
@@ -4752,6 +4774,8 @@ function providerKeysPayload(input: LabsProviderKeys): Record<string, unknown> {
4752
4774
  openai_api_key: input.openai_api_key ?? input.openaiApiKey,
4753
4775
  xai: input.xai,
4754
4776
  xai_api_key: input.xai_api_key ?? input.xaiApiKey,
4777
+ smallest: input.smallest,
4778
+ smallest_api_key: input.smallest_api_key ?? input.smallestApiKey,
4755
4779
  });
4756
4780
  }
4757
4781
 
package/src/s2s.ts ADDED
@@ -0,0 +1,100 @@
1
+ import type {
2
+ CreateLabsAgentRequest,
3
+ GetLabsAgentOptions,
4
+ LabsRealtimeSelection,
5
+ SupafoneLabs,
6
+ } from "./index.js";
7
+
8
+ export type S2SProviderName = "ultravox" | "openai" | "google" | "xai" | "smallest";
9
+ export interface S2SModelOptions {
10
+ model?: string;
11
+ voice?: string;
12
+ }
13
+ export interface S2SOptions extends S2SModelOptions {
14
+ provider?: S2SProviderName;
15
+ }
16
+
17
+ /** Shared parent for Supafone-hosted S2S agents. Vendor keys stay on the server. */
18
+ export class SupafoneS2S {
19
+ readonly provider: S2SProviderName;
20
+ private readonly selection: LabsRealtimeSelection | null;
21
+
22
+ constructor(protected readonly client: SupafoneLabs, options: S2SOptions = {}) {
23
+ const provider = options.provider ?? "ultravox";
24
+ if (!["ultravox", "openai", "google", "xai", "smallest"].includes(provider)) {
25
+ throw new Error("Unsupported Supafone S2S provider");
26
+ }
27
+ if (provider === "ultravox" && (options.model !== undefined || options.voice !== undefined)) {
28
+ throw new Error("Configure Ultravox voices through the agent's voice settings");
29
+ }
30
+ for (const field of ["model", "voice"] as const) {
31
+ const value = options[field];
32
+ if (value !== undefined && (typeof value !== "string" || !value.trim())) {
33
+ throw new Error(`${field} must be a non-empty string`);
34
+ }
35
+ }
36
+ this.provider = provider;
37
+ this.selection = provider === "ultravox" ? null : {
38
+ provider,
39
+ ...(options.model !== undefined ? { model: options.model.trim() } : {}),
40
+ ...(options.voice !== undefined ? { voice: options.voice.trim() } : {}),
41
+ };
42
+ }
43
+
44
+ /** A fresh wire selection; null explicitly restores the default Ultravox runtime. */
45
+ get realtime(): LabsRealtimeSelection | null {
46
+ return this.selection ? { ...this.selection } : null;
47
+ }
48
+
49
+ /** Create through the normal hosted agent factory with this provider. */
50
+ create(input: Omit<CreateLabsAgentRequest, "realtime">) {
51
+ if ("realtime" in input) {
52
+ throw new Error("Set provider/model/voice on the S2S adapter, not create({realtime: ...})");
53
+ }
54
+ return this.client.labs.agents.create({
55
+ ...input,
56
+ ...(this.realtime ? { realtime: this.realtime } : {}),
57
+ });
58
+ }
59
+
60
+ /** Change the saved selection for subsequent calls, preserving the agent and number. */
61
+ apply(agentKey: string, options: GetLabsAgentOptions = {}) {
62
+ this.checkAgentKey(agentKey);
63
+ return this.client.labs.agents.update(agentKey, { realtime: this.realtime }, options);
64
+ }
65
+
66
+ /** Preview the saved agent. Call apply first when switching providers. */
67
+ testCall(agentKey: string, options: GetLabsAgentOptions = {}) {
68
+ this.checkAgentKey(agentKey);
69
+ return this.client.labs.agents.testCall(agentKey, options);
70
+ }
71
+
72
+ private checkAgentKey(agentKey: string): void {
73
+ if (typeof agentKey !== "string" || !agentKey.trim()) throw new Error("agentKey is required");
74
+ }
75
+ }
76
+
77
+ export class UltravoxS2S extends SupafoneS2S {
78
+ constructor(client: SupafoneLabs) { super(client, { provider: "ultravox" }); }
79
+ }
80
+ export class OpenAIS2S extends SupafoneS2S {
81
+ constructor(client: SupafoneLabs, options: S2SModelOptions = {}) {
82
+ super(client, { ...options, provider: "openai" });
83
+ }
84
+ }
85
+ export class GeminiS2S extends SupafoneS2S {
86
+ constructor(client: SupafoneLabs, options: S2SModelOptions = {}) {
87
+ super(client, { ...options, provider: "google" });
88
+ }
89
+ }
90
+ export class GrokS2S extends SupafoneS2S {
91
+ constructor(client: SupafoneLabs, options: S2SModelOptions = {}) {
92
+ super(client, { ...options, provider: "xai" });
93
+ }
94
+ }
95
+ /** Smallest AI Hydra: full-duplex audio, without transcript events. */
96
+ export class HydraS2S extends SupafoneS2S {
97
+ constructor(client: SupafoneLabs, options: S2SModelOptions = {}) {
98
+ super(client, { ...options, provider: "smallest" });
99
+ }
100
+ }