@klex/agent-admin-api 0.10.0 → 0.11.0

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
@@ -34,6 +34,16 @@ returned by the API are redacted and must never contain resolved environment
34
34
  secrets. Model selection uses separate `providerId` and opaque `modelId` fields;
35
35
  clients must not split model IDs on colons.
36
36
 
37
+ ## Realtime voice client contract
38
+
39
+ - `GET /v1/providers/{id}/voices?modelId=...&refresh=false` returns `selectionSupported`, optional `defaultVoiceId`, and compatible entries with opaque `voiceId`, display metadata, provenance and preview availability. Provider capabilities advertise discovery/preview hooks; model-scoped support determines whether a selector is available. Listing does not generate audio. Encode the complete model ID in the query, including slashes/colons.
40
+ - `POST /v1/providers/{id}/voices/preview` takes `{ modelId, voiceId }`. It can trigger billable same-model Live generation and returns binary `audio/wav`, not JSON/base64 or a public URL. `X-Voice-Preview-Model` is URI-encoded and `X-Voice-Preview-Mode` is `live`. On failure parse the JSON error contract; 429 means quota, 502 means upstream generation failure. Arbitrary text/URLs/model overrides are not accepted.
41
+ - `PATCH /v1/settings/model-selection` saves `voice.sts` references with optional `voiceId`. Preserve both `voice.tts` and `voice.stt` because the voice object is replaced. Omit `voiceId` in the replacement STS reference to reset. Other selection purposes reject it. New calls use changes; active calls do not switch voices.
42
+
43
+ Existing omitted defaults remain: OpenAI Realtime/GPT-Live `marin`, Gemini's provider default. Unknown/custom model profiles remain usable with defaults, but have no selectable catalog. Catalog provenance distinguishes maintained/discovered data, with explicit fallback/stale flags. Samples improvise a short introduction from the current agent name and full soul. Realtime/Gemini generate it directly; GPT-Live uses the first configured chat model to write commentary before speaking it with the selected Live voice. That extra text call is potentially billable and requires a chat selection. GPT-Live may paraphrase commentary. Name/soul changes bypass old cached samples; different voices may use different wording. Browser clients fetch over their existing authorized Cloud path, check `response.ok`, then use `response.blob()` and an object URL for playback (revoke it afterward). Headless/TUI clients use `arrayBuffer()` and an external WAV player; the backend does not implement playback.
44
+
45
+ Local admin access remains unauthenticated and loopback-only; Cloud access remains authorized through the existing tunnel. Responses use private/no-store headers, while the agent caches successful samples in bounded memory for reuse. Previewing never starts a production call or supplies history, tools, or credentials as prompt context. It intentionally supplies the full soul to the speech provider or, for GPT-Live, the configured chat provider. Prompts instruct models not to speak private details, but generated output still depends on provider behavior. No UI selector is included in this contract change.
46
+
37
47
  ## MCP OAuth authorization
38
48
 
39
49
  Version 0.2 adds the consolidated MCP authorization contract. Authorization is
package/dist/index.d.ts CHANGED
@@ -207,6 +207,7 @@ export type AdminApi = import("hono/hono-base").HonoBase<any, {
207
207
  [x: string]: import("hono/utils/types").JSONValue;
208
208
  };
209
209
  } | undefined;
210
+ voiceId?: string | undefined;
210
211
  }[];
