@shogo-ai/voice 1.10.0 → 2.4.1

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.
Files changed (68) hide show
  1. package/README.md +89 -0
  2. package/dist/{chunk-S3S2RNO6.js → chunk-BI6SL35K.js} +1 -184
  3. package/dist/chunk-CLF25CZC.js +987 -0
  4. package/dist/chunk-KMSL5PWK.js +540 -0
  5. package/dist/chunk-ME3SIZZU.js +581 -0
  6. package/dist/chunk-TQOBJMEK.js +17 -0
  7. package/dist/{chunk-T3T4EBWY.js → chunk-UH75UVM2.js} +6 -2
  8. package/dist/chunk-UW7VQ3S6.js +148 -0
  9. package/dist/chunk-XE4LLC7Z.js +1067 -0
  10. package/dist/chunk-ZAW6F3YT.js +172 -0
  11. package/dist/index.cjs +735 -25
  12. package/dist/index.d.cts +373 -3
  13. package/dist/index.d.ts +373 -3
  14. package/dist/index.js +59 -3
  15. package/dist/live/client.cjs +173 -0
  16. package/dist/live/client.d.cts +132 -0
  17. package/dist/live/client.d.ts +132 -0
  18. package/dist/live/client.js +9 -0
  19. package/dist/native/index.d.cts +5 -2
  20. package/dist/native/index.d.ts +5 -2
  21. package/dist/native/index.js +15 -11
  22. package/dist/{organicParticlesShaders-DIva0vBO.d.ts → organicParticlesShaders-seZq7jYX.d.cts} +1 -421
  23. package/dist/{organicParticlesShaders-DIva0vBO.d.cts → organicParticlesShaders-seZq7jYX.d.ts} +1 -421
  24. package/dist/particlesConfig-0YbdPOdY.d.cts +223 -0
  25. package/dist/particlesConfig-0YbdPOdY.d.ts +223 -0
  26. package/dist/react/conversation.cjs +789 -0
  27. package/dist/react/conversation.d.cts +134 -0
  28. package/dist/react/conversation.d.ts +134 -0
  29. package/dist/react/conversation.js +13 -0
  30. package/dist/react/index.cjs +374 -36
  31. package/dist/react/index.d.cts +10 -141
  32. package/dist/react/index.d.ts +10 -141
  33. package/dist/react/index.js +23 -770
  34. package/dist/react/visuals.cjs +1048 -0
  35. package/dist/react/visuals.d.cts +70 -0
  36. package/dist/react/visuals.d.ts +70 -0
  37. package/dist/react/visuals.js +10 -0
  38. package/dist/route/agent.cjs +1038 -85
  39. package/dist/route/agent.js +3 -3
  40. package/dist/route/audio-tags.cjs +1038 -85
  41. package/dist/route/audio-tags.js +3 -3
  42. package/dist/route/index.cjs +1042 -85
  43. package/dist/route/index.d.cts +19 -3
  44. package/dist/route/index.d.ts +19 -3
  45. package/dist/route/index.js +3 -3
  46. package/dist/route/music.cjs +1038 -85
  47. package/dist/route/music.js +3 -3
  48. package/dist/route/op.cjs +2118 -0
  49. package/dist/route/op.d.cts +43 -0
  50. package/dist/route/op.d.ts +43 -0
  51. package/dist/route/op.js +27 -0
  52. package/dist/route/signed-url.cjs +1038 -85
  53. package/dist/route/signed-url.js +3 -3
  54. package/dist/route/tts-preview.cjs +1038 -85
  55. package/dist/route/tts-preview.d.cts +6 -4
  56. package/dist/route/tts-preview.d.ts +6 -4
  57. package/dist/route/tts-preview.js +3 -3
  58. package/dist/server.cjs +1038 -85
  59. package/dist/server.d.cts +40 -8
  60. package/dist/server.d.ts +40 -8
  61. package/dist/server.js +2 -2
  62. package/dist/types-Bfhu-aQH.d.cts +199 -0
  63. package/dist/types-Bfhu-aQH.d.ts +199 -0
  64. package/dist/{types-W9y6eMj3.d.ts → types-CadjTXNH.d.cts} +193 -12
  65. package/dist/{types-W9y6eMj3.d.cts → types-CadjTXNH.d.ts} +193 -12
  66. package/package.json +21 -1
  67. package/dist/chunk-B4JC3DK2.js +0 -529
  68. package/dist/chunk-O362EJQR.js +0 -524
package/README.md CHANGED
@@ -17,6 +17,95 @@ Native UI primitives.
17
17
  | `@shogo-ai/voice/native` | React Native equivalents (Expo). |