211
212
  tts: {
212
213
  providerId: string;
@@ -280,6 +281,7 @@ export type AdminApi = import("hono/hono-base").HonoBase<any, {
280
281
  providerId: string;
281
282
  modelId: string;
282
283
  providerOptions?: Record<string, Record<string, unknown>> | undefined;
284
+ voiceId?: string | undefined;
283
285
  }[];
284
286
  tts: {
285
287
  providerId: string;
@@ -339,6 +341,7 @@ export type AdminApi = import("hono/hono-base").HonoBase<any, {
339
341
  providerId: string;
340
342
  modelId: string;
341
343
  providerOptions?: Record<string, Record<string, unknown>> | undefined;
344
+ voiceId?: string | undefined;
342
345
  }[];
343
346
  tts: {
344
347
  providerId: string;
@@ -418,6 +421,7 @@ export type AdminApi = import("hono/hono-base").HonoBase<any, {
418
421
  [x: string]: import("hono/utils/types").JSONValue;
419
422
  };
420
423
  } | undefined;
424
+ voiceId?: string | undefined;
421
425
  }[];
422
426
  tts: {
423
427
  providerId: string;
@@ -482,6 +486,7 @@ export type AdminApi = import("hono/hono-base").HonoBase<any, {
482
486
  providerId: string;
483
487
  modelId: string;
484
488
  providerOptions?: Record<string, Record<string, unknown>> | undefined;
489
+ voiceId?: string | undefined;
485
490
  }[];
486
491
  tts: {
487
492
  providerId: string;
@@ -1924,6 +1929,8 @@ export type AdminApi = import("hono/hono-base").HonoBase<any, {
1924
1929
  documentationUrl?: string | undefined;
1925
1930
  capabilities: {
1926
1931
  modelDiscovery: boolean;
1932
+ voiceDiscovery: boolean;
1933
+ voicePreview: boolean;
1927
1934
  connectivityTest: boolean;
1928
1935
  customModels: boolean;
1929
1936
  };
@@ -1989,6 +1996,8 @@ export type AdminApi = import("hono/hono-base").HonoBase<any, {
1989
1996
  documentationUrl?: string | undefined;
1990
1997
  capabilities: {
1991
1998
  modelDiscovery: boolean;
1999
+ voiceDiscovery: boolean;
2000
+ voicePreview: boolean;
1992
2001
  connectivityTest: boolean;
1993
2002
  customModels: boolean;
1994
2003
  };
@@ -2039,6 +2048,8 @@ export type AdminApi = import("hono/hono-base").HonoBase<any, {
2039
2048
  documentationUrl?: string | undefined;
2040
2049
  capabilities: {
2041
2050
  modelDiscovery: boolean;
2051
+ voiceDiscovery: boolean;
2052
+ voicePreview: boolean;
2042
2053
  connectivityTest: boolean;
2043
2054
  customModels: boolean;
2044
2055
  };
@@ -2129,6 +2140,8 @@ export type AdminApi = import("hono/hono-base").HonoBase<any, {
2129
2140
  documentationUrl?: string | undefined;
2130
2141
  capabilities: {
2131
2142
  modelDiscovery: boolean;
2143
+ voiceDiscovery: boolean;
2144
+ voicePreview: boolean;
2132
2145
  connectivityTest: boolean;
2133
2146
  customModels: boolean;
2134
2147
  };
@@ -2231,6 +2244,8 @@ export type AdminApi = import("hono/hono-base").HonoBase<any, {
2231
2244
  documentationUrl?: string | undefined;
2232
2245
  capabilities: {
2233
2246
  modelDiscovery: boolean;
2247
+ voiceDiscovery: boolean;
2248
+ voicePreview: boolean;
2234
2249
  connectivityTest: boolean;
2235
2250
  customModels: boolean;
2236
2251
  };
@@ -2336,6 +2351,8 @@ export type AdminApi = import("hono/hono-base").HonoBase<any, {
2336
2351
  documentationUrl?: string | undefined;
2337
2352
  capabilities: {
2338
2353
  modelDiscovery: boolean;
2354
+ voiceDiscovery: boolean;
2355
+ voicePreview: boolean;
2339
2356
  connectivityTest: boolean;
2340
2357
  customModels: boolean;
2341
2358
  };
@@ -2528,6 +2545,243 @@ export type AdminApi = import("hono/hono-base").HonoBase<any, {
2528
2545
  };
2529
2546
  };
2530
2547
  };
2548
+ } & {
2549
+ "/v1/providers/:id/voices": {
2550
+ $get: {
2551
+ output: {
2552
+ error: string;
2553
+ code: string;
2554
+ remediation?: string | undefined;
2555
+ };
2556
+ outputFormat: "json";
2557
+ status: 400;
2558
+ input: {
2559
+ param: {
2560
+ id: string;
2561
+ };
2562
+ } & {
2563
+ query: {
2564
+ modelId: string;
2565
+ refresh?: "false" | "true" | undefined;
2566
+ };
2567
+ };
2568
+ } | {
2569
+ output: {
2570
+ error: string;
2571
+ code: string;
2572
+ remediation?: string | undefined;
2573
+ };
2574
+ outputFormat: "json";
2575
+ status: 404;
2576
+ input: {
2577
+ param: {
2578
+ id: string;
2579
+ };
2580
+ } & {
2581
+ query: {
2582
+ modelId: string;
2583
+ refresh?: "false" | "true" | undefined;
2584
+ };
2585
+ };
2586
+ } | {
2587
+ output: {
2588
+ error: string;
2589
+ code: string;
2590
+ remediation?: string | undefined;
2591
+ };
2592
+ outputFormat: "json";
2593
+ status: 429;
2594
+ input: {
2595
+ param: {
2596
+ id: string;
2597
+ };
2598
+ } & {
2599
+ query: {
2600
+ modelId: string;
2601
+ refresh?: "false" | "true" | undefined;
2602
+ };
2603
+ };
2604
+ } | {
2605
+ output: {
2606
+ error: string;
2607
+ code: string;
2608
+ remediation?: string | undefined;
2609
+ };
2610
+ outputFormat: "json";
2611
+ status: 500;
2612
+ input: {
2613
+ param: {
2614
+ id: string;
2615
+ };
2616
+ } & {
2617
+ query: {
2618
+ modelId: string;
2619
+ refresh?: "false" | "true" | undefined;
2620
+ };
2621
+ };
2622
+ } | {
2623
+ output: {
2624
+ error: string;
2625
+ code: string;
2626
+ remediation?: string | undefined;
2627
+ };
2628
+ outputFormat: "json";
2629
+ status: 502;
2630
+ input: {
2631
+ param: {
2632
+ id: string;
2633
+ };
2634
+ } & {
2635
+ query: {
2636
+ modelId: string;
2637
+ refresh?: "false" | "true" | undefined;
2638
+ };
2639
+ };
2640
+ } | {
2641
+ output: {
2642
+ selectionSupported: boolean;
2643
+ defaultVoiceId?: string | undefined;
2644
+ fallback?: boolean | undefined;
2645
+ stale?: boolean | undefined;
2646
+ voices: {
2647
+ voiceId: string;
2648
+ displayName: string;
2649
+ description?: string | undefined;
2650
+ language?: string | undefined;
2651
+ region?: string | undefined;
2652
+ provenance: {
2653
+ source: "discovered" | "maintained";
2654
+ documentationUrl: string;
2655
+ reviewedAt?: string | undefined;
2656
+ };
2657
+ preview: {
2658
+ available: boolean;
2659
+ mode?: "live" | undefined;
2660
+ };
2661
+ }[];
2662
+ };
2663
+ outputFormat: "json";
2664
+ status: 200;
2665
+ input: {
2666
+ param: {
2667
+ id: string;
2668
+ };
2669
+ } & {
2670
+ query: {
2671
+ modelId: string;
2672
+ refresh?: "false" | "true" | undefined;
2673
+ };
2674
+ };
2675
+ };
2676
+ };
2677
+ } & {
2678
+ "/v1/providers/:id/voices/preview": {
2679
+ $post: {
2680
+ output: {
2681
+ error: string;
2682
+ code: string;
2683
+ remediation?: string | undefined;
2684
+ };
2685
+ outputFormat: "json";
2686
+ status: 400;
2687
+ input: {
2688
+ param: {
2689
+ id: string;
2690
+ };
2691
+ } & {
2692
+ json: {
2693
+ modelId: string;
2694
+ voiceId: string;
2695
+ };
2696
+ };
2697
+ } | {
2698
+ output: {
2699
+ error: string;
2700
+ code: string;
2701
+ remediation?: string | undefined;
2702
+ };
2703
+ outputFormat: "json";
2704
+ status: 404;
2705
+ input: {
2706
+ param: {
2707
+ id: string;
2708
+ };
2709
+ } & {
2710
+ json: {
2711
+ modelId: string;
2712
+ voiceId: string;
2713
+ };
2714
+ };
2715
+ } | {
2716
+ output: {
2717
+ error: string;
2718
+ code: string;
2719
+ remediation?: string | undefined;
2720
+ };
2721
+ outputFormat: "json";
2722
+ status: 429;
2723
+ input: {
2724
+ param: {
2725
+ id: string;
2726
+ };
2727
+ } & {
2728
+ json: {
2729
+ modelId: string;
2730
+ voiceId: string;
2731
+ };
2732
+ };
2733
+ } | {
2734
+ output: {
2735
+ error: string;
2736
+ code: string;
2737
+ remediation?: string | undefined;
2738
+ };
2739
+ outputFormat: "json";
2740
+ status: 500;
2741
+ input: {
2742
+ param: {
2743
+ id: string;
2744
+ };
2745
+ } & {
2746
+ json: {
2747
+ modelId: string;
2748
+ voiceId: string;
2749
+ };
2750
+ };
2751
+ } | {
2752
+ output: {
2753
+ error: string;
2754
+ code: string;
2755
+ remediation?: string | undefined;
2756
+ };
2757
+ outputFormat: "json";
2758
+ status: 502;
2759
+ input: {
2760
+ param: {
2761
+ id: string;
2762
+ };
2763
+ } & {
2764
+ json: {
2765
+ modelId: string;
2766
+ voiceId: string;
2767
+ };
2768
+ };
2769
+ } | {
2770
+ output: Response;
2771
+ outputFormat: "json";
2772
+ status: import("hono/utils/http-status").StatusCode;
2773
+ input: {
2774
+ param: {
2775
+ id: string;
2776
+ };
2777
+ } & {
2778
+ json: {
2779
+ modelId: string;
2780
+ voiceId: string;
2781
+ };
2782
+ };
2783
+ };
2784
+ };
2531
2785
  } & {
2532
2786
  "/v1/providers/:id/models": {
2533
2787
  $post: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@klex/agent-admin-api",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Shared types for the Klex Bot Admin API",