18
18
  | `@shogo-ai/voice/route/*` | Standard `(Request) => Response` route handlers. |
19
19
 
20
+ ## Media ops: one registry, no per-endpoint code
21
+
22
+ `VOICE_OPS` (from `@shogo-ai/voice`) is the registry of every ElevenLabs media
23
+ endpoint the SDK exposes. A row carries the upstream path, the transport
24
+ (`json-binary`, `json-json`, `multipart-binary`, `multipart-json`), the project
25
+ permission, the body limit, the model list and the metering unit. Handlers read
26
+ that table — there is no hand-written route per endpoint.
27
+
28
+ | Op | Transport | Upstream |
29
+ | --- | --- | --- |
30
+ | `text-to-speech` | JSON → audio | `POST /v1/text-to-speech/{voiceId}` |
31
+ | `text-to-speech-with-timestamps` | JSON → JSON | `POST /v1/text-to-speech/{voiceId}/with-timestamps` |
32
+ | `speech-to-speech` | multipart → audio | `POST /v1/speech-to-speech/{voiceId}` |
33
+ | `speech-to-text` | multipart → JSON | `POST /v1/speech-to-text` |
34
+ | `sound-generation` | JSON → audio | `POST /v1/sound-generation` |
35
+ | `music` | JSON → audio | `POST /v1/music` |
36
+ | `voices` | JSON → JSON | `GET /v1/voices` |
37
+ | `models` | JSON → JSON | `GET /v1/models` |
38
+
39
+ One route file serves all of them, present and future:
40
+
41
+ ```ts
42
+ // app/api/voice/op/[opId]+api.ts
43
+ export { GET, POST } from '@shogo-ai/sdk/voice/route/op'
44
+ ```
45
+
46
+ `handlers.op(req, opId)` is the same thing without a file convention. In proxy
47
+ mode every op is hosted on the Shogo API; the two legacy paths
48
+ (`/api/voice/tts`, `/api/voice/music`) still work because a row may keep a
49
+ `legacyHostedPath` for clients already in the field.
50
+
51
+ ### Adding an op
52
+
53
+ 1. Append a row to `VOICE_OPS` (`packages/voice/src/ops.ts`).
54
+ 2. Add one row to `packages/voice/src/__tests__/ops.test.ts` if it needs
55
+ validation the declarative fields cannot express.
56
+
57
+ That is the whole change. No route file, no handler, no proxy branch, no
58
+ per-op test file: `handlers.op`, the `route/op` modules and the hosted
59
+ `/api/voice/op/:opId` executor all pick it up.
60
+
61
+ Two things a row has to state, because the code cannot infer them: a body
62
+ field goes in `forward` (caller name → upstream name), while an upstream
63
+ **query** param goes in `queryForward` under its upstream name — ElevenLabs
64
+ ignores a body field that belongs in the query (`sound-generation`'s
65
+ `output_format`), so putting it in the wrong one is a silent no-op. A path
66
+ param in `pathParams` may be sent by the caller as a body field or a query
67
+ param; the multipart rebuild drops it from the upload either way.
68
+
69
+
70
+ ## TTS models
71
+
72
+ `VOICE_TTS_MODELS` (from `@shogo-ai/voice`) is the single source of truth for
73
+ model ids, per-request character caps and which models a convai agent can run
74
+ on (`realtime`). It covers `eleven_v4`, `eleven_v4_turbo`, `eleven_v3`,
75
+ `eleven_v3_conversational`, `eleven_multilingual_v2`, `eleven_flash_v2_5`,
76
+ `eleven_flash_v2`, `eleven_turbo_v2_5` and `eleven_turbo_v2`.
77
+
78
+ - `textToSpeech()` defaults to `eleven_v4`; convai agents default to
79
+ `eleven_v4_turbo` (`CONVAI_TTS_MODEL_FALLBACK`).
80
+ - `resolveConvaiTtsModelDetailed(requested)` returns
81
+ `{ modelId, requested, downgraded, reason }`; a downgrade is logged once per
82
+ distinct model instead of silently swapping it.
83
+ - `textToSpeech()` only falls back when the upstream failure is model-related
84
+ (402, or 400/403/404/422 mentioning model/plan/permission) and reports
85
+ `requestedModel` / `fellBack` / `fallbackReason`. The retry target is
86
+ `TTS_FALLBACK_MODEL` (`eleven_flash_v2_5`, the widest-available model) —
87
+ deliberately *not* `CONVAI_TTS_MODEL_FALLBACK`, so a BYO account without v4
88
+ entitlement still gets audio. The `tts` handler adds `x-tts-model-used`,
89
+ `x-tts-model-requested` and a `Warning: 199` header when they differ.
90
+
91
+ ## Proxy mode (Shogo pods)
92
+
93
+ With `RUNTIME_AUTH_SECRET` + `PROJECT_ID` in env and no `apiKey`,
94
+ `createVoiceHandlers({})` forwards to the Shogo API (`SHOGO_API_URL`, else
95
+ `SHOGO_CLOUD_URL`) using the runtime token:
96
+
97
+ - `signedUrl`, `tts`, `music`, `op`, `audioTags` — hosted.
98
+ - `elevenLabs.textToSpeech()`, `.composeMusic()`, `.speechToSpeech()`,
99
+ `.soundEffects()`, `.transcribe()` — hosted.
100
+ - `agent.*` and the other paired-account `elevenLabs` methods (cloning,
101
+ dubbing, voice design) — not available; they throw and need a BYO key.
102
+
103
+ An explicit `apiKey` wins over the ambient runtime token. `mode: 'proxy'`
104
+ forces the runtime token, `mode: 'byo'` forces your key, `'auto'` (default)
105
+ prefers the key. `tts` and `music` need only `apiKey`; `getUser` and
106
+ `companionStore` are required only for the user-scoped handlers
107
+ (`signedUrl`, `agent.*`).
108
+
20
109
  ## Peers (all optional)
21
110
 
22
111
  Install only the peers you actually use:
@@ -1,7 +1,3 @@
1
- import {
2
- stripAudioTags
3
- } from "./chunk-Q3TJAJ54.js";
4
-
5
1
  // src/react/shaders/organicSphereShaders.ts
6
2
  var PERLIN_4D = (
7
3
  /* glsl */
@@ -478,186 +474,7 @@ function resolveOrganicParticlesConfig(partial) {
478
474
  };
479
475
  }
480
476
 
481
- // src/shared/postJson.ts
482
- function createPostJson({
483
- authHeaders,
484
- fetchCredentials
485
- }) {
486
- return async function postJson(path, body) {
487
- return fetch(path, {
488
- method: "POST",
489
- headers: { "content-type": "application/json", ...authHeaders() },
490
- credentials: fetchCredentials,
491
- body: JSON.stringify(body)
492
- });
493
- };
494
- }
495
-
496
- // src/shared/memory.ts
497
- function createMemoryAddTool({
498
- postJson,
499
- memoryAddPath
500
- }) {
501
- return async (params) => {
502
- const fact = typeof params.fact === "string" ? params.fact : "";
503
- if (!fact.trim()) return "Memory save failed: empty fact.";
504
- try {
505
- const res = await postJson(memoryAddPath, { fact });
506
- if (!res.ok) return "Failed to save memory.";
507
- return "Memory saved.";
508
- } catch {
509
- return "Memory save failed.";
510
- }
511
- };
512
- }
513
- function createMemoryContextInjector({
514
- postJson,
515
- memoryRetrievePath,
516
- conversationRef,
517
- enabled,
518
- lastInjectedRef
519
- }) {
520
- return async function inject(userText) {
521
- if (!enabled) return;
522
- try {
523
- const res = await postJson(memoryRetrievePath, { query: userText, limit: 4 });
524
- if (!res.ok) return;
525
- const data = await res.json();
526
- const results = data.results ?? [];
527
- if (!results.length) return;
528
- const lines = results.map((r) => `- ${r.chunk.trim().replace(/\s+/g, " ").slice(0, 200)}`).join("\n");
529
- if (lines === lastInjectedRef.current) return;
530
- lastInjectedRef.current = lines;
531
- const payload = `Relevant memory about this user:
532
- ${lines}`;
533
- conversationRef.current?.sendContextualUpdate(payload);
534
- } catch {
535
- }
536
- };
537
- }
538
-
539
- // src/shared/transcript.ts
540
- function createTranscriptDisconnectHandler({
541
- isRestartingRef,
542
- weStartedSessionRef,
543
- transcriptRef,
544
- onTranscript,
545
- transcriptIngestPath,
546
- postJson
547
- }) {
548
- return function handleTranscriptOnDisconnect() {
549
- if (isRestartingRef.current) {
550
- return;
551
- }
552
- if (!weStartedSessionRef.current) {
553
- transcriptRef.current = [];
554
- return;
555
- }
556
- weStartedSessionRef.current = false;
557
- const transcript = transcriptRef.current.join("\n");
558
- transcriptRef.current = [];
559
- if (onTranscript) {
560
- void onTranscript(transcript);
561
- return;
562
- }
563
- const trimmed = transcript.trim();
564
- if (trimmed.length < 20) return;
565
- void postJson(transcriptIngestPath, { transcript: trimmed }).catch(() => {
566
- });
567
- };
568
- }
569
- function appendTranscriptLine(msg, { transcriptRef, weStartedSessionRef }) {
570
- if (!msg?.message || !msg?.source) return;
571
- if (!weStartedSessionRef.current) return;
572
- const speaker = msg.source === "user" ? "User" : "Agent";
573
- const cleaned = msg.source === "user" ? msg.message : stripAudioTags(msg.message);
574
- if (!cleaned) return;
575
- transcriptRef.current.push(`${speaker}: ${cleaned}`);
576
- }
577
-
578
- // src/shared/sessionPayload.ts
579
- function sanitizeDynamicVariables(raw) {
580
- if (raw == null) return {};
581
- const out = {};
582
- for (const [k, v] of Object.entries(raw)) {
583
- if (v == null) continue;
584
- out[k] = typeof v === "string" ? v : String(v);
585
- }
586
- return out;
587
- }
588
- function buildSessionPayload(opts) {
589
- const dynamicVariables = {
590
- ...sanitizeDynamicVariables(opts.dynamicVariables),
591
- character_name: opts.characterName,
592
- user_context: opts.userContext
593
- };
594
- if (typeof opts.conversationId === "string" && opts.conversationId.length > 0) {
595
- dynamicVariables.conversation_id = opts.conversationId;
596
- }
597
- const payload = {
598
- signedUrl: opts.signedUrl,
599
- dynamicVariables
600
- };
601
- const agentOverrides = {};
602
- if (opts.suppressFirstMessage) {
603
- agentOverrides.firstMessage = "";
604
- }
605
- if (typeof opts.agentPromptOverride === "string" && opts.agentPromptOverride.length > 0) {
606
- agentOverrides.prompt = { prompt: opts.agentPromptOverride };
607
- }
608
- if (Object.keys(agentOverrides).length > 0) {
609
- payload.overrides = { agent: agentOverrides };
610
- }
611
- return payload;
612
- }
613
- async function fetchSignedUrl({
614
- path,
615
- fetchCredentials,
616
- authHeaders
617
- }) {
618
- const res = await fetch(path, {
619
- credentials: fetchCredentials,
620
- headers: authHeaders()
621
- });
622
- if (!res.ok) throw new Error(`Signed URL request failed: ${res.status}`);
623
- return await res.json();
624
- }
625
- function withProjectQuery(signedUrlPath, params) {
626
- const tail = [];
627
- if (typeof params.projectId === "string" && params.projectId.length > 0) {
628
- tail.push(`projectId=${encodeURIComponent(params.projectId)}`);
629
- }
630
- if (typeof params.agentName === "string" && params.agentName.length > 0) {
631
- tail.push(`agentName=${encodeURIComponent(params.agentName)}`);
632
- }
633
- if (tail.length === 0) return signedUrlPath;
634
- const sep = signedUrlPath.includes("?") ? "&" : "?";
635
- return `${signedUrlPath}${sep}${tail.join("&")}`;
636
- }
637
-
638
- // src/shared/chatUrl.ts
639
- function appendChatQuery(basePath, params) {
640
- const tail = [];
641
- for (const [k, v] of Object.entries(params)) {
642
- if (typeof v === "string" && v.length > 0) {
643
- tail.push(`${k}=${encodeURIComponent(v)}`);
644
- }
645
- }
646
- if (tail.length === 0) return basePath;
647
- const sep = basePath.includes("?") ? "&" : "?";
648
- return `${basePath}${sep}${tail.join("&")}`;
649
- }
650
-
651
477
  export {
652
- createPostJson,
653
- createMemoryAddTool,
654
- createMemoryContextInjector,
655
- createTranscriptDisconnectHandler,
656
- appendTranscriptLine,
657
- buildSessionPayload,
658
- fetchSignedUrl,
659
- withProjectQuery,
660
- appendChatQuery,
661
478
  PERLIN_4D,
662
479
  ORGANIC_SPHERE_VERTEX_SHADER,
663
480
  ORGANIC_SPHERE_FRAGMENT_SHADER,
@@ -668,4 +485,4 @@ export {
668
485
  DEFAULT_ORGANIC_PARTICLES_CONFIG,
669
486
  resolveOrganicParticlesConfig
670
487
  };
671
- //# sourceMappingURL=chunk-S3S2RNO6.js.map
488
+ //# sourceMappingURL=chunk-BI6SL35K.js.map