@effect-uai/inworld 0.12.0 → 0.12.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 (42) hide show
  1. package/dist/InworldRealtimeSynthesizer.d.mts +6 -11
  2. package/dist/InworldRealtimeSynthesizer.d.mts.map +1 -1
  3. package/dist/InworldRealtimeSynthesizer.mjs +1 -1
  4. package/dist/InworldRealtimeSynthesizer.mjs.map +1 -1
  5. package/dist/InworldRealtimeTranscriber.d.mts +5 -12
  6. package/dist/InworldRealtimeTranscriber.d.mts.map +1 -1
  7. package/dist/InworldRealtimeTranscriber.mjs +1 -1
  8. package/dist/InworldRealtimeTranscriber.mjs.map +1 -1
  9. package/dist/InworldSynthesizer.d.mts +8 -11
  10. package/dist/InworldSynthesizer.d.mts.map +1 -1
  11. package/dist/InworldSynthesizer.mjs +10 -9
  12. package/dist/InworldSynthesizer.mjs.map +1 -1
  13. package/dist/InworldTranscriber.d.mts +3 -5
  14. package/dist/InworldTranscriber.d.mts.map +1 -1
  15. package/dist/InworldTranscriber.mjs +1 -1
  16. package/dist/InworldTranscriber.mjs.map +1 -1
  17. package/dist/{codec-C-2ssVAz.d.mts → codec-BU4azW_k.d.mts} +2 -4
  18. package/dist/codec-BU4azW_k.d.mts.map +1 -0
  19. package/dist/codec.d.mts +1 -1
  20. package/dist/codec.mjs +1 -1
  21. package/dist/codec.mjs.map +1 -1
  22. package/dist/index.d.mts +2 -2
  23. package/dist/{models-CPLZDcgt.d.mts → models-DySX9PVy.d.mts} +1 -1
  24. package/dist/models-DySX9PVy.d.mts.map +1 -0
  25. package/dist/models.d.mts +1 -1
  26. package/dist/realtimeStt.d.mts +0 -1
  27. package/dist/realtimeStt.d.mts.map +1 -1
  28. package/dist/realtimeStt.mjs.map +1 -1
  29. package/dist/realtimeTts.d.mts +1 -2
  30. package/dist/realtimeTts.d.mts.map +1 -1
  31. package/dist/realtimeTts.mjs.map +1 -1
  32. package/dist/wsAuth.d.mts +0 -1
  33. package/dist/wsAuth.d.mts.map +1 -1
  34. package/dist/wsAuth.mjs.map +1 -1
  35. package/package.json +5 -5
  36. package/src/InworldRealtimeSynthesizer.ts +9 -13
  37. package/src/InworldRealtimeTranscriber.ts +4 -8
  38. package/src/InworldSynthesizer.ts +8 -12
  39. package/src/InworldTranscriber.ts +4 -8
  40. package/dist/codec-C-2ssVAz.d.mts.map +0 -1
  41. package/dist/models-CPLZDcgt.d.mts.map +0 -1
  42. /package/dist/{chunk-CfYAbeIz.mjs → rolldown-runtime-D7D4PA-g.mjs} +0 -0
@@ -1,24 +1,19 @@
1
1
  import { Config, InworldSynthesizeRequest, InworldSynthesizer, InworldSynthesizerService } from "./InworldSynthesizer.mjs";
2
2
  import { Effect, Layer, Stream } from "effect";
3
3
  import { HttpClient } from "effect/unstable/http";
4
- import * as _$_effect_uai_core_SpeechSynthesizer0 from "@effect-uai/core/SpeechSynthesizer";
5
4
  import { CommonStreamSynthesizeRequest, SpeechSynthesizer, TtsIncrementalText } from "@effect-uai/core/SpeechSynthesizer";
6
- import * as _$_effect_uai_core_AiError0 from "@effect-uai/core/AiError";
7
- import * as _$_effect_uai_core_Audio0 from "@effect-uai/core/Audio";
8
-
9
- //#region src/InworldRealtimeSynthesizer.d.ts
10
5
  declare namespace InworldRealtimeSynthesizer_d_exports {
11
6
  export { Config, InworldSynthesizeRequest, InworldSynthesizer, InworldSynthesizerService, layer, make };
12
7
  }
13
8
  declare const make: (cfg: Config) => Effect.Effect<{
14
9
  synthesize: (r: InworldSynthesizeRequest) => Effect.Effect<{
15
- format: _$_effect_uai_core_Audio0.AudioFormat;
10
+ format: import("@effect-uai/core/Audio").AudioFormat;
16
11
  bytes: Uint8Array<ArrayBufferLike>;
17
- }, _$_effect_uai_core_AiError0.AiError, never>;
18
- streamSynthesis: (r: InworldSynthesizeRequest) => Stream.Stream<_$_effect_uai_core_Audio0.AudioChunk, _$_effect_uai_core_AiError0.AiError, never>;
19
- streamSynthesisFrom: <E, R>(textIn: Stream.Stream<string, E, R>, request: CommonStreamSynthesizeRequest) => Stream.Stream<_$_effect_uai_core_Audio0.AudioChunk, _$_effect_uai_core_AiError0.AiError | E, R>;
20
- synthesizeDialogue: (request: _$_effect_uai_core_SpeechSynthesizer0.CommonSynthesizeDialogueRequest) => Effect.Effect<_$_effect_uai_core_Audio0.AudioBlob, _$_effect_uai_core_AiError0.AiError>;
21
- streamSynthesizeDialogue: (request: _$_effect_uai_core_SpeechSynthesizer0.CommonSynthesizeDialogueRequest) => Stream.Stream<_$_effect_uai_core_Audio0.AudioChunk, _$_effect_uai_core_AiError0.AiError>;
12
+ }, import("@effect-uai/core/AiError").AiError, never>;
13
+ streamSynthesis: (r: InworldSynthesizeRequest) => Stream.Stream<import("@effect-uai/core/Audio").AudioChunk, import("@effect-uai/core/AiError").AiError, never>;
14
+ streamSynthesisFrom: <E, R>(textIn: Stream.Stream<string, E, R>, request: CommonStreamSynthesizeRequest) => Stream.Stream<import("@effect-uai/core/Audio").AudioChunk, E | import("@effect-uai/core/AiError").AiError, R>;
15
+ synthesizeDialogue: (request: import("@effect-uai/core/SpeechSynthesizer").CommonSynthesizeDialogueRequest) => Effect.Effect<import("@effect-uai/core/Audio").AudioBlob, import("@effect-uai/core/AiError").AiError>;
16
+ streamSynthesizeDialogue: (request: import("@effect-uai/core/SpeechSynthesizer").CommonSynthesizeDialogueRequest) => Stream.Stream<import("@effect-uai/core/Audio").AudioChunk, import("@effect-uai/core/AiError").AiError>;
22
17
  }, never, HttpClient.HttpClient>;
23
18
  /**
24
19
  * Realtime Layer. Registers `InworldSynthesizer`, the generic
@@ -1 +1 @@
1
- {"version":3,"file":"InworldRealtimeSynthesizer.d.mts","names":[],"sources":["../src/InworldRealtimeSynthesizer.ts"],"mappings":";;;;;;;;;;;;cAsCa,IAAA,GAAQ,GAAA,EAAK,MAAA,KAAM,MAAA,CAAA,MAAA;;;;;;;;;;;;;;;;;cAuBnB,KAAA,GAAS,GAAA,EAAK,MAAA,KAAM,KAAA,CAAA,KAAA,CAAA,kBAAA,GAAA,iBAAA,GAAA,kBAAA,SAAA,UAAA,CAAA,UAAA"}
1
+ {"version":3,"file":"InworldRealtimeSynthesizer.d.mts","names":[],"sources":["../src/InworldRealtimeSynthesizer.ts"],"mappings":";;;;;;;cAsCa,OAAI,KAAS,WAAM,OAAA;;;;;;;;;UAc7B,WAAA;;;;;;;;cASU,QAAK,KAAS,WAAM,MAAA,MAAA,qBAAA,oBAAA,2BAAA,WAAA"}
@@ -1,4 +1,4 @@
1
- import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
2
  import { InworldSynthesizer, dialogueUnsupportedImpl, streamDialogueUnsupportedImpl, streamSynthesisImpl, synthesizeImpl } from "./InworldSynthesizer.mjs";
3
3
  import { streamSynthesis } from "./realtimeTts.mjs";
4
4
  import { Effect, Layer, Stream } from "effect";
@@ -1 +1 @@
1
- {"version":3,"file":"InworldRealtimeSynthesizer.mjs","names":["realtimeStream"],"sources":["../src/InworldRealtimeSynthesizer.ts"],"sourcesContent":["/**\n * Realtime variant of `InworldSynthesizer`. Wires `streamSynthesisFrom` to\n * `wss://api.inworld.ai/tts/v1/voice:streamBidirectional` and registers\n * the `TtsIncrementalText` capability marker, so the call compiles\n * against this Layer alone.\n *\n * Sync `synthesize` and chunked `streamSynthesis` reuse the implementations\n * exported from `./InworldSynthesizer.js` — the only added surface here is\n * the WS path.\n */\nimport { Effect, Layer, Stream } from \"effect\"\nimport { HttpClient } from \"effect/unstable/http\"\nimport {\n type CommonStreamSynthesizeRequest,\n type CommonSynthesizeRequest,\n SpeechSynthesizer,\n type SpeechSynthesizerService,\n TtsIncrementalText,\n} from \"@effect-uai/core/SpeechSynthesizer\"\nimport {\n type Config,\n dialogueUnsupportedImpl,\n InworldSynthesizer,\n type InworldSynthesizerService,\n type InworldSynthesizeRequest,\n streamDialogueUnsupportedImpl,\n streamSynthesisImpl,\n synthesizeImpl,\n} from \"./InworldSynthesizer.js\"\nimport { streamSynthesis as realtimeStream } from \"./realtimeTts.js\"\n\nexport type {\n Config,\n InworldSynthesizerService,\n InworldSynthesizeRequest,\n} from \"./InworldSynthesizer.js\"\nexport { InworldSynthesizer } from \"./InworldSynthesizer.js\"\n\nexport const make = (cfg: Config) =>\n Effect.map(\n HttpClient.HttpClient,\n (client) =>\n ({\n synthesize: (r) =>\n synthesizeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamSynthesis: (r) =>\n streamSynthesisImpl(cfg)(r).pipe(Stream.provideService(HttpClient.HttpClient, client)),\n streamSynthesisFrom: (textIn, request) =>\n realtimeStream(cfg)(textIn, request as InworldSynthesizeRequest),\n synthesizeDialogue: dialogueUnsupportedImpl,\n streamSynthesizeDialogue: streamDialogueUnsupportedImpl,\n }) satisfies InworldSynthesizerService,\n )\n\n/**\n * Realtime Layer. Registers `InworldSynthesizer`, the generic\n * `SpeechSynthesizer`, **and** the `TtsIncrementalText` capability\n * marker. The WS constructor uses the `ws` peer dep internally to set\n * the `Authorization: Basic` header — no `Socket.WebSocketConstructor`\n * needed at the call site.\n */\nexport const layer = (cfg: Config) =>\n Layer.mergeAll(\n Layer.effect(InworldSynthesizer, make(cfg)),\n Layer.effect(\n SpeechSynthesizer,\n Effect.map(\n make(cfg),\n (s): SpeechSynthesizerService => ({\n synthesize: (req: CommonSynthesizeRequest) =>\n s.synthesize(req as InworldSynthesizeRequest),\n streamSynthesis: (req: CommonSynthesizeRequest) =>\n s.streamSynthesis(req as InworldSynthesizeRequest),\n streamSynthesisFrom: (textIn, req: CommonStreamSynthesizeRequest) =>\n s.streamSynthesisFrom(textIn, req),\n synthesizeDialogue: s.synthesizeDialogue,\n streamSynthesizeDialogue: s.streamSynthesizeDialogue,\n }),\n ),\n ),\n Layer.succeed(TtsIncrementalText, undefined),\n )\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAsCA,MAAa,QAAQ,QACnB,OAAO,IACL,WAAW,aACV,YACE;CACC,aAAa,MACX,eAAe,IAAI,CAAC,EAAE,CAAC,KAAK,OAAO,eAAe,WAAW,YAAY,OAAO,CAAC;CACnF,kBAAkB,MAChB,oBAAoB,IAAI,CAAC,EAAE,CAAC,KAAK,OAAO,eAAe,WAAW,YAAY,OAAO,CAAC;CACxF,sBAAsB,QAAQ,YAC5BA,gBAAe,IAAI,CAAC,QAAQ,QAAoC;CAClE,oBAAoB;CACpB,0BAA0B;CAC3B,EACJ;;;;;;;;AASH,MAAa,SAAS,QACpB,MAAM,SACJ,MAAM,OAAO,oBAAoB,KAAK,IAAI,CAAC,EAC3C,MAAM,OACJ,mBACA,OAAO,IACL,KAAK,IAAI,GACR,OAAiC;CAChC,aAAa,QACX,EAAE,WAAW,IAAgC;CAC/C,kBAAkB,QAChB,EAAE,gBAAgB,IAAgC;CACpD,sBAAsB,QAAQ,QAC5B,EAAE,oBAAoB,QAAQ,IAAI;CACpC,oBAAoB,EAAE;CACtB,0BAA0B,EAAE;CAC7B,EACF,CACF,EACD,MAAM,QAAQ,oBAAoB,KAAA,EAAU,CAC7C"}
1
+ {"version":3,"file":"InworldRealtimeSynthesizer.mjs","names":["realtimeStream"],"sources":["../src/InworldRealtimeSynthesizer.ts"],"sourcesContent":["/**\n * Realtime variant of `InworldSynthesizer`. Wires `streamSynthesisFrom` to\n * `wss://api.inworld.ai/tts/v1/voice:streamBidirectional` and registers\n * the `TtsIncrementalText` capability marker, so the call compiles\n * against this Layer alone.\n *\n * Sync `synthesize` and chunked `streamSynthesis` reuse the implementations\n * exported from `./InworldSynthesizer.js` — the only added surface here is\n * the WS path.\n */\nimport { Effect, Layer, Stream } from \"effect\"\nimport { HttpClient } from \"effect/unstable/http\"\nimport {\n type CommonStreamSynthesizeRequest,\n type CommonSynthesizeRequest,\n SpeechSynthesizer,\n type SpeechSynthesizerService,\n TtsIncrementalText,\n} from \"@effect-uai/core/SpeechSynthesizer\"\nimport {\n type Config,\n dialogueUnsupportedImpl,\n InworldSynthesizer,\n type InworldSynthesizerService,\n type InworldSynthesizeRequest,\n streamDialogueUnsupportedImpl,\n streamSynthesisImpl,\n synthesizeImpl,\n} from \"./InworldSynthesizer.js\"\nimport { streamSynthesis as realtimeStream } from \"./realtimeTts.js\"\n\nexport type {\n Config,\n InworldSynthesizerService,\n InworldSynthesizeRequest,\n} from \"./InworldSynthesizer.js\"\nexport { InworldSynthesizer } from \"./InworldSynthesizer.js\"\n\nexport const make = (cfg: Config) =>\n Effect.map(\n HttpClient.HttpClient,\n (client) =>\n ({\n synthesize: (r) =>\n synthesizeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamSynthesis: (r) =>\n streamSynthesisImpl(cfg)(r).pipe(Stream.provideService(HttpClient.HttpClient, client)),\n streamSynthesisFrom: (textIn, request) =>\n realtimeStream(cfg)(textIn, request as InworldSynthesizeRequest),\n synthesizeDialogue: dialogueUnsupportedImpl,\n streamSynthesizeDialogue: streamDialogueUnsupportedImpl,\n }) satisfies InworldSynthesizerService,\n )\n\n/**\n * Realtime Layer. Registers `InworldSynthesizer`, the generic\n * `SpeechSynthesizer`, **and** the `TtsIncrementalText` capability\n * marker. The WS constructor uses the `ws` peer dep internally to set\n * the `Authorization: Basic` header — no `Socket.WebSocketConstructor`\n * needed at the call site.\n */\nexport const layer = (cfg: Config) =>\n Layer.mergeAll(\n Layer.effect(InworldSynthesizer, make(cfg)),\n Layer.effect(\n SpeechSynthesizer,\n Effect.map(make(cfg), (s): SpeechSynthesizerService => ({\n synthesize: (req: CommonSynthesizeRequest) => s.synthesize(req as InworldSynthesizeRequest),\n streamSynthesis: (req: CommonSynthesizeRequest) =>\n s.streamSynthesis(req as InworldSynthesizeRequest),\n streamSynthesisFrom: (textIn, req: CommonStreamSynthesizeRequest) =>\n s.streamSynthesisFrom(textIn, req),\n synthesizeDialogue: s.synthesizeDialogue,\n streamSynthesizeDialogue: s.streamSynthesizeDialogue,\n })),\n ),\n Layer.succeed(TtsIncrementalText, undefined),\n )\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAsCA,MAAa,QAAQ,QACnB,OAAO,IACL,WAAW,aACV,YACE;CACC,aAAa,MACX,eAAe,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,eAAe,WAAW,YAAY,MAAM,CAAC;CAClF,kBAAkB,MAChB,oBAAoB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,eAAe,WAAW,YAAY,MAAM,CAAC;CACvF,sBAAsB,QAAQ,YAC5BA,gBAAe,GAAG,CAAC,CAAC,QAAQ,OAAmC;CACjE,oBAAoB;CACpB,0BAA0B;AAC5B,EACJ;;;;;;;;AASF,MAAa,SAAS,QACpB,MAAM,SACJ,MAAM,OAAO,oBAAoB,KAAK,GAAG,CAAC,GAC1C,MAAM,OACJ,mBACA,OAAO,IAAI,KAAK,GAAG,IAAI,OAAiC;CACtD,aAAa,QAAiC,EAAE,WAAW,GAA+B;CAC1F,kBAAkB,QAChB,EAAE,gBAAgB,GAA+B;CACnD,sBAAsB,QAAQ,QAC5B,EAAE,oBAAoB,QAAQ,GAAG;CACnC,oBAAoB,EAAE;CACtB,0BAA0B,EAAE;AAC9B,EAAE,CACJ,GACA,MAAM,QAAQ,oBAAoB,KAAA,CAAS,CAC7C"}
@@ -1,30 +1,23 @@
1
1
  import { Config, InworldTranscribeRequest, InworldTranscriber, InworldTranscriberService } from "./InworldTranscriber.mjs";
2
2
  import { Effect, Layer } from "effect";
3
3
  import { HttpClient } from "effect/unstable/http";
4
- import * as _$_effect_uai_core_AiError0 from "@effect-uai/core/AiError";
5
- import * as _$_effect_uai_core_Transcriber0 from "@effect-uai/core/Transcriber";
6
4
  import { SttStreaming, Transcriber } from "@effect-uai/core/Transcriber";
7
- import * as _$effect_Schema0 from "effect/Schema";
8
- import * as _$_effect_uai_core_Transcript0 from "@effect-uai/core/Transcript";
9
- import * as _$effect_Stream0 from "effect/Stream";
10
-
11
- //#region src/InworldRealtimeTranscriber.d.ts
12
5
  declare namespace InworldRealtimeTranscriber_d_exports {
13
6
  export { Config, InworldTranscribeRequest, InworldTranscriber, InworldTranscriberService, layer, make };
14
7
  }
15
8
  declare const make: (cfg: Config) => Effect.Effect<{
16
9
  transcribe: (r: InworldTranscribeRequest) => Effect.Effect<{
17
- raw: _$effect_Schema0.Json;
18
- words?: _$_effect_uai_core_Transcript0.WordTimestamp[];
19
10
  text: string;
20
- }, _$_effect_uai_core_AiError0.AiError, never>;
21
- streamTranscriptionFrom: <E, R>(audioIn: _$effect_Stream0.Stream<Uint8Array<ArrayBufferLike>, E, R>, request: _$_effect_uai_core_Transcriber0.CommonStreamTranscribeRequest) => _$effect_Stream0.Stream<_$_effect_uai_core_Transcript0.TranscriptEvent, _$_effect_uai_core_AiError0.AiError | E, R>;
11
+ words?: import("@effect-uai/core/Transcript").WordTimestamp[];
12
+ raw: import("effect/Schema").Json;
13
+ }, import("@effect-uai/core/AiError").AiError, never>;
14
+ streamTranscriptionFrom: <E, R>(audioIn: import("effect/Stream").Stream<Uint8Array<ArrayBufferLike>, E, R>, request: import("@effect-uai/core/Transcriber").CommonStreamTranscribeRequest) => import("effect/Stream").Stream<import("@effect-uai/core/Transcript").TranscriptEvent, E | import("@effect-uai/core/AiError").AiError, R>;
22
15
  }, never, HttpClient.HttpClient>;
23
16
  /**
24
17
  * Realtime Layer. Registers `InworldTranscriber`, the generic
25
18
  * `Transcriber`, **and** the `SttStreaming` capability marker.
26
19
  */
27
- declare const layer: (cfg: Config) => Layer.Layer<InworldTranscriber | Transcriber | SttStreaming, never, HttpClient.HttpClient>;
20
+ declare const layer: (cfg: Config) => Layer.Layer<InworldTranscriber | SttStreaming | Transcriber, never, HttpClient.HttpClient>;
28
21
  //#endregion
29
22
  export { type Config, type InworldTranscribeRequest, InworldTranscriber, type InworldTranscriberService, layer, make, InworldRealtimeTranscriber_d_exports as t };
30
23
  //# sourceMappingURL=InworldRealtimeTranscriber.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"InworldRealtimeTranscriber.d.mts","names":[],"sources":["../src/InworldRealtimeTranscriber.ts"],"mappings":";;;;;;;;;;;;;;cAiCa,IAAA,GAAQ,GAAA,EAAK,MAAA,KAAM,MAAA,CAAA,MAAA;;;;;;;;;;;;cAenB,KAAA,GAAS,GAAA,EAAK,MAAA,KAAM,KAAA,CAAA,KAAA,CAAA,kBAAA,GAAA,WAAA,GAAA,YAAA,SAAA,UAAA,CAAA,UAAA"}
1
+ {"version":3,"file":"InworldRealtimeTranscriber.d.mts","names":[],"sources":["../src/InworldRealtimeTranscriber.ts"],"mappings":";;;;;;;cAiCa,OAAI,KAAS,WAAM,OAAA;;;;;;;UAS7B,WAAA;;;;;cAMU,QAAK,KAAS,WAAM,MAAA,MAAA,qBAAA,eAAA,oBAAA,WAAA"}
@@ -1,4 +1,4 @@
1
- import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
2
  import { InworldTranscriber, transcribeImpl } from "./InworldTranscriber.mjs";
3
3
  import { streamTranscription } from "./realtimeStt.mjs";
4
4
  import { Effect, Layer } from "effect";
@@ -1 +1 @@
1
- {"version":3,"file":"InworldRealtimeTranscriber.mjs","names":[],"sources":["../src/InworldRealtimeTranscriber.ts"],"sourcesContent":["/**\n * Realtime variant of `InworldTranscriber`. Wires `streamTranscriptionFrom`\n * to `wss://api.inworld.ai/stt/v1/transcribe:streamBidirectional` and\n * registers the `SttStreaming` capability marker, so calls compile against\n * this Layer alone.\n *\n * Sync `transcribe` reuses `transcribeImpl` from `./InworldTranscriber.js` —\n * the only added surface is the WS path.\n */\nimport { Effect, Layer } from \"effect\"\nimport { HttpClient } from \"effect/unstable/http\"\nimport {\n type CommonTranscribeRequest,\n SttStreaming,\n Transcriber,\n type TranscriberService,\n} from \"@effect-uai/core/Transcriber\"\nimport {\n type Config,\n InworldTranscriber,\n type InworldTranscriberService,\n type InworldTranscribeRequest,\n transcribeImpl,\n} from \"./InworldTranscriber.js\"\nimport { streamTranscription } from \"./realtimeStt.js\"\n\nexport type {\n Config,\n InworldTranscriberService,\n InworldTranscribeRequest,\n} from \"./InworldTranscriber.js\"\nexport { InworldTranscriber } from \"./InworldTranscriber.js\"\n\nexport const make = (cfg: Config) =>\n Effect.map(\n HttpClient.HttpClient,\n (client) =>\n ({\n transcribe: (r) =>\n transcribeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamTranscriptionFrom: (audioIn, request) => streamTranscription(cfg)(audioIn, request),\n }) satisfies InworldTranscriberService,\n )\n\n/**\n * Realtime Layer. Registers `InworldTranscriber`, the generic\n * `Transcriber`, **and** the `SttStreaming` capability marker.\n */\nexport const layer = (cfg: Config) =>\n Layer.mergeAll(\n Layer.effect(InworldTranscriber, make(cfg)),\n Layer.effect(\n Transcriber,\n Effect.map(\n make(cfg),\n (s): TranscriberService => ({\n transcribe: (req: CommonTranscribeRequest) =>\n s.transcribe(req as InworldTranscribeRequest),\n streamTranscriptionFrom: s.streamTranscriptionFrom,\n }),\n ),\n ),\n Layer.succeed(SttStreaming, undefined),\n )\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAiCA,MAAa,QAAQ,QACnB,OAAO,IACL,WAAW,aACV,YACE;CACC,aAAa,MACX,eAAe,IAAI,CAAC,EAAE,CAAC,KAAK,OAAO,eAAe,WAAW,YAAY,OAAO,CAAC;CACnF,0BAA0B,SAAS,YAAY,oBAAoB,IAAI,CAAC,SAAS,QAAQ;CAC1F,EACJ;;;;;AAMH,MAAa,SAAS,QACpB,MAAM,SACJ,MAAM,OAAO,oBAAoB,KAAK,IAAI,CAAC,EAC3C,MAAM,OACJ,aACA,OAAO,IACL,KAAK,IAAI,GACR,OAA2B;CAC1B,aAAa,QACX,EAAE,WAAW,IAAgC;CAC/C,yBAAyB,EAAE;CAC5B,EACF,CACF,EACD,MAAM,QAAQ,cAAc,KAAA,EAAU,CACvC"}
1
+ {"version":3,"file":"InworldRealtimeTranscriber.mjs","names":[],"sources":["../src/InworldRealtimeTranscriber.ts"],"sourcesContent":["/**\n * Realtime variant of `InworldTranscriber`. Wires `streamTranscriptionFrom`\n * to `wss://api.inworld.ai/stt/v1/transcribe:streamBidirectional` and\n * registers the `SttStreaming` capability marker, so calls compile against\n * this Layer alone.\n *\n * Sync `transcribe` reuses `transcribeImpl` from `./InworldTranscriber.js` —\n * the only added surface is the WS path.\n */\nimport { Effect, Layer } from \"effect\"\nimport { HttpClient } from \"effect/unstable/http\"\nimport {\n type CommonTranscribeRequest,\n SttStreaming,\n Transcriber,\n type TranscriberService,\n} from \"@effect-uai/core/Transcriber\"\nimport {\n type Config,\n InworldTranscriber,\n type InworldTranscriberService,\n type InworldTranscribeRequest,\n transcribeImpl,\n} from \"./InworldTranscriber.js\"\nimport { streamTranscription } from \"./realtimeStt.js\"\n\nexport type {\n Config,\n InworldTranscriberService,\n InworldTranscribeRequest,\n} from \"./InworldTranscriber.js\"\nexport { InworldTranscriber } from \"./InworldTranscriber.js\"\n\nexport const make = (cfg: Config) =>\n Effect.map(\n HttpClient.HttpClient,\n (client) =>\n ({\n transcribe: (r) =>\n transcribeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamTranscriptionFrom: (audioIn, request) => streamTranscription(cfg)(audioIn, request),\n }) satisfies InworldTranscriberService,\n )\n\n/**\n * Realtime Layer. Registers `InworldTranscriber`, the generic\n * `Transcriber`, **and** the `SttStreaming` capability marker.\n */\nexport const layer = (cfg: Config) =>\n Layer.mergeAll(\n Layer.effect(InworldTranscriber, make(cfg)),\n Layer.effect(\n Transcriber,\n Effect.map(make(cfg), (s): TranscriberService => ({\n transcribe: (req: CommonTranscribeRequest) => s.transcribe(req as InworldTranscribeRequest),\n streamTranscriptionFrom: s.streamTranscriptionFrom,\n })),\n ),\n Layer.succeed(SttStreaming, undefined),\n )\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAiCA,MAAa,QAAQ,QACnB,OAAO,IACL,WAAW,aACV,YACE;CACC,aAAa,MACX,eAAe,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,eAAe,WAAW,YAAY,MAAM,CAAC;CAClF,0BAA0B,SAAS,YAAY,oBAAoB,GAAG,CAAC,CAAC,SAAS,OAAO;AAC1F,EACJ;;;;;AAMF,MAAa,SAAS,QACpB,MAAM,SACJ,MAAM,OAAO,oBAAoB,KAAK,GAAG,CAAC,GAC1C,MAAM,OACJ,aACA,OAAO,IAAI,KAAK,GAAG,IAAI,OAA2B;CAChD,aAAa,QAAiC,EAAE,WAAW,GAA+B;CAC1F,yBAAyB,EAAE;AAC7B,EAAE,CACJ,GACA,MAAM,QAAQ,cAAc,KAAA,CAAS,CACvC"}
@@ -1,13 +1,10 @@
1
- import { a as InworldVoiceId, i as InworldTtsModel, n as InworldDeliveryMode } from "./models-CPLZDcgt.mjs";
2
- import { t as AudioConfig } from "./codec-C-2ssVAz.mjs";
1
+ import { a as InworldVoiceId, i as InworldTtsModel, n as InworldDeliveryMode } from "./models-DySX9PVy.mjs";
2
+ import { t as AudioConfig } from "./codec-BU4azW_k.mjs";
3
3
  import { Context, Effect, Layer, Redacted, Stream } from "effect";
4
4
  import { HttpClient } from "effect/unstable/http";
5
5
  import { CommonSynthesizeRequest, SpeechSynthesizer, SpeechSynthesizerService } from "@effect-uai/core/SpeechSynthesizer";
6
6
  import * as AiError from "@effect-uai/core/AiError";
7
- import * as _$_effect_uai_core_Audio0 from "@effect-uai/core/Audio";
8
7
  import { AudioBlob, AudioChunk } from "@effect-uai/core/Audio";
9
-
10
- //#region src/InworldSynthesizer.d.ts
11
8
  declare namespace InworldSynthesizer_d_exports {
12
9
  export { Config, InworldSynthesizeRequest, InworldSynthesizer, InworldSynthesizerService, buildBody, dialogueUnsupportedImpl, layer, make, streamDialogueUnsupportedImpl, streamSynthesisImpl, synthesizeImpl };
13
10
  }
@@ -43,20 +40,20 @@ type Config = {
43
40
  /** Exported for reuse by the realtime variant's BOS `create` frame. */
44
41
  declare const buildBody: (r: InworldSynthesizeRequest) => Effect.Effect<{
45
42
  body: {
46
- applyTextNormalization?: "ON" | "OFF";
47
- temperature?: number;
48
- deliveryMode?: InworldDeliveryMode;
49
- language?: string;
50
43
  text: string;
51
44
  voiceId: string;
52
45
  modelId: InworldTtsModel;
53
46
  audioConfig: AudioConfig;
47
+ language?: string;
48
+ deliveryMode?: InworldDeliveryMode;
49
+ temperature?: number;
50
+ applyTextNormalization?: "OFF" | "ON";
54
51
  };
55
- format: _$_effect_uai_core_Audio0.AudioFormat;
52
+ format: import("@effect-uai/core/Audio").AudioFormat;
56
53
  }, AiError.AiError, never>;
57
54
  /** Exported for reuse by `InworldRealtimeSynthesizer`. */
58
55
  declare const synthesizeImpl: (cfg: Config) => (request: InworldSynthesizeRequest) => Effect.Effect<{
59
- format: _$_effect_uai_core_Audio0.AudioFormat;
56
+ format: import("@effect-uai/core/Audio").AudioFormat;
60
57
  bytes: Uint8Array<ArrayBufferLike>;
61
58
  }, AiError.AiError, HttpClient.HttpClient>;
62
59
  /** Exported for reuse by `InworldRealtimeSynthesizer`. */
@@ -1 +1 @@
1
- {"version":3,"file":"InworldSynthesizer.d.mts","names":[],"sources":["../src/InworldSynthesizer.ts"],"mappings":";;;;;;;;;;;;;;;;;;;AA+CA;;;KAAY,wBAAA,GAA2B,IAAA,CAAK,uBAAA;EAAA,SACjC,KAAA,EAAO,eAAA;EAAA,SACP,OAAA,EAAS,cAAA;EAAA,SACT,WAAA;EAAA,SACA,YAAA,GAAe,mBAAA;EAAA,SACf,sBAAA;AAAA;AAAA,KAGC,yBAAA;EAAA,SACD,UAAA,GAAa,CAAA,EAAG,wBAAA,KAA6B,MAAA,CAAO,MAAA,CAAO,SAAA,EAAW,OAAA,CAAQ,OAAA;EAAA,SAC9E,eAAA,GACP,CAAA,EAAG,wBAAA,KACA,MAAA,CAAO,MAAA,CAAO,UAAA,EAAY,OAAA,CAAQ,OAAA;EAAA,SAC9B,mBAAA,EAAqB,wBAAA;EAAA,SACrB,kBAAA,EAAoB,wBAAA;EAAA,SACpB,wBAAA,EAA0B,wBAAA;AAAA;AAAA,cACpC,uBAAA;cAEY,kBAAA,SAA2B,uBAAA;AAAA,KAK5B,MAAA;EAAA,SAAoB,MAAA,EAAQ,QAAA,CAAS,QAAA;EAAA,SAAmB,OAAA;AAAA;;cAyBvD,SAAA,GAAa,CAAA,EAAG,wBAAA,KAAwB,MAAA,CAAA,MAAA;;;;;;;;;;;;;;cA4CxC,cAAA,GAAkB,GAAA,EAAK,MAAA,MAAY,OAAA,EAAS,wBAAA,KAAwB,MAAA,CAAA,MAAA;UAAA,yBAAA,CAAA,WAAA;;;;cAoCpE,mBAAA,GAAuB,GAAA,EAAK,MAAA,MAAY,OAAA,EAAS,wBAAA,KAAwB,MAAA,CAAA,MAAA,CAAA,UAAA,EAAA,OAAA,CAAA,OAAA,EAAA,UAAA,CAAA,UAAA;;cA2CzE,uBAAA,EAAyB,wBAAA;;cAUzB,6BAAA,EAA+B,wBAAA;AAAA,cAc/B,IAAA,GACX,GAAA,EAAK,MAAA,KACJ,MAAA,CAAO,MAAA,CAAO,yBAAA,SAAkC,UAAA,CAAW,UAAA;;;;;;cAgBjD,KAAA,GACX,GAAA,EAAK,MAAA,KACJ,KAAA,CAAM,KAAA,CAAM,kBAAA,GAAqB,iBAAA,SAA0B,UAAA,CAAW,UAAA"}
1
+ {"version":3,"file":"InworldSynthesizer.d.mts","names":[],"sources":["../src/InworldSynthesizer.ts"],"mappings":";;;;;;;;;;;;;;;;;;;KA+CY,2BAA2B,KAAK;WACjC,OAAO;WACP,SAAS;WACT;WACA,eAAe;WACf;;KAGC;WACD,aAAa,GAAG,6BAA6B,OAAO,OAAO,WAAW,QAAQ;WAC9E,kBACP,GAAG,6BACA,OAAO,OAAO,YAAY,QAAQ;WAC9B,qBAAqB;WACrB,oBAAoB;WACpB,0BAA0B;;;cAGxB,2BAA2B;KAK5B;WAAoB,QAAQ,SAAS;WAAmB;;;cAyBvD,YAAS,GAAO,6BAAwB,OAAA;;;;;;;;;;;;GAiBjD,QAAA;;cA2BS,iBAAc,KAAS,YAAM,SAAe,6BAAwB,OAAA;;;GAsB7E,QAAA,SAAA,WAAA;;cAcS,sBAAmB,KAAS,YAAM,SAAe,6BAAwB,OAAA,OAAA,YAAA,QAAA,SAAA,WAAA;;cA2CzE,yBAAyB;;cAUzB,+BAA+B;cAc/B,OAAI,KACV,WACJ,OAAO,OAAO,kCAAkC,WAAW;;;;;;cAgBjD,QAAK,KACX,WACJ,MAAM,MAAM,qBAAqB,0BAA0B,WAAW"}
@@ -1,4 +1,4 @@
1
- import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
2
  import { audioConfigFor, authHeader, decodeAudioContent, defaultFormat, httpStatusError, transportFailure } from "./codec.mjs";
3
3
  import { Array, Context, Effect, Layer, Schema, Stream } from "effect";
4
4
  import { HttpClient, HttpClientRequest } from "effect/unstable/http";
@@ -77,16 +77,17 @@ const synthesizeImpl = (cfg) => (request) => Effect.gen(function* () {
77
77
  return yield* Effect.fail(httpStatusError(response.status, text));
78
78
  }
79
79
  const json = yield* response.json.pipe(Effect.mapError(transportFailure));
80
+ const wire = yield* decodeSyncResponse(json).pipe(Effect.mapError((cause) => new AiError.GenerationFailed({
81
+ provider: "inworld",
82
+ raw: {
83
+ message: "sync TTS response missing `audioContent`",
84
+ cause,
85
+ json
86
+ }
87
+ })));
80
88
  return {
81
89
  format,
82
- bytes: yield* decodeAudioContent((yield* decodeSyncResponse(json).pipe(Effect.mapError((cause) => new AiError.GenerationFailed({
83
- provider: "inworld",
84
- raw: {
85
- message: "sync TTS response missing `audioContent`",
86
- cause,
87
- json
88
- }
89
- })))).audioContent)
90
+ bytes: yield* decodeAudioContent(wire.audioContent)
90
91
  };
91
92
  });
92
93
  const lineToStream = (line) => {
@@ -1 +1 @@
1
- {"version":3,"file":"InworldSynthesizer.mjs","names":["Arr"],"sources":["../src/InworldSynthesizer.ts"],"sourcesContent":["/**\n * Sync + chunked-HTTP TTS via Inworld's REST endpoints.\n *\n * - `synthesize` → `POST /tts/v1/voice` (JSON body, single base64 audio in\n * response).\n * - `streamSynthesis` → `POST /tts/v1/voice:stream` (NDJSON response, one\n * JSON object per line, each carrying a base64 audio chunk).\n *\n * Incremental text-in (`streamSynthesisFrom`) lives at the\n * `InworldRealtimeSynthesizer` subpath, which adds the WS path and the\n * `TtsIncrementalText` capability marker.\n */\nimport { Array as Arr, Context, Effect, Layer, Redacted, Schema, Stream } from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/unstable/http\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioBlob, AudioChunk } from \"@effect-uai/core/Audio\"\nimport * as JSONL from \"@effect-uai/core/JSONL\"\nimport {\n type CommonStreamSynthesizeRequest,\n type CommonSynthesizeRequest,\n type CustomPronunciation,\n SpeechSynthesizer,\n type SpeechSynthesizerService,\n} from \"@effect-uai/core/SpeechSynthesizer\"\nimport {\n audioConfigFor,\n authHeader,\n decodeAudioContent,\n defaultFormat,\n httpStatusError,\n transportFailure,\n} from \"./codec.js\"\nimport type { InworldDeliveryMode, InworldTtsModel, InworldVoiceId } from \"./models.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Inworld-typed synthesize request.\n *\n * - `deliveryMode` only honored by `inworld-tts-2` (`STABLE` / `BALANCED` /\n * `CREATIVE` — older models ignore it).\n * - `temperature` valid range is `(0, 2]` per docs.\n * - `applyTextNormalization` defaults to `ON`; pass `\"OFF\"` to feed the\n * model raw text (faster, but punctuation pacing is on you).\n */\nexport type InworldSynthesizeRequest = Omit<CommonSynthesizeRequest, \"model\" | \"voiceId\"> & {\n readonly model: InworldTtsModel\n readonly voiceId: InworldVoiceId\n readonly temperature?: number\n readonly deliveryMode?: InworldDeliveryMode\n readonly applyTextNormalization?: \"ON\" | \"OFF\"\n}\n\nexport type InworldSynthesizerService = {\n readonly synthesize: (r: InworldSynthesizeRequest) => Effect.Effect<AudioBlob, AiError.AiError>\n readonly streamSynthesis: (\n r: InworldSynthesizeRequest,\n ) => Stream.Stream<AudioChunk, AiError.AiError>\n readonly streamSynthesisFrom: SpeechSynthesizerService[\"streamSynthesisFrom\"]\n readonly synthesizeDialogue: SpeechSynthesizerService[\"synthesizeDialogue\"]\n readonly streamSynthesizeDialogue: SpeechSynthesizerService[\"streamSynthesizeDialogue\"]\n}\n\nexport class InworldSynthesizer extends Context.Service<\n InworldSynthesizer,\n InworldSynthesizerService\n>()(\"@betalyra/effect-uai/providers/inworld/InworldSynthesizer\") {}\n\nexport type Config = { readonly apiKey: Redacted.Redacted; readonly baseUrl?: string }\n\n// ---------------------------------------------------------------------------\n// Request body\n// ---------------------------------------------------------------------------\n\n/**\n * Inworld accepts inline phoneme overrides as `/ipa/` tokens directly\n * in the text, no separate field. `CustomPronunciation.pronunciation`\n * is always IPA, so every entry is inlined. Whole-word,\n * case-insensitive replacement.\n */\nconst escapeForRegex = (s: string): string => s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n\nconst applyPronunciations = (\n text: string,\n pronunciations: ReadonlyArray<CustomPronunciation> | undefined,\n): string => {\n if (pronunciations === undefined) return text\n return Arr.reduce(pronunciations, text, (acc, p) =>\n acc.replace(new RegExp(`\\\\b${escapeForRegex(p.phrase)}\\\\b`, \"i\"), `/${p.pronunciation}/`),\n )\n}\n\n/** Exported for reuse by the realtime variant's BOS `create` frame. */\nexport const buildBody = (r: InworldSynthesizeRequest) =>\n Effect.gen(function* () {\n const format = r.outputFormat ?? defaultFormat\n const audioConfig = yield* audioConfigFor(format, r.speed)\n const body = {\n text: applyPronunciations(r.text, r.pronunciations),\n voiceId: r.voiceId,\n modelId: r.model,\n audioConfig,\n ...(r.languageCode !== undefined && { language: r.languageCode }),\n ...(r.deliveryMode !== undefined && { deliveryMode: r.deliveryMode }),\n ...(r.temperature !== undefined && { temperature: r.temperature }),\n ...(r.applyTextNormalization !== undefined && {\n applyTextNormalization: r.applyTextNormalization,\n }),\n }\n return { body, format }\n })\n\n// ---------------------------------------------------------------------------\n// Wire schemas\n// ---------------------------------------------------------------------------\n\nconst SyncResponse = Schema.Struct({ audioContent: Schema.String })\nconst decodeSyncResponse = Schema.decodeUnknownEffect(SyncResponse)\n\nconst StreamLine = Schema.Struct({\n result: Schema.optional(Schema.Struct({ audioContent: Schema.optional(Schema.String) })),\n error: Schema.optional(Schema.Unknown),\n})\n\n// ---------------------------------------------------------------------------\n// HTTP plumbing\n// ---------------------------------------------------------------------------\n\nconst baseUrl = (cfg: Config) => cfg.baseUrl ?? \"https://api.inworld.ai\"\n\nconst buildRequest = (cfg: Config, path: \"/tts/v1/voice\" | \"/tts/v1/voice:stream\", body: unknown) =>\n HttpClientRequest.post(`${baseUrl(cfg)}${path}`).pipe(\n HttpClientRequest.setHeader(\"Authorization\", authHeader(cfg.apiKey)),\n HttpClientRequest.bodyJsonUnsafe(body),\n )\n\n/** Exported for reuse by `InworldRealtimeSynthesizer`. */\nexport const synthesizeImpl = (cfg: Config) => (request: InworldSynthesizeRequest) =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const { body, format } = yield* buildBody(request)\n const httpRequest = buildRequest(cfg, \"/tts/v1/voice\", body)\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(httpStatusError(response.status, text))\n }\n const json = yield* response.json.pipe(Effect.mapError(transportFailure))\n const wire = yield* decodeSyncResponse(json).pipe(\n Effect.mapError(\n (cause) =>\n new AiError.GenerationFailed({\n provider: \"inworld\",\n raw: { message: \"sync TTS response missing `audioContent`\", cause, json },\n }),\n ),\n )\n const bytes = yield* decodeAudioContent(wire.audioContent)\n return { format, bytes } satisfies AudioBlob\n })\n\nconst lineToStream = (line: typeof StreamLine.Type): Stream.Stream<AudioChunk, AiError.AiError> => {\n if (line.error !== undefined) {\n return Stream.fail(new AiError.GenerationFailed({ provider: \"inworld\", raw: line.error }))\n }\n const b64 = line.result?.audioContent\n if (b64 === undefined) return Stream.empty\n return Stream.fromEffect(\n decodeAudioContent(b64).pipe(Effect.map((bytes): AudioChunk => ({ bytes }))),\n )\n}\n\n/** Exported for reuse by `InworldRealtimeSynthesizer`. */\nexport const streamSynthesisImpl = (cfg: Config) => (request: InworldSynthesizeRequest) =>\n Stream.unwrap(\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const { body } = yield* buildBody(request)\n const httpRequest = buildRequest(cfg, \"/tts/v1/voice:stream\", body)\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return Stream.fail(httpStatusError(response.status, text))\n }\n return response.stream.pipe(\n Stream.mapError(transportFailure),\n JSONL.fromBytes,\n JSONL.parse(StreamLine),\n Stream.mapError(\n (cause): AiError.AiError =>\n new AiError.GenerationFailed({\n provider: \"inworld\",\n raw: { message: \"NDJSON parse failed\", cause },\n }),\n ),\n Stream.flatMap(lineToStream),\n )\n }),\n )\n\nconst streamUnsupported = <E, R>(\n _textIn: Stream.Stream<string, E, R>,\n _request: CommonStreamSynthesizeRequest,\n): Stream.Stream<AudioChunk, AiError.AiError | E, R> => {\n const fail: Stream.Stream<AudioChunk, AiError.AiError | E, R> = Stream.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"streamSynthesisFrom\",\n reason:\n \"This Layer is sync-only. Import `@effect-uai/inworld/InworldRealtimeSynthesizer` to use the WS streamSynthesisFrom path.\",\n }),\n )\n return fail\n}\n\n/** Exported for reuse by `InworldRealtimeSynthesizer`. */\nexport const dialogueUnsupportedImpl: SpeechSynthesizerService[\"synthesizeDialogue\"] = () =>\n Effect.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"synthesizeDialogue\",\n reason: \"Inworld TTS has no multi-speaker endpoint.\",\n }),\n )\n\n/** Exported for reuse by `InworldRealtimeSynthesizer`. */\nexport const streamDialogueUnsupportedImpl: SpeechSynthesizerService[\"streamSynthesizeDialogue\"] =\n () =>\n Stream.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"streamSynthesizeDialogue\",\n reason: \"Inworld TTS has no multi-speaker endpoint.\",\n }),\n )\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\nexport const make = (\n cfg: Config,\n): Effect.Effect<InworldSynthesizerService, never, HttpClient.HttpClient> =>\n Effect.map(HttpClient.HttpClient, (client) => ({\n synthesize: (r) =>\n synthesizeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamSynthesis: (r) =>\n streamSynthesisImpl(cfg)(r).pipe(Stream.provideService(HttpClient.HttpClient, client)),\n streamSynthesisFrom: streamUnsupported,\n synthesizeDialogue: dialogueUnsupportedImpl,\n streamSynthesizeDialogue: streamDialogueUnsupportedImpl,\n }))\n\n/**\n * Sync-only Layer. Registers `InworldSynthesizer` + the generic\n * `SpeechSynthesizer`. Does **not** register `TtsIncrementalText` — for\n * incremental text-in use `@effect-uai/inworld/InworldRealtimeSynthesizer`.\n */\nexport const layer = (\n cfg: Config,\n): Layer.Layer<InworldSynthesizer | SpeechSynthesizer, never, HttpClient.HttpClient> =>\n Layer.merge(\n Layer.effect(InworldSynthesizer, make(cfg)),\n Layer.effect(\n SpeechSynthesizer,\n Effect.map(\n make(cfg),\n (s): SpeechSynthesizerService => ({\n synthesize: (req: CommonSynthesizeRequest) =>\n s.synthesize(req as InworldSynthesizeRequest),\n streamSynthesis: (req: CommonSynthesizeRequest) =>\n s.streamSynthesis(req as InworldSynthesizeRequest),\n streamSynthesisFrom: s.streamSynthesisFrom,\n synthesizeDialogue: s.synthesizeDialogue,\n streamSynthesizeDialogue: s.streamSynthesizeDialogue,\n }),\n ),\n ),\n )\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiEA,IAAa,qBAAb,cAAwC,QAAQ,SAG7C,CAAC,4DAA4D,CAAC;;;;;;;AAcjE,MAAM,kBAAkB,MAAsB,EAAE,QAAQ,uBAAuB,OAAO;AAEtF,MAAM,uBACJ,MACA,mBACW;AACX,KAAI,mBAAmB,KAAA,EAAW,QAAO;AACzC,QAAOA,MAAI,OAAO,gBAAgB,OAAO,KAAK,MAC5C,IAAI,QAAQ,IAAI,OAAO,MAAM,eAAe,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE,IAAI,EAAE,cAAc,GAAG,CAC1F;;;AAIH,MAAa,aAAa,MACxB,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,EAAE,gBAAgB;CACjC,MAAM,cAAc,OAAO,eAAe,QAAQ,EAAE,MAAM;AAa1D,QAAO;EAAE,MAAA;GAXP,MAAM,oBAAoB,EAAE,MAAM,EAAE,eAAe;GACnD,SAAS,EAAE;GACX,SAAS,EAAE;GACX;GACA,GAAI,EAAE,iBAAiB,KAAA,KAAa,EAAE,UAAU,EAAE,cAAc;GAChE,GAAI,EAAE,iBAAiB,KAAA,KAAa,EAAE,cAAc,EAAE,cAAc;GACpE,GAAI,EAAE,gBAAgB,KAAA,KAAa,EAAE,aAAa,EAAE,aAAa;GACjE,GAAI,EAAE,2BAA2B,KAAA,KAAa,EAC5C,wBAAwB,EAAE,wBAC3B;GAEU;EAAE;EAAQ;EACvB;AAMJ,MAAM,eAAe,OAAO,OAAO,EAAE,cAAc,OAAO,QAAQ,CAAC;AACnE,MAAM,qBAAqB,OAAO,oBAAoB,aAAa;AAEnE,MAAM,aAAa,OAAO,OAAO;CAC/B,QAAQ,OAAO,SAAS,OAAO,OAAO,EAAE,cAAc,OAAO,SAAS,OAAO,OAAO,EAAE,CAAC,CAAC;CACxF,OAAO,OAAO,SAAS,OAAO,QAAQ;CACvC,CAAC;AAMF,MAAM,WAAW,QAAgB,IAAI,WAAW;AAEhD,MAAM,gBAAgB,KAAa,MAAgD,SACjF,kBAAkB,KAAK,GAAG,QAAQ,IAAI,GAAG,OAAO,CAAC,KAC/C,kBAAkB,UAAU,iBAAiB,WAAW,IAAI,OAAO,CAAC,EACpE,kBAAkB,eAAe,KAAK,CACvC;;AAGH,MAAa,kBAAkB,SAAiB,YAC9C,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,WAAW;CACjC,MAAM,EAAE,MAAM,WAAW,OAAO,UAAU,QAAQ;CAClD,MAAM,cAAc,aAAa,KAAK,iBAAiB,KAAK;CAC5D,MAAM,WAAW,OAAO,OAAO,QAAQ,YAAY,CAAC,KAAK,OAAO,SAAS,iBAAiB,CAAC;AAC3F,KAAI,SAAS,UAAU,KAAK;EAC1B,MAAM,OAAO,OAAO,SAAS,KAAK,KAAK,OAAO,oBAAoB,GAAG,CAAC;AACtE,SAAO,OAAO,OAAO,KAAK,gBAAgB,SAAS,QAAQ,KAAK,CAAC;;CAEnE,MAAM,OAAO,OAAO,SAAS,KAAK,KAAK,OAAO,SAAS,iBAAiB,CAAC;AAWzE,QAAO;EAAE;EAAQ,OAAA,OADI,oBAAmB,OATpB,mBAAmB,KAAK,CAAC,KAC3C,OAAO,UACJ,UACC,IAAI,QAAQ,iBAAiB;GAC3B,UAAU;GACV,KAAK;IAAE,SAAS;IAA4C;IAAO;IAAM;GAC1E,CAAC,CACL,CACF,EAC4C,aAAa;EAClC;EACxB;AAEJ,MAAM,gBAAgB,SAA6E;AACjG,KAAI,KAAK,UAAU,KAAA,EACjB,QAAO,OAAO,KAAK,IAAI,QAAQ,iBAAiB;EAAE,UAAU;EAAW,KAAK,KAAK;EAAO,CAAC,CAAC;CAE5F,MAAM,MAAM,KAAK,QAAQ;AACzB,KAAI,QAAQ,KAAA,EAAW,QAAO,OAAO;AACrC,QAAO,OAAO,WACZ,mBAAmB,IAAI,CAAC,KAAK,OAAO,KAAK,WAAuB,EAAE,OAAO,EAAE,CAAC,CAC7E;;;AAIH,MAAa,uBAAuB,SAAiB,YACnD,OAAO,OACL,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,WAAW;CACjC,MAAM,EAAE,SAAS,OAAO,UAAU,QAAQ;CAC1C,MAAM,cAAc,aAAa,KAAK,wBAAwB,KAAK;CACnE,MAAM,WAAW,OAAO,OAAO,QAAQ,YAAY,CAAC,KAAK,OAAO,SAAS,iBAAiB,CAAC;AAC3F,KAAI,SAAS,UAAU,KAAK;EAC1B,MAAM,OAAO,OAAO,SAAS,KAAK,KAAK,OAAO,oBAAoB,GAAG,CAAC;AACtE,SAAO,OAAO,KAAK,gBAAgB,SAAS,QAAQ,KAAK,CAAC;;AAE5D,QAAO,SAAS,OAAO,KACrB,OAAO,SAAS,iBAAiB,EACjC,MAAM,WACN,MAAM,MAAM,WAAW,EACvB,OAAO,UACJ,UACC,IAAI,QAAQ,iBAAiB;EAC3B,UAAU;EACV,KAAK;GAAE,SAAS;GAAuB;GAAO;EAC/C,CAAC,CACL,EACD,OAAO,QAAQ,aAAa,CAC7B;EACD,CACH;AAEH,MAAM,qBACJ,SACA,aACsD;AAStD,QARgE,OAAO,KACrE,IAAI,QAAQ,YAAY;EACtB,UAAU;EACV,YAAY;EACZ,QACE;EACH,CAAC,CAEO;;;AAIb,MAAa,gCACX,OAAO,KACL,IAAI,QAAQ,YAAY;CACtB,UAAU;CACV,YAAY;CACZ,QAAQ;CACT,CAAC,CACH;;AAGH,MAAa,sCAET,OAAO,KACL,IAAI,QAAQ,YAAY;CACtB,UAAU;CACV,YAAY;CACZ,QAAQ;CACT,CAAC,CACH;AAML,MAAa,QACX,QAEA,OAAO,IAAI,WAAW,aAAa,YAAY;CAC7C,aAAa,MACX,eAAe,IAAI,CAAC,EAAE,CAAC,KAAK,OAAO,eAAe,WAAW,YAAY,OAAO,CAAC;CACnF,kBAAkB,MAChB,oBAAoB,IAAI,CAAC,EAAE,CAAC,KAAK,OAAO,eAAe,WAAW,YAAY,OAAO,CAAC;CACxF,qBAAqB;CACrB,oBAAoB;CACpB,0BAA0B;CAC3B,EAAE;;;;;;AAOL,MAAa,SACX,QAEA,MAAM,MACJ,MAAM,OAAO,oBAAoB,KAAK,IAAI,CAAC,EAC3C,MAAM,OACJ,mBACA,OAAO,IACL,KAAK,IAAI,GACR,OAAiC;CAChC,aAAa,QACX,EAAE,WAAW,IAAgC;CAC/C,kBAAkB,QAChB,EAAE,gBAAgB,IAAgC;CACpD,qBAAqB,EAAE;CACvB,oBAAoB,EAAE;CACtB,0BAA0B,EAAE;CAC7B,EACF,CACF,CACF"}
1
+ {"version":3,"file":"InworldSynthesizer.mjs","names":["Arr"],"sources":["../src/InworldSynthesizer.ts"],"sourcesContent":["/**\n * Sync + chunked-HTTP TTS via Inworld's REST endpoints.\n *\n * - `synthesize` → `POST /tts/v1/voice` (JSON body, single base64 audio in\n * response).\n * - `streamSynthesis` → `POST /tts/v1/voice:stream` (NDJSON response, one\n * JSON object per line, each carrying a base64 audio chunk).\n *\n * Incremental text-in (`streamSynthesisFrom`) lives at the\n * `InworldRealtimeSynthesizer` subpath, which adds the WS path and the\n * `TtsIncrementalText` capability marker.\n */\nimport { Array as Arr, Context, Effect, Layer, Redacted, Schema, Stream } from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/unstable/http\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioBlob, AudioChunk } from \"@effect-uai/core/Audio\"\nimport * as JSONL from \"@effect-uai/core/JSONL\"\nimport {\n type CommonStreamSynthesizeRequest,\n type CommonSynthesizeRequest,\n type CustomPronunciation,\n SpeechSynthesizer,\n type SpeechSynthesizerService,\n} from \"@effect-uai/core/SpeechSynthesizer\"\nimport {\n audioConfigFor,\n authHeader,\n decodeAudioContent,\n defaultFormat,\n httpStatusError,\n transportFailure,\n} from \"./codec.js\"\nimport type { InworldDeliveryMode, InworldTtsModel, InworldVoiceId } from \"./models.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Inworld-typed synthesize request.\n *\n * - `deliveryMode` only honored by `inworld-tts-2` (`STABLE` / `BALANCED` /\n * `CREATIVE` — older models ignore it).\n * - `temperature` valid range is `(0, 2]` per docs.\n * - `applyTextNormalization` defaults to `ON`; pass `\"OFF\"` to feed the\n * model raw text (faster, but punctuation pacing is on you).\n */\nexport type InworldSynthesizeRequest = Omit<CommonSynthesizeRequest, \"model\" | \"voiceId\"> & {\n readonly model: InworldTtsModel\n readonly voiceId: InworldVoiceId\n readonly temperature?: number\n readonly deliveryMode?: InworldDeliveryMode\n readonly applyTextNormalization?: \"ON\" | \"OFF\"\n}\n\nexport type InworldSynthesizerService = {\n readonly synthesize: (r: InworldSynthesizeRequest) => Effect.Effect<AudioBlob, AiError.AiError>\n readonly streamSynthesis: (\n r: InworldSynthesizeRequest,\n ) => Stream.Stream<AudioChunk, AiError.AiError>\n readonly streamSynthesisFrom: SpeechSynthesizerService[\"streamSynthesisFrom\"]\n readonly synthesizeDialogue: SpeechSynthesizerService[\"synthesizeDialogue\"]\n readonly streamSynthesizeDialogue: SpeechSynthesizerService[\"streamSynthesizeDialogue\"]\n}\n\nexport class InworldSynthesizer extends Context.Service<\n InworldSynthesizer,\n InworldSynthesizerService\n>()(\"@betalyra/effect-uai/providers/inworld/InworldSynthesizer\") {}\n\nexport type Config = { readonly apiKey: Redacted.Redacted; readonly baseUrl?: string }\n\n// ---------------------------------------------------------------------------\n// Request body\n// ---------------------------------------------------------------------------\n\n/**\n * Inworld accepts inline phoneme overrides as `/ipa/` tokens directly\n * in the text, no separate field. `CustomPronunciation.pronunciation`\n * is always IPA, so every entry is inlined. Whole-word,\n * case-insensitive replacement.\n */\nconst escapeForRegex = (s: string): string => s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n\nconst applyPronunciations = (\n text: string,\n pronunciations: ReadonlyArray<CustomPronunciation> | undefined,\n): string => {\n if (pronunciations === undefined) return text\n return Arr.reduce(pronunciations, text, (acc, p) =>\n acc.replace(new RegExp(`\\\\b${escapeForRegex(p.phrase)}\\\\b`, \"i\"), `/${p.pronunciation}/`),\n )\n}\n\n/** Exported for reuse by the realtime variant's BOS `create` frame. */\nexport const buildBody = (r: InworldSynthesizeRequest) =>\n Effect.gen(function* () {\n const format = r.outputFormat ?? defaultFormat\n const audioConfig = yield* audioConfigFor(format, r.speed)\n const body = {\n text: applyPronunciations(r.text, r.pronunciations),\n voiceId: r.voiceId,\n modelId: r.model,\n audioConfig,\n ...(r.languageCode !== undefined && { language: r.languageCode }),\n ...(r.deliveryMode !== undefined && { deliveryMode: r.deliveryMode }),\n ...(r.temperature !== undefined && { temperature: r.temperature }),\n ...(r.applyTextNormalization !== undefined && {\n applyTextNormalization: r.applyTextNormalization,\n }),\n }\n return { body, format }\n })\n\n// ---------------------------------------------------------------------------\n// Wire schemas\n// ---------------------------------------------------------------------------\n\nconst SyncResponse = Schema.Struct({ audioContent: Schema.String })\nconst decodeSyncResponse = Schema.decodeUnknownEffect(SyncResponse)\n\nconst StreamLine = Schema.Struct({\n result: Schema.optional(Schema.Struct({ audioContent: Schema.optional(Schema.String) })),\n error: Schema.optional(Schema.Unknown),\n})\n\n// ---------------------------------------------------------------------------\n// HTTP plumbing\n// ---------------------------------------------------------------------------\n\nconst baseUrl = (cfg: Config) => cfg.baseUrl ?? \"https://api.inworld.ai\"\n\nconst buildRequest = (cfg: Config, path: \"/tts/v1/voice\" | \"/tts/v1/voice:stream\", body: unknown) =>\n HttpClientRequest.post(`${baseUrl(cfg)}${path}`).pipe(\n HttpClientRequest.setHeader(\"Authorization\", authHeader(cfg.apiKey)),\n HttpClientRequest.bodyJsonUnsafe(body),\n )\n\n/** Exported for reuse by `InworldRealtimeSynthesizer`. */\nexport const synthesizeImpl = (cfg: Config) => (request: InworldSynthesizeRequest) =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const { body, format } = yield* buildBody(request)\n const httpRequest = buildRequest(cfg, \"/tts/v1/voice\", body)\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(httpStatusError(response.status, text))\n }\n const json = yield* response.json.pipe(Effect.mapError(transportFailure))\n const wire = yield* decodeSyncResponse(json).pipe(\n Effect.mapError(\n (cause) =>\n new AiError.GenerationFailed({\n provider: \"inworld\",\n raw: { message: \"sync TTS response missing `audioContent`\", cause, json },\n }),\n ),\n )\n const bytes = yield* decodeAudioContent(wire.audioContent)\n return { format, bytes } satisfies AudioBlob\n })\n\nconst lineToStream = (line: typeof StreamLine.Type): Stream.Stream<AudioChunk, AiError.AiError> => {\n if (line.error !== undefined) {\n return Stream.fail(new AiError.GenerationFailed({ provider: \"inworld\", raw: line.error }))\n }\n const b64 = line.result?.audioContent\n if (b64 === undefined) return Stream.empty\n return Stream.fromEffect(\n decodeAudioContent(b64).pipe(Effect.map((bytes): AudioChunk => ({ bytes }))),\n )\n}\n\n/** Exported for reuse by `InworldRealtimeSynthesizer`. */\nexport const streamSynthesisImpl = (cfg: Config) => (request: InworldSynthesizeRequest) =>\n Stream.unwrap(\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const { body } = yield* buildBody(request)\n const httpRequest = buildRequest(cfg, \"/tts/v1/voice:stream\", body)\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return Stream.fail(httpStatusError(response.status, text))\n }\n return response.stream.pipe(\n Stream.mapError(transportFailure),\n JSONL.fromBytes,\n JSONL.parse(StreamLine),\n Stream.mapError(\n (cause): AiError.AiError =>\n new AiError.GenerationFailed({\n provider: \"inworld\",\n raw: { message: \"NDJSON parse failed\", cause },\n }),\n ),\n Stream.flatMap(lineToStream),\n )\n }),\n )\n\nconst streamUnsupported = <E, R>(\n _textIn: Stream.Stream<string, E, R>,\n _request: CommonStreamSynthesizeRequest,\n): Stream.Stream<AudioChunk, AiError.AiError | E, R> => {\n const fail: Stream.Stream<AudioChunk, AiError.AiError | E, R> = Stream.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"streamSynthesisFrom\",\n reason:\n \"This Layer is sync-only. Import `@effect-uai/inworld/InworldRealtimeSynthesizer` to use the WS streamSynthesisFrom path.\",\n }),\n )\n return fail\n}\n\n/** Exported for reuse by `InworldRealtimeSynthesizer`. */\nexport const dialogueUnsupportedImpl: SpeechSynthesizerService[\"synthesizeDialogue\"] = () =>\n Effect.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"synthesizeDialogue\",\n reason: \"Inworld TTS has no multi-speaker endpoint.\",\n }),\n )\n\n/** Exported for reuse by `InworldRealtimeSynthesizer`. */\nexport const streamDialogueUnsupportedImpl: SpeechSynthesizerService[\"streamSynthesizeDialogue\"] =\n () =>\n Stream.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"streamSynthesizeDialogue\",\n reason: \"Inworld TTS has no multi-speaker endpoint.\",\n }),\n )\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\nexport const make = (\n cfg: Config,\n): Effect.Effect<InworldSynthesizerService, never, HttpClient.HttpClient> =>\n Effect.map(HttpClient.HttpClient, (client) => ({\n synthesize: (r) =>\n synthesizeImpl(cfg)(r).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamSynthesis: (r) =>\n streamSynthesisImpl(cfg)(r).pipe(Stream.provideService(HttpClient.HttpClient, client)),\n streamSynthesisFrom: streamUnsupported,\n synthesizeDialogue: dialogueUnsupportedImpl,\n streamSynthesizeDialogue: streamDialogueUnsupportedImpl,\n }))\n\n/**\n * Sync-only Layer. Registers `InworldSynthesizer` + the generic\n * `SpeechSynthesizer`. Does **not** register `TtsIncrementalText` — for\n * incremental text-in use `@effect-uai/inworld/InworldRealtimeSynthesizer`.\n */\nexport const layer = (\n cfg: Config,\n): Layer.Layer<InworldSynthesizer | SpeechSynthesizer, never, HttpClient.HttpClient> =>\n Layer.merge(\n Layer.effect(InworldSynthesizer, make(cfg)),\n Layer.effect(\n SpeechSynthesizer,\n Effect.map(make(cfg), (s): SpeechSynthesizerService => ({\n synthesize: (req: CommonSynthesizeRequest) => s.synthesize(req as InworldSynthesizeRequest),\n streamSynthesis: (req: CommonSynthesizeRequest) =>\n s.streamSynthesis(req as InworldSynthesizeRequest),\n streamSynthesisFrom: s.streamSynthesisFrom,\n synthesizeDialogue: s.synthesizeDialogue,\n streamSynthesizeDialogue: s.streamSynthesizeDialogue,\n })),\n ),\n )\n"],"mappings":"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"}
@@ -1,11 +1,9 @@
1
- import { r as InworldSttModel } from "./models-CPLZDcgt.mjs";
1
+ import { r as InworldSttModel } from "./models-DySX9PVy.mjs";
2
2
  import { Context, Effect, Layer, Redacted, Schema } from "effect";
3
3
  import { HttpClient } from "effect/unstable/http";
4
4
  import * as AiError from "@effect-uai/core/AiError";
5
5
  import { CommonTranscribeRequest, Transcriber, TranscriberService } from "@effect-uai/core/Transcriber";
6
6
  import { TranscriptResult, WordTimestamp } from "@effect-uai/core/Transcript";
7
-
8
- //#region src/InworldTranscriber.d.ts
9
7
  declare namespace InworldTranscriber_d_exports {
10
8
  export { Config, InworldTranscribeRequest, InworldTranscriber, InworldTranscriberService, layer, make, transcribeImpl };
11
9
  }
@@ -32,9 +30,9 @@ type Config = {
32
30
  };
33
31
  /** Exported for reuse by `InworldRealtimeTranscriber`. */
34
32
  declare const transcribeImpl: (cfg: Config) => (request: InworldTranscribeRequest) => Effect.Effect<{
35
- raw: Schema.Json;
36
- words?: WordTimestamp[];
37
33
  text: string;
34
+ words?: WordTimestamp[];
35
+ raw: Schema.Json;
38
36
  }, AiError.AiError, HttpClient.HttpClient>;
39
37
  declare const make: (cfg: Config) => Effect.Effect<InworldTranscriberService, never, HttpClient.HttpClient>;
40
38
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"InworldTranscriber.d.mts","names":[],"sources":["../src/InworldTranscriber.ts"],"mappings":";;;;;;;;;;;;;AAkCA;;;KAAY,wBAAA,GAA2B,IAAA,CAAK,uBAAA;EAAA,SACjC,KAAA,EAAO,eAAA;EAAA,SACP,aAAA;EAAA,SACA,eAAA;EAAA,SACA,gBAAA;AAAA;AAAA,KAGC,yBAAA;EAAA,SACD,UAAA,GACP,CAAA,EAAG,wBAAA,KACA,MAAA,CAAO,MAAA,CAAO,gBAAA,EAAkB,OAAA,CAAQ,OAAA;EAAA,SACpC,uBAAA,EAAyB,kBAAA;AAAA;AAAA,cACnC,uBAAA;cAEY,kBAAA,SAA2B,uBAAA;AAAA,KAK5B,MAAA;EAAA,SAAoB,MAAA,EAAQ,QAAA,CAAS,QAAA;EAAA,SAAmB,OAAA;AAAA;;cAwFvD,cAAA,GAAkB,GAAA,EAAK,MAAA,MAAY,OAAA,EAAS,wBAAA,KAAwB,MAAA,CAAA,MAAA;;;;;cAwDpE,IAAA,GACX,GAAA,EAAK,MAAA,KACJ,MAAA,CAAO,MAAA,CAAO,yBAAA,SAAkC,UAAA,CAAW,UAAA;;;;;;cAYjD,KAAA,GACX,GAAA,EAAK,MAAA,KACJ,KAAA,CAAM,KAAA,CAAM,kBAAA,GAAqB,WAAA,SAAoB,UAAA,CAAW,UAAA"}
1
+ {"version":3,"file":"InworldTranscriber.d.mts","names":[],"sources":["../src/InworldTranscriber.ts"],"mappings":";;;;;;;;;;;;;;KAkCY,2BAA2B,KAAK;WACjC,OAAO;WACP;WACA;WACA;;KAGC;WACD,aACP,GAAG,6BACA,OAAO,OAAO,kBAAkB,QAAQ;WACpC,yBAAyB;;;cAGvB,2BAA2B;KAK5B;WAAoB,QAAQ,SAAS;WAAmB;;;cAwFvD,iBAAc,KAAS,YAAM,SAAe,6BAAwB,OAAA;;;;GA+B7E,QAAA,SAAA,WAAA;cAyBS,OAAI,KACV,WACJ,OAAO,OAAO,kCAAkC,WAAW;;;;;;cAYjD,QAAK,KACX,WACJ,MAAM,MAAM,qBAAqB,oBAAoB,WAAW"}
@@ -1,4 +1,4 @@
1
- import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
2
  import { authHeader, httpStatusError, transportFailure } from "./codec.mjs";
3
3
  import { Context, Effect, Encoding, Layer, Match, Schema, Stream } from "effect";
4
4
  import { HttpClient, HttpClientRequest } from "effect/unstable/http";
@@ -1 +1 @@
1
- {"version":3,"file":"InworldTranscriber.mjs","names":[],"sources":["../src/InworldTranscriber.ts"],"sourcesContent":["/**\n * Sync transcription via Inworld's REST endpoint.\n *\n * - `transcribe` → `POST /stt/v1/transcribe` with audio as base64 in\n * `audioData.content`. URL input is not accepted by Inworld — the\n * adapter rejects `_tag: \"url\"` audio sources with `InvalidRequest`.\n *\n * Streaming transcription lives at the `InworldRealtimeTranscriber`\n * subpath, which adds the WS path and the `SttStreaming` capability marker.\n */\nimport { Context, Effect, Encoding, Layer, Match, Redacted, Schema, Stream } from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/unstable/http\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioSource } from \"@effect-uai/core/Audio\"\nimport * as Capabilities from \"@effect-uai/core/Capabilities\"\nimport type { TranscriptEvent, TranscriptResult, WordTimestamp } from \"@effect-uai/core/Transcript\"\nimport {\n type CommonStreamTranscribeRequest,\n type CommonTranscribeRequest,\n Transcriber,\n type TranscriberService,\n} from \"@effect-uai/core/Transcriber\"\nimport { authHeader, httpStatusError, transportFailure } from \"./codec.js\"\nimport type { InworldSttModel } from \"./models.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Inworld-typed transcribe request. `numberOfChannels` defaults to 1.\n * `audioEncoding` is autodetected from the audio MIME by default; pass\n * an explicit value to override (useful for raw PCM bytes).\n */\nexport type InworldTranscribeRequest = Omit<CommonTranscribeRequest, \"model\"> & {\n readonly model: InworldSttModel\n readonly audioEncoding?: \"AUTO_DETECT\" | \"LINEAR16\" | \"MP3\" | \"OGG_OPUS\" | \"FLAC\"\n readonly sampleRateHertz?: number\n readonly numberOfChannels?: number\n}\n\nexport type InworldTranscriberService = {\n readonly transcribe: (\n r: InworldTranscribeRequest,\n ) => Effect.Effect<TranscriptResult, AiError.AiError>\n readonly streamTranscriptionFrom: TranscriberService[\"streamTranscriptionFrom\"]\n}\n\nexport class InworldTranscriber extends Context.Service<\n InworldTranscriber,\n InworldTranscriberService\n>()(\"@betalyra/effect-uai/providers/inworld/InworldTranscriber\") {}\n\nexport type Config = { readonly apiKey: Redacted.Redacted; readonly baseUrl?: string }\n\n// ---------------------------------------------------------------------------\n// AudioSource → base64. Inworld's sync endpoint takes inline base64 only.\n// ---------------------------------------------------------------------------\n\nconst urlNotSupported: AiError.AiError = new AiError.InvalidRequest({\n provider: \"inworld\",\n param: \"audio\",\n raw: 'Inworld accepts only inline base64. Fetch the URL yourself and pass `{ _tag: \"bytes\", bytes, mimeType }`.',\n})\n\nconst audioToBase64: (audio: AudioSource) => Effect.Effect<string, AiError.AiError> =\n Match.type<AudioSource>().pipe(\n Match.tag(\"bytes\", (a) => Effect.succeed(Encoding.encodeBase64(a.bytes))),\n Match.tag(\"base64\", (a) => Effect.succeed(a.base64)),\n Match.tag(\"url\", () => Effect.fail(urlNotSupported)),\n Match.exhaustive,\n )\n\n// ---------------------------------------------------------------------------\n// Request body\n// ---------------------------------------------------------------------------\n\nconst buildBody = (request: InworldTranscribeRequest) =>\n Effect.gen(function* () {\n const content = yield* audioToBase64(request.audio)\n // Inworld's `prompts` is a vocab-biasing term list — maps from\n // `biasingTerms`. There's no free-form prompt field, so `prompt` warns.\n yield* Capabilities.warnDroppedWhen(request.prompt, {\n provider: \"inworld\",\n capability: \"prompt\",\n field: \"prompt\",\n reason: \"Inworld STT has no free-form prompt field; bias via `biasingTerms`.\",\n })\n return {\n transcribeConfig: {\n modelId: request.model,\n audioEncoding: request.audioEncoding ?? \"AUTO_DETECT\",\n ...(request.sampleRateHertz !== undefined && {\n sampleRateHertz: request.sampleRateHertz,\n }),\n numberOfChannels: request.numberOfChannels ?? 1,\n ...(request.language !== undefined && { language: request.language }),\n ...(request.biasingTerms !== undefined && { prompts: request.biasingTerms }),\n ...(request.wordTimestamps === true && { includeWordTimestamps: true }),\n },\n audioData: { content },\n }\n })\n\n// ---------------------------------------------------------------------------\n// Wire schema\n// ---------------------------------------------------------------------------\n\nconst WireWord = Schema.Struct({\n word: Schema.String,\n startTimeMs: Schema.optional(Schema.Number),\n endTimeMs: Schema.optional(Schema.Number),\n confidence: Schema.optional(Schema.Number),\n})\n\nconst WireResponse = Schema.Struct({\n transcription: Schema.Struct({\n transcript: Schema.String,\n isFinal: Schema.optional(Schema.Boolean),\n wordTimestamps: Schema.optional(Schema.NullOr(Schema.Array(WireWord))),\n }),\n})\nconst decodeResponse = Schema.decodeUnknownEffect(WireResponse)\n\nconst wireWordToCommon = (w: typeof WireWord.Type): WordTimestamp | undefined =>\n w.startTimeMs === undefined || w.endTimeMs === undefined\n ? undefined\n : {\n text: w.word,\n startSeconds: w.startTimeMs / 1000,\n endSeconds: w.endTimeMs / 1000,\n ...(w.confidence !== undefined && { confidence: w.confidence }),\n }\n\n// ---------------------------------------------------------------------------\n// HTTP plumbing\n// ---------------------------------------------------------------------------\n\nconst baseUrl = (cfg: Config) => cfg.baseUrl ?? \"https://api.inworld.ai\"\n\n/** Exported for reuse by `InworldRealtimeTranscriber`. */\nexport const transcribeImpl = (cfg: Config) => (request: InworldTranscribeRequest) =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const body = yield* buildBody(request)\n const httpRequest = HttpClientRequest.post(`${baseUrl(cfg)}/stt/v1/transcribe`).pipe(\n HttpClientRequest.setHeader(\"Authorization\", authHeader(cfg.apiKey)),\n HttpClientRequest.bodyJsonUnsafe(body),\n )\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(httpStatusError(response.status, text))\n }\n const json = yield* response.json.pipe(Effect.mapError(transportFailure))\n const wire = yield* decodeResponse(json).pipe(\n Effect.mapError(\n (cause) =>\n new AiError.GenerationFailed({\n provider: \"inworld\",\n raw: { message: \"STT response missing `transcription.transcript`\", cause, json },\n }),\n ),\n )\n const words = wire.transcription.wordTimestamps\n ?.map(wireWordToCommon)\n .filter((w): w is WordTimestamp => w !== undefined)\n return {\n text: wire.transcription.transcript,\n ...(words !== undefined && words.length > 0 && { words }),\n raw: json,\n } satisfies TranscriptResult\n })\n\n// ---------------------------------------------------------------------------\n// streamTranscriptionFrom Unsupported on this Layer\n// ---------------------------------------------------------------------------\n\nconst streamUnsupported = <E, R>(\n _audioIn: Stream.Stream<Uint8Array, E, R>,\n _request: CommonStreamTranscribeRequest,\n): Stream.Stream<TranscriptEvent, AiError.AiError | E, R> => {\n const fail: Stream.Stream<TranscriptEvent, AiError.AiError | E, R> = Stream.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"streamTranscriptionFrom\",\n reason:\n \"This Layer is sync-only. Import `@effect-uai/inworld/InworldRealtimeTranscriber` to use the WS streamTranscriptionFrom path.\",\n }),\n )\n return fail\n}\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\nexport const make = (\n cfg: Config,\n): Effect.Effect<InworldTranscriberService, never, HttpClient.HttpClient> =>\n Effect.map(HttpClient.HttpClient, (client) => ({\n transcribe: (request) =>\n transcribeImpl(cfg)(request).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamTranscriptionFrom: streamUnsupported,\n }))\n\n/**\n * Sync-only Layer. Registers `InworldTranscriber` + the generic\n * `Transcriber`. Does **not** register `SttStreaming` — for live\n * transcription use `@effect-uai/inworld/InworldRealtimeTranscriber`.\n */\nexport const layer = (\n cfg: Config,\n): Layer.Layer<InworldTranscriber | Transcriber, never, HttpClient.HttpClient> =>\n Layer.merge(\n Layer.effect(InworldTranscriber, make(cfg)),\n Layer.effect(\n Transcriber,\n Effect.map(\n make(cfg),\n (s): TranscriberService => ({\n transcribe: (req: CommonTranscribeRequest) =>\n s.transcribe(req as InworldTranscribeRequest),\n streamTranscriptionFrom: s.streamTranscriptionFrom,\n }),\n ),\n ),\n )\n"],"mappings":"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"}
1
+ {"version":3,"file":"InworldTranscriber.mjs","names":[],"sources":["../src/InworldTranscriber.ts"],"sourcesContent":["/**\n * Sync transcription via Inworld's REST endpoint.\n *\n * - `transcribe` → `POST /stt/v1/transcribe` with audio as base64 in\n * `audioData.content`. URL input is not accepted by Inworld — the\n * adapter rejects `_tag: \"url\"` audio sources with `InvalidRequest`.\n *\n * Streaming transcription lives at the `InworldRealtimeTranscriber`\n * subpath, which adds the WS path and the `SttStreaming` capability marker.\n */\nimport { Context, Effect, Encoding, Layer, Match, Redacted, Schema, Stream } from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/unstable/http\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioSource } from \"@effect-uai/core/Audio\"\nimport * as Capabilities from \"@effect-uai/core/Capabilities\"\nimport type { TranscriptEvent, TranscriptResult, WordTimestamp } from \"@effect-uai/core/Transcript\"\nimport {\n type CommonStreamTranscribeRequest,\n type CommonTranscribeRequest,\n Transcriber,\n type TranscriberService,\n} from \"@effect-uai/core/Transcriber\"\nimport { authHeader, httpStatusError, transportFailure } from \"./codec.js\"\nimport type { InworldSttModel } from \"./models.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Inworld-typed transcribe request. `numberOfChannels` defaults to 1.\n * `audioEncoding` is autodetected from the audio MIME by default; pass\n * an explicit value to override (useful for raw PCM bytes).\n */\nexport type InworldTranscribeRequest = Omit<CommonTranscribeRequest, \"model\"> & {\n readonly model: InworldSttModel\n readonly audioEncoding?: \"AUTO_DETECT\" | \"LINEAR16\" | \"MP3\" | \"OGG_OPUS\" | \"FLAC\"\n readonly sampleRateHertz?: number\n readonly numberOfChannels?: number\n}\n\nexport type InworldTranscriberService = {\n readonly transcribe: (\n r: InworldTranscribeRequest,\n ) => Effect.Effect<TranscriptResult, AiError.AiError>\n readonly streamTranscriptionFrom: TranscriberService[\"streamTranscriptionFrom\"]\n}\n\nexport class InworldTranscriber extends Context.Service<\n InworldTranscriber,\n InworldTranscriberService\n>()(\"@betalyra/effect-uai/providers/inworld/InworldTranscriber\") {}\n\nexport type Config = { readonly apiKey: Redacted.Redacted; readonly baseUrl?: string }\n\n// ---------------------------------------------------------------------------\n// AudioSource → base64. Inworld's sync endpoint takes inline base64 only.\n// ---------------------------------------------------------------------------\n\nconst urlNotSupported: AiError.AiError = new AiError.InvalidRequest({\n provider: \"inworld\",\n param: \"audio\",\n raw: 'Inworld accepts only inline base64. Fetch the URL yourself and pass `{ _tag: \"bytes\", bytes, mimeType }`.',\n})\n\nconst audioToBase64: (audio: AudioSource) => Effect.Effect<string, AiError.AiError> =\n Match.type<AudioSource>().pipe(\n Match.tag(\"bytes\", (a) => Effect.succeed(Encoding.encodeBase64(a.bytes))),\n Match.tag(\"base64\", (a) => Effect.succeed(a.base64)),\n Match.tag(\"url\", () => Effect.fail(urlNotSupported)),\n Match.exhaustive,\n )\n\n// ---------------------------------------------------------------------------\n// Request body\n// ---------------------------------------------------------------------------\n\nconst buildBody = (request: InworldTranscribeRequest) =>\n Effect.gen(function* () {\n const content = yield* audioToBase64(request.audio)\n // Inworld's `prompts` is a vocab-biasing term list — maps from\n // `biasingTerms`. There's no free-form prompt field, so `prompt` warns.\n yield* Capabilities.warnDroppedWhen(request.prompt, {\n provider: \"inworld\",\n capability: \"prompt\",\n field: \"prompt\",\n reason: \"Inworld STT has no free-form prompt field; bias via `biasingTerms`.\",\n })\n return {\n transcribeConfig: {\n modelId: request.model,\n audioEncoding: request.audioEncoding ?? \"AUTO_DETECT\",\n ...(request.sampleRateHertz !== undefined && {\n sampleRateHertz: request.sampleRateHertz,\n }),\n numberOfChannels: request.numberOfChannels ?? 1,\n ...(request.language !== undefined && { language: request.language }),\n ...(request.biasingTerms !== undefined && { prompts: request.biasingTerms }),\n ...(request.wordTimestamps === true && { includeWordTimestamps: true }),\n },\n audioData: { content },\n }\n })\n\n// ---------------------------------------------------------------------------\n// Wire schema\n// ---------------------------------------------------------------------------\n\nconst WireWord = Schema.Struct({\n word: Schema.String,\n startTimeMs: Schema.optional(Schema.Number),\n endTimeMs: Schema.optional(Schema.Number),\n confidence: Schema.optional(Schema.Number),\n})\n\nconst WireResponse = Schema.Struct({\n transcription: Schema.Struct({\n transcript: Schema.String,\n isFinal: Schema.optional(Schema.Boolean),\n wordTimestamps: Schema.optional(Schema.NullOr(Schema.Array(WireWord))),\n }),\n})\nconst decodeResponse = Schema.decodeUnknownEffect(WireResponse)\n\nconst wireWordToCommon = (w: typeof WireWord.Type): WordTimestamp | undefined =>\n w.startTimeMs === undefined || w.endTimeMs === undefined\n ? undefined\n : {\n text: w.word,\n startSeconds: w.startTimeMs / 1000,\n endSeconds: w.endTimeMs / 1000,\n ...(w.confidence !== undefined && { confidence: w.confidence }),\n }\n\n// ---------------------------------------------------------------------------\n// HTTP plumbing\n// ---------------------------------------------------------------------------\n\nconst baseUrl = (cfg: Config) => cfg.baseUrl ?? \"https://api.inworld.ai\"\n\n/** Exported for reuse by `InworldRealtimeTranscriber`. */\nexport const transcribeImpl = (cfg: Config) => (request: InworldTranscribeRequest) =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient\n const body = yield* buildBody(request)\n const httpRequest = HttpClientRequest.post(`${baseUrl(cfg)}/stt/v1/transcribe`).pipe(\n HttpClientRequest.setHeader(\"Authorization\", authHeader(cfg.apiKey)),\n HttpClientRequest.bodyJsonUnsafe(body),\n )\n const response = yield* client.execute(httpRequest).pipe(Effect.mapError(transportFailure))\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return yield* Effect.fail(httpStatusError(response.status, text))\n }\n const json = yield* response.json.pipe(Effect.mapError(transportFailure))\n const wire = yield* decodeResponse(json).pipe(\n Effect.mapError(\n (cause) =>\n new AiError.GenerationFailed({\n provider: \"inworld\",\n raw: { message: \"STT response missing `transcription.transcript`\", cause, json },\n }),\n ),\n )\n const words = wire.transcription.wordTimestamps\n ?.map(wireWordToCommon)\n .filter((w): w is WordTimestamp => w !== undefined)\n return {\n text: wire.transcription.transcript,\n ...(words !== undefined && words.length > 0 && { words }),\n raw: json,\n } satisfies TranscriptResult\n })\n\n// ---------------------------------------------------------------------------\n// streamTranscriptionFrom Unsupported on this Layer\n// ---------------------------------------------------------------------------\n\nconst streamUnsupported = <E, R>(\n _audioIn: Stream.Stream<Uint8Array, E, R>,\n _request: CommonStreamTranscribeRequest,\n): Stream.Stream<TranscriptEvent, AiError.AiError | E, R> => {\n const fail: Stream.Stream<TranscriptEvent, AiError.AiError | E, R> = Stream.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"streamTranscriptionFrom\",\n reason:\n \"This Layer is sync-only. Import `@effect-uai/inworld/InworldRealtimeTranscriber` to use the WS streamTranscriptionFrom path.\",\n }),\n )\n return fail\n}\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\nexport const make = (\n cfg: Config,\n): Effect.Effect<InworldTranscriberService, never, HttpClient.HttpClient> =>\n Effect.map(HttpClient.HttpClient, (client) => ({\n transcribe: (request) =>\n transcribeImpl(cfg)(request).pipe(Effect.provideService(HttpClient.HttpClient, client)),\n streamTranscriptionFrom: streamUnsupported,\n }))\n\n/**\n * Sync-only Layer. Registers `InworldTranscriber` + the generic\n * `Transcriber`. Does **not** register `SttStreaming` — for live\n * transcription use `@effect-uai/inworld/InworldRealtimeTranscriber`.\n */\nexport const layer = (\n cfg: Config,\n): Layer.Layer<InworldTranscriber | Transcriber, never, HttpClient.HttpClient> =>\n Layer.merge(\n Layer.effect(InworldTranscriber, make(cfg)),\n Layer.effect(\n Transcriber,\n Effect.map(make(cfg), (s): TranscriberService => ({\n transcribe: (req: CommonTranscribeRequest) => s.transcribe(req as InworldTranscribeRequest),\n streamTranscriptionFrom: s.streamTranscriptionFrom,\n })),\n ),\n )\n"],"mappings":"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"}
@@ -1,9 +1,7 @@
1
- import { t as InworldAudioEncoding } from "./models-CPLZDcgt.mjs";
1
+ import { t as InworldAudioEncoding } from "./models-DySX9PVy.mjs";
2
2
  import { Effect, Redacted } from "effect";
3
3
  import * as AiError from "@effect-uai/core/AiError";
4
4
  import { AudioFormat } from "@effect-uai/core/Audio";
5
-
6
- //#region src/codec.d.ts
7
5
  declare namespace codec_d_exports {
8
6
  export { AudioConfig, audioConfigFor, audioEncodingFor, authHeader, decodeAudioContent, defaultFormat, httpStatusError, transportFailure };
9
7
  }
@@ -32,4 +30,4 @@ declare const httpStatusError: (status: number, body: string) => AiError.AiError
32
30
  declare const transportFailure: (cause: unknown) => AiError.AiError;
33
31
  //#endregion
34
32
  export { codec_d_exports as a, httpStatusError as c, authHeader as i, transportFailure as l, audioConfigFor as n, decodeAudioContent as o, audioEncodingFor as r, defaultFormat as s, AudioConfig as t };
35
- //# sourceMappingURL=codec-C-2ssVAz.d.mts.map
33
+ //# sourceMappingURL=codec-BU4azW_k.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec-BU4azW_k.d.mts","names":[],"sources":["../src/codec.ts"],"mappings":";;;;;;;cAUa,aAAU,QAAY,SAAS;KAMhC;WACD,eAAe;WACf;WACA;WACA;;;;;;;;;;;cAmBE,mBACX,QAAQ,gBACL,OAAO,OAAO,sBAAsB,QAAQ;cAoBpC,iBAAc,QACjB,aAAW,0BAElB,OAAO,OAAO,aAAa,QAAQ;;cASzB,eAAe;cAUf,qBAAkB,gBAAkB,OAAO,OAAO,YAAY,QAAQ;cAgBtE,kBAAkB,gBAAgB,iBAAiB,QAAQ;cAwC3D,mBAAgB,mBAAqB,QAAQ"}
package/dist/codec.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { c as httpStatusError, i as authHeader, l as transportFailure, n as audioConfigFor, o as decodeAudioContent, r as audioEncodingFor, s as defaultFormat, t as AudioConfig } from "./codec-C-2ssVAz.mjs";
1
+ import { c as httpStatusError, i as authHeader, l as transportFailure, n as audioConfigFor, o as decodeAudioContent, r as audioEncodingFor, s as defaultFormat, t as AudioConfig } from "./codec-BU4azW_k.mjs";
2
2
  export { AudioConfig, audioConfigFor, audioEncodingFor, authHeader, decodeAudioContent, defaultFormat, httpStatusError, transportFailure };
package/dist/codec.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
2
  import { Effect, Encoding, Match, Redacted, Result } from "effect";
3
3
  import * as AiError from "@effect-uai/core/AiError";
4
4
  //#region src/codec.ts
@@ -1 +1 @@
1
- {"version":3,"file":"codec.mjs","names":[],"sources":["../src/codec.ts"],"sourcesContent":["import { Effect, Encoding, Match, Redacted, Result } from \"effect\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioFormat } from \"@effect-uai/core/Audio\"\nimport type { InworldAudioEncoding } from \"./models.js\"\n\n// ---------------------------------------------------------------------------\n// Auth — `Authorization: Basic $INWORLD_API_KEY`. The portal key is already\n// base64-encoded, so we inject it verbatim. Do NOT re-encode `key:secret`.\n// ---------------------------------------------------------------------------\n\nexport const authHeader = (apiKey: Redacted.Redacted): string => `Basic ${Redacted.value(apiKey)}`\n\n// ---------------------------------------------------------------------------\n// AudioFormat → Inworld `audioConfig`\n// ---------------------------------------------------------------------------\n\nexport type AudioConfig = {\n readonly audioEncoding: InworldAudioEncoding\n readonly sampleRateHertz?: number\n readonly bitRate?: number\n readonly speakingRate?: number\n}\n\nconst unsupportedFormat = (format: AudioFormat): AiError.AiError =>\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"outputFormat\",\n reason: `Cannot encode ${JSON.stringify(format)} as Inworld audioConfig. Supported: mp3, wav (LINEAR16), ogg+opus, flac, raw pcm_s16le/mulaw/alaw.`,\n })\n\n/**\n * Map our cross-provider `AudioFormat` to Inworld's `audioConfig.audioEncoding`.\n *\n * Inworld quirk: sync `LINEAR16` / `WAV` responses include a WAV header in\n * the returned `audioContent`; streaming (NDJSON + WS) responses for the\n * same encoding do NOT include the header. Callers consuming raw PCM via\n * streaming should request `raw + pcm_s16le` (→ `PCM`) for predictable\n * concatenation, and reserve `wav` for sync.\n */\nexport const audioEncodingFor: (\n format: AudioFormat,\n) => Effect.Effect<InworldAudioEncoding, AiError.AiError> = (format) =>\n Match.value(format).pipe(\n Match.when({ container: \"mp3\" }, () => Effect.succeed<InworldAudioEncoding>(\"MP3\")),\n Match.when({ container: \"wav\" }, () => Effect.succeed<InworldAudioEncoding>(\"LINEAR16\")),\n Match.when({ container: \"ogg\", encoding: \"opus\" }, () =>\n Effect.succeed<InworldAudioEncoding>(\"OGG_OPUS\"),\n ),\n Match.when({ container: \"flac\" }, () => Effect.succeed<InworldAudioEncoding>(\"FLAC\")),\n Match.when({ container: \"raw\", encoding: \"pcm_s16le\" }, () =>\n Effect.succeed<InworldAudioEncoding>(\"PCM\"),\n ),\n Match.when({ container: \"raw\", encoding: \"pcm_mulaw\" }, () =>\n Effect.succeed<InworldAudioEncoding>(\"MULAW\"),\n ),\n Match.when({ container: \"raw\", encoding: \"pcm_alaw\" }, () =>\n Effect.succeed<InworldAudioEncoding>(\"ALAW\"),\n ),\n Match.orElse((f) => Effect.fail(unsupportedFormat(f))),\n )\n\nexport const audioConfigFor = (\n format: AudioFormat,\n speakingRate?: number,\n): Effect.Effect<AudioConfig, AiError.AiError> =>\n Effect.map(audioEncodingFor(format), (audioEncoding) => ({\n audioEncoding,\n sampleRateHertz: format.sampleRate,\n ...(format.bitRate !== undefined && { bitRate: format.bitRate }),\n ...(speakingRate !== undefined && { speakingRate }),\n }))\n\n/** Default Inworld output: 24 kHz mono mp3. Matches Inworld's docs default. */\nexport const defaultFormat: AudioFormat = {\n container: \"mp3\",\n encoding: \"mp3\",\n sampleRate: 24000,\n}\n\n// ---------------------------------------------------------------------------\n// base64 → bytes — decoding `audioContent` from sync, NDJSON, and WS responses\n// ---------------------------------------------------------------------------\n\nexport const decodeAudioContent = (b64: string): Effect.Effect<Uint8Array, AiError.AiError> =>\n Result.match(Encoding.decodeBase64(b64), {\n onSuccess: Effect.succeed,\n onFailure: (cause) =>\n Effect.fail(\n new AiError.GenerationFailed({\n provider: \"inworld\",\n raw: { message: \"audioContent base64 decode failed\", cause },\n }),\n ),\n })\n\n// ---------------------------------------------------------------------------\n// HTTP status → AiError\n// ---------------------------------------------------------------------------\n\nexport const httpStatusError: (status: number, body: string) => AiError.AiError = (status, body) =>\n Match.value(status).pipe(\n Match.when(\n 429,\n (): AiError.AiError => new AiError.RateLimited({ provider: \"inworld\", raw: body }),\n ),\n Match.whenOr(\n 408,\n 504,\n (): AiError.AiError => new AiError.Timeout({ provider: \"inworld\", raw: body }),\n ),\n Match.when(\n 401,\n (): AiError.AiError =>\n new AiError.AuthFailed({ provider: \"inworld\", subtype: \"auth\", raw: body }),\n ),\n Match.when(\n 403,\n (): AiError.AiError =>\n new AiError.AuthFailed({ provider: \"inworld\", subtype: \"permission\", raw: body }),\n ),\n Match.when(\n 402,\n (): AiError.AiError =>\n new AiError.AuthFailed({ provider: \"inworld\", subtype: \"billing\", raw: body }),\n ),\n Match.when(\n 413,\n (): AiError.AiError => new AiError.ContextLengthExceeded({ provider: \"inworld\", raw: body }),\n ),\n Match.when(\n (n) => n >= 500,\n (n): AiError.AiError =>\n new AiError.Unavailable({ provider: \"inworld\", status: n, raw: body }),\n ),\n Match.orElse(\n (): AiError.AiError => new AiError.InvalidRequest({ provider: \"inworld\", raw: body }),\n ),\n )\n\nexport const transportFailure = (cause: unknown): AiError.AiError =>\n new AiError.Unavailable({ provider: \"inworld\", raw: cause })\n"],"mappings":";;;;;;;;;;;;;AAUA,MAAa,cAAc,WAAsC,SAAS,SAAS,MAAM,OAAO;AAahG,MAAM,qBAAqB,WACzB,IAAI,QAAQ,YAAY;CACtB,UAAU;CACV,YAAY;CACZ,QAAQ,iBAAiB,KAAK,UAAU,OAAO,CAAC;CACjD,CAAC;;;;;;;;;;AAWJ,MAAa,oBAEgD,WAC3D,MAAM,MAAM,OAAO,CAAC,KAClB,MAAM,KAAK,EAAE,WAAW,OAAO,QAAQ,OAAO,QAA8B,MAAM,CAAC,EACnF,MAAM,KAAK,EAAE,WAAW,OAAO,QAAQ,OAAO,QAA8B,WAAW,CAAC,EACxF,MAAM,KAAK;CAAE,WAAW;CAAO,UAAU;CAAQ,QAC/C,OAAO,QAA8B,WAAW,CACjD,EACD,MAAM,KAAK,EAAE,WAAW,QAAQ,QAAQ,OAAO,QAA8B,OAAO,CAAC,EACrF,MAAM,KAAK;CAAE,WAAW;CAAO,UAAU;CAAa,QACpD,OAAO,QAA8B,MAAM,CAC5C,EACD,MAAM,KAAK;CAAE,WAAW;CAAO,UAAU;CAAa,QACpD,OAAO,QAA8B,QAAQ,CAC9C,EACD,MAAM,KAAK;CAAE,WAAW;CAAO,UAAU;CAAY,QACnD,OAAO,QAA8B,OAAO,CAC7C,EACD,MAAM,QAAQ,MAAM,OAAO,KAAK,kBAAkB,EAAE,CAAC,CAAC,CACvD;AAEH,MAAa,kBACX,QACA,iBAEA,OAAO,IAAI,iBAAiB,OAAO,GAAG,mBAAmB;CACvD;CACA,iBAAiB,OAAO;CACxB,GAAI,OAAO,YAAY,KAAA,KAAa,EAAE,SAAS,OAAO,SAAS;CAC/D,GAAI,iBAAiB,KAAA,KAAa,EAAE,cAAc;CACnD,EAAE;;AAGL,MAAa,gBAA6B;CACxC,WAAW;CACX,UAAU;CACV,YAAY;CACb;AAMD,MAAa,sBAAsB,QACjC,OAAO,MAAM,SAAS,aAAa,IAAI,EAAE;CACvC,WAAW,OAAO;CAClB,YAAY,UACV,OAAO,KACL,IAAI,QAAQ,iBAAiB;EAC3B,UAAU;EACV,KAAK;GAAE,SAAS;GAAqC;GAAO;EAC7D,CAAC,CACH;CACJ,CAAC;AAMJ,MAAa,mBAAsE,QAAQ,SACzF,MAAM,MAAM,OAAO,CAAC,KAClB,MAAM,KACJ,WACuB,IAAI,QAAQ,YAAY;CAAE,UAAU;CAAW,KAAK;CAAM,CAAC,CACnF,EACD,MAAM,OACJ,KACA,WACuB,IAAI,QAAQ,QAAQ;CAAE,UAAU;CAAW,KAAK;CAAM,CAAC,CAC/E,EACD,MAAM,KACJ,WAEE,IAAI,QAAQ,WAAW;CAAE,UAAU;CAAW,SAAS;CAAQ,KAAK;CAAM,CAAC,CAC9E,EACD,MAAM,KACJ,WAEE,IAAI,QAAQ,WAAW;CAAE,UAAU;CAAW,SAAS;CAAc,KAAK;CAAM,CAAC,CACpF,EACD,MAAM,KACJ,WAEE,IAAI,QAAQ,WAAW;CAAE,UAAU;CAAW,SAAS;CAAW,KAAK;CAAM,CAAC,CACjF,EACD,MAAM,KACJ,WACuB,IAAI,QAAQ,sBAAsB;CAAE,UAAU;CAAW,KAAK;CAAM,CAAC,CAC7F,EACD,MAAM,MACH,MAAM,KAAK,MACX,MACC,IAAI,QAAQ,YAAY;CAAE,UAAU;CAAW,QAAQ;CAAG,KAAK;CAAM,CAAC,CACzE,EACD,MAAM,aACmB,IAAI,QAAQ,eAAe;CAAE,UAAU;CAAW,KAAK;CAAM,CAAC,CACtF,CACF;AAEH,MAAa,oBAAoB,UAC/B,IAAI,QAAQ,YAAY;CAAE,UAAU;CAAW,KAAK;CAAO,CAAC"}
1
+ {"version":3,"file":"codec.mjs","names":[],"sources":["../src/codec.ts"],"sourcesContent":["import { Effect, Encoding, Match, Redacted, Result } from \"effect\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioFormat } from \"@effect-uai/core/Audio\"\nimport type { InworldAudioEncoding } from \"./models.js\"\n\n// ---------------------------------------------------------------------------\n// Auth — `Authorization: Basic $INWORLD_API_KEY`. The portal key is already\n// base64-encoded, so we inject it verbatim. Do NOT re-encode `key:secret`.\n// ---------------------------------------------------------------------------\n\nexport const authHeader = (apiKey: Redacted.Redacted): string => `Basic ${Redacted.value(apiKey)}`\n\n// ---------------------------------------------------------------------------\n// AudioFormat → Inworld `audioConfig`\n// ---------------------------------------------------------------------------\n\nexport type AudioConfig = {\n readonly audioEncoding: InworldAudioEncoding\n readonly sampleRateHertz?: number\n readonly bitRate?: number\n readonly speakingRate?: number\n}\n\nconst unsupportedFormat = (format: AudioFormat): AiError.AiError =>\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"outputFormat\",\n reason: `Cannot encode ${JSON.stringify(format)} as Inworld audioConfig. Supported: mp3, wav (LINEAR16), ogg+opus, flac, raw pcm_s16le/mulaw/alaw.`,\n })\n\n/**\n * Map our cross-provider `AudioFormat` to Inworld's `audioConfig.audioEncoding`.\n *\n * Inworld quirk: sync `LINEAR16` / `WAV` responses include a WAV header in\n * the returned `audioContent`; streaming (NDJSON + WS) responses for the\n * same encoding do NOT include the header. Callers consuming raw PCM via\n * streaming should request `raw + pcm_s16le` (→ `PCM`) for predictable\n * concatenation, and reserve `wav` for sync.\n */\nexport const audioEncodingFor: (\n format: AudioFormat,\n) => Effect.Effect<InworldAudioEncoding, AiError.AiError> = (format) =>\n Match.value(format).pipe(\n Match.when({ container: \"mp3\" }, () => Effect.succeed<InworldAudioEncoding>(\"MP3\")),\n Match.when({ container: \"wav\" }, () => Effect.succeed<InworldAudioEncoding>(\"LINEAR16\")),\n Match.when({ container: \"ogg\", encoding: \"opus\" }, () =>\n Effect.succeed<InworldAudioEncoding>(\"OGG_OPUS\"),\n ),\n Match.when({ container: \"flac\" }, () => Effect.succeed<InworldAudioEncoding>(\"FLAC\")),\n Match.when({ container: \"raw\", encoding: \"pcm_s16le\" }, () =>\n Effect.succeed<InworldAudioEncoding>(\"PCM\"),\n ),\n Match.when({ container: \"raw\", encoding: \"pcm_mulaw\" }, () =>\n Effect.succeed<InworldAudioEncoding>(\"MULAW\"),\n ),\n Match.when({ container: \"raw\", encoding: \"pcm_alaw\" }, () =>\n Effect.succeed<InworldAudioEncoding>(\"ALAW\"),\n ),\n Match.orElse((f) => Effect.fail(unsupportedFormat(f))),\n )\n\nexport const audioConfigFor = (\n format: AudioFormat,\n speakingRate?: number,\n): Effect.Effect<AudioConfig, AiError.AiError> =>\n Effect.map(audioEncodingFor(format), (audioEncoding) => ({\n audioEncoding,\n sampleRateHertz: format.sampleRate,\n ...(format.bitRate !== undefined && { bitRate: format.bitRate }),\n ...(speakingRate !== undefined && { speakingRate }),\n }))\n\n/** Default Inworld output: 24 kHz mono mp3. Matches Inworld's docs default. */\nexport const defaultFormat: AudioFormat = {\n container: \"mp3\",\n encoding: \"mp3\",\n sampleRate: 24000,\n}\n\n// ---------------------------------------------------------------------------\n// base64 → bytes — decoding `audioContent` from sync, NDJSON, and WS responses\n// ---------------------------------------------------------------------------\n\nexport const decodeAudioContent = (b64: string): Effect.Effect<Uint8Array, AiError.AiError> =>\n Result.match(Encoding.decodeBase64(b64), {\n onSuccess: Effect.succeed,\n onFailure: (cause) =>\n Effect.fail(\n new AiError.GenerationFailed({\n provider: \"inworld\",\n raw: { message: \"audioContent base64 decode failed\", cause },\n }),\n ),\n })\n\n// ---------------------------------------------------------------------------\n// HTTP status → AiError\n// ---------------------------------------------------------------------------\n\nexport const httpStatusError: (status: number, body: string) => AiError.AiError = (status, body) =>\n Match.value(status).pipe(\n Match.when(\n 429,\n (): AiError.AiError => new AiError.RateLimited({ provider: \"inworld\", raw: body }),\n ),\n Match.whenOr(\n 408,\n 504,\n (): AiError.AiError => new AiError.Timeout({ provider: \"inworld\", raw: body }),\n ),\n Match.when(\n 401,\n (): AiError.AiError =>\n new AiError.AuthFailed({ provider: \"inworld\", subtype: \"auth\", raw: body }),\n ),\n Match.when(\n 403,\n (): AiError.AiError =>\n new AiError.AuthFailed({ provider: \"inworld\", subtype: \"permission\", raw: body }),\n ),\n Match.when(\n 402,\n (): AiError.AiError =>\n new AiError.AuthFailed({ provider: \"inworld\", subtype: \"billing\", raw: body }),\n ),\n Match.when(\n 413,\n (): AiError.AiError => new AiError.ContextLengthExceeded({ provider: \"inworld\", raw: body }),\n ),\n Match.when(\n (n) => n >= 500,\n (n): AiError.AiError =>\n new AiError.Unavailable({ provider: \"inworld\", status: n, raw: body }),\n ),\n Match.orElse(\n (): AiError.AiError => new AiError.InvalidRequest({ provider: \"inworld\", raw: body }),\n ),\n )\n\nexport const transportFailure = (cause: unknown): AiError.AiError =>\n new AiError.Unavailable({ provider: \"inworld\", raw: cause })\n"],"mappings":";;;;;;;;;;;;;AAUA,MAAa,cAAc,WAAsC,SAAS,SAAS,MAAM,MAAM;AAa/F,MAAM,qBAAqB,WACzB,IAAI,QAAQ,YAAY;CACtB,UAAU;CACV,YAAY;CACZ,QAAQ,iBAAiB,KAAK,UAAU,MAAM,EAAE;AAClD,CAAC;;;;;;;;;;AAWH,MAAa,oBAEgD,WAC3D,MAAM,MAAM,MAAM,CAAC,CAAC,KAClB,MAAM,KAAK,EAAE,WAAW,MAAM,SAAS,OAAO,QAA8B,KAAK,CAAC,GAClF,MAAM,KAAK,EAAE,WAAW,MAAM,SAAS,OAAO,QAA8B,UAAU,CAAC,GACvF,MAAM,KAAK;CAAE,WAAW;CAAO,UAAU;AAAO,SAC9C,OAAO,QAA8B,UAAU,CACjD,GACA,MAAM,KAAK,EAAE,WAAW,OAAO,SAAS,OAAO,QAA8B,MAAM,CAAC,GACpF,MAAM,KAAK;CAAE,WAAW;CAAO,UAAU;AAAY,SACnD,OAAO,QAA8B,KAAK,CAC5C,GACA,MAAM,KAAK;CAAE,WAAW;CAAO,UAAU;AAAY,SACnD,OAAO,QAA8B,OAAO,CAC9C,GACA,MAAM,KAAK;CAAE,WAAW;CAAO,UAAU;AAAW,SAClD,OAAO,QAA8B,MAAM,CAC7C,GACA,MAAM,QAAQ,MAAM,OAAO,KAAK,kBAAkB,CAAC,CAAC,CAAC,CACvD;AAEF,MAAa,kBACX,QACA,iBAEA,OAAO,IAAI,iBAAiB,MAAM,IAAI,mBAAmB;CACvD;CACA,iBAAiB,OAAO;CACxB,GAAI,OAAO,YAAY,KAAA,KAAa,EAAE,SAAS,OAAO,QAAQ;CAC9D,GAAI,iBAAiB,KAAA,KAAa,EAAE,aAAa;AACnD,EAAE;;AAGJ,MAAa,gBAA6B;CACxC,WAAW;CACX,UAAU;CACV,YAAY;AACd;AAMA,MAAa,sBAAsB,QACjC,OAAO,MAAM,SAAS,aAAa,GAAG,GAAG;CACvC,WAAW,OAAO;CAClB,YAAY,UACV,OAAO,KACL,IAAI,QAAQ,iBAAiB;EAC3B,UAAU;EACV,KAAK;GAAE,SAAS;GAAqC;EAAM;CAC7D,CAAC,CACH;AACJ,CAAC;AAMH,MAAa,mBAAsE,QAAQ,SACzF,MAAM,MAAM,MAAM,CAAC,CAAC,KAClB,MAAM,KACJ,WACuB,IAAI,QAAQ,YAAY;CAAE,UAAU;CAAW,KAAK;AAAK,CAAC,CACnF,GACA,MAAM,OACJ,KACA,WACuB,IAAI,QAAQ,QAAQ;CAAE,UAAU;CAAW,KAAK;AAAK,CAAC,CAC/E,GACA,MAAM,KACJ,WAEE,IAAI,QAAQ,WAAW;CAAE,UAAU;CAAW,SAAS;CAAQ,KAAK;AAAK,CAAC,CAC9E,GACA,MAAM,KACJ,WAEE,IAAI,QAAQ,WAAW;CAAE,UAAU;CAAW,SAAS;CAAc,KAAK;AAAK,CAAC,CACpF,GACA,MAAM,KACJ,WAEE,IAAI,QAAQ,WAAW;CAAE,UAAU;CAAW,SAAS;CAAW,KAAK;AAAK,CAAC,CACjF,GACA,MAAM,KACJ,WACuB,IAAI,QAAQ,sBAAsB;CAAE,UAAU;CAAW,KAAK;AAAK,CAAC,CAC7F,GACA,MAAM,MACH,MAAM,KAAK,MACX,MACC,IAAI,QAAQ,YAAY;CAAE,UAAU;CAAW,QAAQ;CAAG,KAAK;AAAK,CAAC,CACzE,GACA,MAAM,aACmB,IAAI,QAAQ,eAAe;CAAE,UAAU;CAAW,KAAK;AAAK,CAAC,CACtF,CACF;AAEF,MAAa,oBAAoB,UAC/B,IAAI,QAAQ,YAAY;CAAE,UAAU;CAAW,KAAK;AAAM,CAAC"}
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { a as InworldVoiceId, i as InworldTtsModel, n as InworldDeliveryMode, r as InworldSttModel, t as InworldAudioEncoding } from "./models-CPLZDcgt.mjs";
2
- import { a as codec_d_exports } from "./codec-C-2ssVAz.mjs";
1
+ import { a as InworldVoiceId, i as InworldTtsModel, n as InworldDeliveryMode, r as InworldSttModel, t as InworldAudioEncoding } from "./models-DySX9PVy.mjs";
2
+ import { a as codec_d_exports } from "./codec-BU4azW_k.mjs";
3
3
  import { t as InworldSynthesizer_d_exports } from "./InworldSynthesizer.mjs";
4
4
  import { t as InworldRealtimeSynthesizer_d_exports } from "./InworldRealtimeSynthesizer.mjs";
5
5
  import { t as InworldTranscriber_d_exports } from "./InworldTranscriber.mjs";
@@ -44,4 +44,4 @@ type InworldDeliveryMode = "STABLE" | "BALANCED" | "CREATIVE";
44
44
  type InworldAudioEncoding = "LINEAR16" | "MP3" | "OGG_OPUS" | "ALAW" | "MULAW" | "FLAC" | "PCM" | "WAV";
45
45
  //#endregion
46
46
  export { InworldVoiceId as a, InworldTtsModel as i, InworldDeliveryMode as n, InworldSttModel as r, InworldAudioEncoding as t };
47
- //# sourceMappingURL=models-CPLZDcgt.d.mts.map
47
+ //# sourceMappingURL=models-DySX9PVy.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models-DySX9PVy.d.mts","names":[],"sources":["../src/models.ts"],"mappings":";;;;;;;;;;;;;KAYY;;;;;;;KAaA;;;;;;;;;;KAWA;;;;;KAeA;;;;;;;;KASA"}
package/dist/models.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as InworldVoiceId, i as InworldTtsModel, n as InworldDeliveryMode, r as InworldSttModel, t as InworldAudioEncoding } from "./models-CPLZDcgt.mjs";
1
+ import { a as InworldVoiceId, i as InworldTtsModel, n as InworldDeliveryMode, r as InworldSttModel, t as InworldAudioEncoding } from "./models-DySX9PVy.mjs";
2
2
  export { InworldAudioEncoding, InworldDeliveryMode, InworldSttModel, InworldTtsModel, InworldVoiceId };
@@ -2,7 +2,6 @@ import { Redacted, Schema, Stream } from "effect";
2
2
  import * as AiError from "@effect-uai/core/AiError";
3
3
  import { CommonStreamTranscribeRequest } from "@effect-uai/core/Transcriber";
4
4
  import { TranscriptEvent } from "@effect-uai/core/Transcript";
5
-
6
5
  //#region src/realtimeStt.d.ts
7
6
  type Config = {
8
7
  readonly apiKey: Redacted.Redacted;
@@ -1 +1 @@
1
- {"version":3,"file":"realtimeStt.d.mts","names":[],"sources":["../src/realtimeStt.ts"],"mappings":";;;;;;KA8BY,MAAA;EAAA,SAAoB,MAAA,EAAQ,QAAA,CAAS,QAAA;EAAA,SAAmB,OAAA;AAAA;AAAA,cA+F9D,WAAA,EAAW,MAAA,CAAA,MAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;cAgBJ,WAAA,GAAe,KAAA,SAAc,WAAA,CAAY,IAAA,KAAO,eAAA;AAAA,cAoDhD,mBAAA,GACV,GAAA,EAAK,MAAA,YAEJ,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,UAAA,EAAY,CAAA,EAAG,CAAA,GACtC,OAAA,EAAS,6BAAA,KACR,MAAA,CAAO,MAAA,CAAO,eAAA,EAAiB,OAAA,CAAQ,OAAA,GAAU,CAAA,EAAG,CAAA"}
1
+ {"version":3,"file":"realtimeStt.d.mts","names":[],"sources":["../src/realtimeStt.ts"],"mappings":";;;;;KA8BY;WAAoB,QAAQ,SAAS;WAAmB;;cA+F9D,aAAW,OAAA;;;;;;;;;;;;;;;;;;;;;;;cAgBJ,cAAW,cAAkB,YAAY,SAAO;cAoDhD,sBAAmB,KACxB,YACL,GAAG,GAAC,SACM,OAAO,OAAO,YAAY,GAAG,IAAE,SAC/B,kCACR,OAAO,OAAO,iBAAiB,QAAQ,UAAU,GAAG"}
@@ -1 +1 @@
1
- {"version":3,"file":"realtimeStt.mjs","names":[],"sources":["../src/realtimeStt.ts"],"sourcesContent":["/**\n * Inworld Realtime STT — `wss://api.inworld.ai/stt/v1/transcribe:streamBidirectional`.\n *\n * Auth: `Authorization: Basic <API_KEY>` on the WS upgrade header (matches\n * Inworld's own JS sample). Setting headers needs the `ws` peer dep\n * (Node/Bun); see `./wsAuth.ts`.\n *\n * Wire shape (per [inworld-ai/inworld-api-examples](https://github.com/inworld-ai/inworld-api-examples)):\n * client → server:\n * `{ \"transcribeConfig\": { modelId, audioEncoding, sampleRateHertz, language, ... } }` (first frame)\n * `{ \"audioChunk\": { \"content\": \"<base64 audio>\" } }` (×N)\n * `{ \"closeStream\": {} }` (end-of-input)\n * server → client:\n * `{ \"result\": { \"transcription\": { \"transcript\": \"...\", \"isFinal\": true|false } } }`\n * `{ \"result\": { \"speechStarted\": { \"startTimeMs\": ... } } }`\n * `{ \"result\": { \"speechStopped\": { \"silenceDurationMs\": ... } } }`\n *\n * Inworld's STT WS sends audio as base64 inside JSON (NOT binary frames),\n * matching the rest of the Inworld API style.\n */\nimport { Cause, Effect, Encoding, Match, Queue, Redacted, Schema, Stream } from \"effect\"\nimport * as Socket from \"effect/unstable/socket/Socket\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioFormat } from \"@effect-uai/core/Audio\"\nimport * as Capabilities from \"@effect-uai/core/Capabilities\"\nimport * as JSONL from \"@effect-uai/core/JSONL\"\nimport type { TranscriptEvent, WordTimestamp } from \"@effect-uai/core/Transcript\"\nimport type { CommonStreamTranscribeRequest } from \"@effect-uai/core/Transcriber\"\nimport { authedWsConstructor } from \"./wsAuth.js\"\n\nexport type Config = { readonly apiKey: Redacted.Redacted; readonly baseUrl?: string }\n\n// ---------------------------------------------------------------------------\n// AudioFormat → `audioEncoding` slug for Inworld STT\n// ---------------------------------------------------------------------------\n\ntype WireEncoding = \"LINEAR16\" | \"MP3\" | \"OGG_OPUS\" | \"FLAC\"\n\nconst unsupportedFormat = (format: AudioFormat) =>\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"inputFormat\",\n reason: `Inworld realtime STT accepts pcm_s16le (LINEAR16), mp3, ogg/opus, or flac. Got ${JSON.stringify(format)}.`,\n })\n\nconst inputFormatToWire: (format: AudioFormat) => Effect.Effect<WireEncoding, AiError.AiError> =\n Match.type<AudioFormat>().pipe(\n Match.when({ container: \"raw\", encoding: \"pcm_s16le\" }, () =>\n Effect.succeed<WireEncoding>(\"LINEAR16\"),\n ),\n Match.when({ container: \"wav\", encoding: \"pcm_s16le\" }, () =>\n Effect.succeed<WireEncoding>(\"LINEAR16\"),\n ),\n Match.when({ container: \"mp3\" }, () => Effect.succeed<WireEncoding>(\"MP3\")),\n Match.when({ container: \"ogg\", encoding: \"opus\" }, () =>\n Effect.succeed<WireEncoding>(\"OGG_OPUS\"),\n ),\n Match.when({ container: \"flac\" }, () => Effect.succeed<WireEncoding>(\"FLAC\")),\n Match.orElse((f) => Effect.fail(unsupportedFormat(f))),\n )\n\n// ---------------------------------------------------------------------------\n// URL + frame builders\n// ---------------------------------------------------------------------------\n\nconst buildWsUrl = (cfg: Config) => {\n const wsBase = (cfg.baseUrl ?? \"https://api.inworld.ai\").replace(/^http/, \"ws\")\n return `${wsBase}/stt/v1/transcribe:streamBidirectional`\n}\n\nconst configFrame = (encoding: WireEncoding, request: CommonStreamTranscribeRequest) =>\n JSON.stringify({\n transcribeConfig: {\n modelId: request.model,\n audioEncoding: encoding,\n sampleRateHertz: request.inputFormat.sampleRate,\n numberOfChannels: request.inputFormat.channels ?? 1,\n // Inworld's sample includes `language` even though docs mark it optional.\n // Default to en-US to match the sample's behavior; caller can override.\n language: request.language ?? \"en-US\",\n // `prompts` is a vocab-biasing term list — maps from `biasingTerms`.\n ...(request.biasingTerms !== undefined && { prompts: request.biasingTerms }),\n ...(request.wordTimestamps === true && { includeWordTimestamps: true }),\n },\n })\n\nconst audioChunkFrame = (bytes: Uint8Array) =>\n JSON.stringify({ audioChunk: { content: Encoding.encodeBase64(bytes) } })\n\nconst endTurnFrame = JSON.stringify({ endTurn: {} })\nconst closeStreamFrame = JSON.stringify({ closeStream: {} })\n\n// ---------------------------------------------------------------------------\n// Wire schemas (server → client)\n// ---------------------------------------------------------------------------\n\nconst WireWord = Schema.Struct({\n word: Schema.String,\n startTimeMs: Schema.optional(Schema.Number),\n endTimeMs: Schema.optional(Schema.Number),\n confidence: Schema.optional(Schema.Number),\n})\n\nconst ResultBody = Schema.Struct({\n transcription: Schema.optional(\n Schema.Struct({\n transcript: Schema.String,\n isFinal: Schema.optional(Schema.Boolean),\n wordTimestamps: Schema.optional(Schema.NullOr(Schema.Array(WireWord))),\n }),\n ),\n speechStarted: Schema.optional(\n Schema.Struct({\n startTimeMs: Schema.optional(Schema.Number),\n confidence: Schema.optional(Schema.Number),\n }),\n ),\n speechStopped: Schema.optional(\n Schema.Struct({\n silenceDurationMs: Schema.optional(Schema.Number),\n }),\n ),\n status: Schema.optional(Schema.Unknown),\n})\n\nconst ServerFrame = Schema.Struct({\n result: Schema.optional(ResultBody),\n error: Schema.optional(Schema.Unknown),\n})\nconst decodeServerFrame = Schema.decodeUnknownEffect(ServerFrame)\n\nconst wireWordToCommon = (w: typeof WireWord.Type): WordTimestamp | undefined =>\n w.startTimeMs === undefined || w.endTimeMs === undefined\n ? undefined\n : {\n text: w.word,\n startSeconds: w.startTimeMs / 1000,\n endSeconds: w.endTimeMs / 1000,\n ...(w.confidence !== undefined && { confidence: w.confidence }),\n }\n\nexport const wireToEvent = (frame: typeof ServerFrame.Type): TranscriptEvent | undefined => {\n if (frame.error !== undefined) {\n return {\n _tag: \"error\",\n message: typeof frame.error === \"string\" ? frame.error : JSON.stringify(frame.error),\n }\n }\n const result = frame.result\n if (result === undefined) return undefined\n if (result.transcription !== undefined) {\n const t = result.transcription\n const words = t.wordTimestamps\n ?.map(wireWordToCommon)\n .filter((w): w is WordTimestamp => w !== undefined)\n return t.isFinal === true\n ? {\n _tag: \"final\",\n text: t.transcript,\n ...(words !== undefined && words.length > 0 && { words }),\n }\n : {\n _tag: \"partial\",\n text: t.transcript,\n ...(words !== undefined && words.length > 0 && { words }),\n }\n }\n if (result.speechStarted !== undefined) {\n return {\n _tag: \"speech-started\",\n atSeconds: (result.speechStarted.startTimeMs ?? 0) / 1000,\n }\n }\n if (result.speechStopped !== undefined) {\n return { _tag: \"utterance-ended\", atSeconds: 0 }\n }\n return undefined\n}\n\nconst handleServerMessage = (queue: Queue.Queue<TranscriptEvent, Cause.Done>) => (raw: string) =>\n Effect.gen(function* () {\n const json = yield* JSONL.parseSafe(raw)\n if (json === undefined) return\n const decoded = yield* decodeServerFrame(json).pipe(Effect.option)\n if (decoded._tag === \"None\") return\n const event = wireToEvent(decoded.value)\n if (event !== undefined) yield* Queue.offer(queue, event)\n })\n\n// ---------------------------------------------------------------------------\n// Stream<Uint8Array> → Stream<TranscriptEvent>\n// ---------------------------------------------------------------------------\n\nexport const streamTranscription =\n (cfg: Config) =>\n <E, R>(\n audioIn: Stream.Stream<Uint8Array, E, R>,\n request: CommonStreamTranscribeRequest,\n ): Stream.Stream<TranscriptEvent, AiError.AiError | E, R> =>\n Stream.unwrap(\n Effect.gen(function* () {\n yield* Capabilities.warnDroppedWhen(request.prompt, {\n provider: \"inworld\",\n capability: \"prompt\",\n field: \"prompt\",\n reason: \"Inworld STT has no free-form prompt field; bias via `biasingTerms`.\",\n })\n const encoding = yield* inputFormatToWire(request.inputFormat)\n const socket = yield* Socket.makeWebSocket(buildWsUrl(cfg), {\n // Effect's Socket treats all close codes as errors by default —\n // whitelist standard clean-close codes (1000 / 1001 / 1005).\n closeCodeIsError: (code) => code !== 1000 && code !== 1001 && code !== 1005,\n }).pipe(Effect.provideService(Socket.WebSocketConstructor, authedWsConstructor(cfg.apiKey)))\n const queue = yield* Queue.bounded<TranscriptEvent, Cause.Done>(64)\n const write = yield* socket.writer\n\n // Writer: config → drain audio → endTurn → closeStream. Inworld\n // emits `result.transcription` partials in real-time via VAD;\n // `endTurn` is sent on input-stream end to flush any tail audio\n // into a final transcript, then `closeStream` for graceful close.\n yield* Effect.gen(function* () {\n yield* write(configFrame(encoding, request))\n yield* Stream.runForEach(audioIn, (bytes) => write(audioChunkFrame(bytes)))\n yield* write(endTurnFrame)\n yield* write(closeStreamFrame)\n }).pipe(Effect.ignore, Effect.forkScoped)\n\n // `Queue.end` flushes pending events then fails the next take with\n // `Done` — clean stream end. `Queue.shutdown` would CLEAR queued\n // items and interrupt pending takes (wrong for graceful teardown).\n yield* socket\n .runString(handleServerMessage(queue))\n .pipe(Effect.ensuring(Queue.end(queue)), Effect.forkScoped)\n\n return Stream.fromQueue(queue)\n }),\n )\n"],"mappings":"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"}
1
+ {"version":3,"file":"realtimeStt.mjs","names":[],"sources":["../src/realtimeStt.ts"],"sourcesContent":["/**\n * Inworld Realtime STT — `wss://api.inworld.ai/stt/v1/transcribe:streamBidirectional`.\n *\n * Auth: `Authorization: Basic <API_KEY>` on the WS upgrade header (matches\n * Inworld's own JS sample). Setting headers needs the `ws` peer dep\n * (Node/Bun); see `./wsAuth.ts`.\n *\n * Wire shape (per [inworld-ai/inworld-api-examples](https://github.com/inworld-ai/inworld-api-examples)):\n * client → server:\n * `{ \"transcribeConfig\": { modelId, audioEncoding, sampleRateHertz, language, ... } }` (first frame)\n * `{ \"audioChunk\": { \"content\": \"<base64 audio>\" } }` (×N)\n * `{ \"closeStream\": {} }` (end-of-input)\n * server → client:\n * `{ \"result\": { \"transcription\": { \"transcript\": \"...\", \"isFinal\": true|false } } }`\n * `{ \"result\": { \"speechStarted\": { \"startTimeMs\": ... } } }`\n * `{ \"result\": { \"speechStopped\": { \"silenceDurationMs\": ... } } }`\n *\n * Inworld's STT WS sends audio as base64 inside JSON (NOT binary frames),\n * matching the rest of the Inworld API style.\n */\nimport { Cause, Effect, Encoding, Match, Queue, Redacted, Schema, Stream } from \"effect\"\nimport * as Socket from \"effect/unstable/socket/Socket\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioFormat } from \"@effect-uai/core/Audio\"\nimport * as Capabilities from \"@effect-uai/core/Capabilities\"\nimport * as JSONL from \"@effect-uai/core/JSONL\"\nimport type { TranscriptEvent, WordTimestamp } from \"@effect-uai/core/Transcript\"\nimport type { CommonStreamTranscribeRequest } from \"@effect-uai/core/Transcriber\"\nimport { authedWsConstructor } from \"./wsAuth.js\"\n\nexport type Config = { readonly apiKey: Redacted.Redacted; readonly baseUrl?: string }\n\n// ---------------------------------------------------------------------------\n// AudioFormat → `audioEncoding` slug for Inworld STT\n// ---------------------------------------------------------------------------\n\ntype WireEncoding = \"LINEAR16\" | \"MP3\" | \"OGG_OPUS\" | \"FLAC\"\n\nconst unsupportedFormat = (format: AudioFormat) =>\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"inputFormat\",\n reason: `Inworld realtime STT accepts pcm_s16le (LINEAR16), mp3, ogg/opus, or flac. Got ${JSON.stringify(format)}.`,\n })\n\nconst inputFormatToWire: (format: AudioFormat) => Effect.Effect<WireEncoding, AiError.AiError> =\n Match.type<AudioFormat>().pipe(\n Match.when({ container: \"raw\", encoding: \"pcm_s16le\" }, () =>\n Effect.succeed<WireEncoding>(\"LINEAR16\"),\n ),\n Match.when({ container: \"wav\", encoding: \"pcm_s16le\" }, () =>\n Effect.succeed<WireEncoding>(\"LINEAR16\"),\n ),\n Match.when({ container: \"mp3\" }, () => Effect.succeed<WireEncoding>(\"MP3\")),\n Match.when({ container: \"ogg\", encoding: \"opus\" }, () =>\n Effect.succeed<WireEncoding>(\"OGG_OPUS\"),\n ),\n Match.when({ container: \"flac\" }, () => Effect.succeed<WireEncoding>(\"FLAC\")),\n Match.orElse((f) => Effect.fail(unsupportedFormat(f))),\n )\n\n// ---------------------------------------------------------------------------\n// URL + frame builders\n// ---------------------------------------------------------------------------\n\nconst buildWsUrl = (cfg: Config) => {\n const wsBase = (cfg.baseUrl ?? \"https://api.inworld.ai\").replace(/^http/, \"ws\")\n return `${wsBase}/stt/v1/transcribe:streamBidirectional`\n}\n\nconst configFrame = (encoding: WireEncoding, request: CommonStreamTranscribeRequest) =>\n JSON.stringify({\n transcribeConfig: {\n modelId: request.model,\n audioEncoding: encoding,\n sampleRateHertz: request.inputFormat.sampleRate,\n numberOfChannels: request.inputFormat.channels ?? 1,\n // Inworld's sample includes `language` even though docs mark it optional.\n // Default to en-US to match the sample's behavior; caller can override.\n language: request.language ?? \"en-US\",\n // `prompts` is a vocab-biasing term list — maps from `biasingTerms`.\n ...(request.biasingTerms !== undefined && { prompts: request.biasingTerms }),\n ...(request.wordTimestamps === true && { includeWordTimestamps: true }),\n },\n })\n\nconst audioChunkFrame = (bytes: Uint8Array) =>\n JSON.stringify({ audioChunk: { content: Encoding.encodeBase64(bytes) } })\n\nconst endTurnFrame = JSON.stringify({ endTurn: {} })\nconst closeStreamFrame = JSON.stringify({ closeStream: {} })\n\n// ---------------------------------------------------------------------------\n// Wire schemas (server → client)\n// ---------------------------------------------------------------------------\n\nconst WireWord = Schema.Struct({\n word: Schema.String,\n startTimeMs: Schema.optional(Schema.Number),\n endTimeMs: Schema.optional(Schema.Number),\n confidence: Schema.optional(Schema.Number),\n})\n\nconst ResultBody = Schema.Struct({\n transcription: Schema.optional(\n Schema.Struct({\n transcript: Schema.String,\n isFinal: Schema.optional(Schema.Boolean),\n wordTimestamps: Schema.optional(Schema.NullOr(Schema.Array(WireWord))),\n }),\n ),\n speechStarted: Schema.optional(\n Schema.Struct({\n startTimeMs: Schema.optional(Schema.Number),\n confidence: Schema.optional(Schema.Number),\n }),\n ),\n speechStopped: Schema.optional(\n Schema.Struct({\n silenceDurationMs: Schema.optional(Schema.Number),\n }),\n ),\n status: Schema.optional(Schema.Unknown),\n})\n\nconst ServerFrame = Schema.Struct({\n result: Schema.optional(ResultBody),\n error: Schema.optional(Schema.Unknown),\n})\nconst decodeServerFrame = Schema.decodeUnknownEffect(ServerFrame)\n\nconst wireWordToCommon = (w: typeof WireWord.Type): WordTimestamp | undefined =>\n w.startTimeMs === undefined || w.endTimeMs === undefined\n ? undefined\n : {\n text: w.word,\n startSeconds: w.startTimeMs / 1000,\n endSeconds: w.endTimeMs / 1000,\n ...(w.confidence !== undefined && { confidence: w.confidence }),\n }\n\nexport const wireToEvent = (frame: typeof ServerFrame.Type): TranscriptEvent | undefined => {\n if (frame.error !== undefined) {\n return {\n _tag: \"error\",\n message: typeof frame.error === \"string\" ? frame.error : JSON.stringify(frame.error),\n }\n }\n const result = frame.result\n if (result === undefined) return undefined\n if (result.transcription !== undefined) {\n const t = result.transcription\n const words = t.wordTimestamps\n ?.map(wireWordToCommon)\n .filter((w): w is WordTimestamp => w !== undefined)\n return t.isFinal === true\n ? {\n _tag: \"final\",\n text: t.transcript,\n ...(words !== undefined && words.length > 0 && { words }),\n }\n : {\n _tag: \"partial\",\n text: t.transcript,\n ...(words !== undefined && words.length > 0 && { words }),\n }\n }\n if (result.speechStarted !== undefined) {\n return {\n _tag: \"speech-started\",\n atSeconds: (result.speechStarted.startTimeMs ?? 0) / 1000,\n }\n }\n if (result.speechStopped !== undefined) {\n return { _tag: \"utterance-ended\", atSeconds: 0 }\n }\n return undefined\n}\n\nconst handleServerMessage = (queue: Queue.Queue<TranscriptEvent, Cause.Done>) => (raw: string) =>\n Effect.gen(function* () {\n const json = yield* JSONL.parseSafe(raw)\n if (json === undefined) return\n const decoded = yield* decodeServerFrame(json).pipe(Effect.option)\n if (decoded._tag === \"None\") return\n const event = wireToEvent(decoded.value)\n if (event !== undefined) yield* Queue.offer(queue, event)\n })\n\n// ---------------------------------------------------------------------------\n// Stream<Uint8Array> → Stream<TranscriptEvent>\n// ---------------------------------------------------------------------------\n\nexport const streamTranscription =\n (cfg: Config) =>\n <E, R>(\n audioIn: Stream.Stream<Uint8Array, E, R>,\n request: CommonStreamTranscribeRequest,\n ): Stream.Stream<TranscriptEvent, AiError.AiError | E, R> =>\n Stream.unwrap(\n Effect.gen(function* () {\n yield* Capabilities.warnDroppedWhen(request.prompt, {\n provider: \"inworld\",\n capability: \"prompt\",\n field: \"prompt\",\n reason: \"Inworld STT has no free-form prompt field; bias via `biasingTerms`.\",\n })\n const encoding = yield* inputFormatToWire(request.inputFormat)\n const socket = yield* Socket.makeWebSocket(buildWsUrl(cfg), {\n // Effect's Socket treats all close codes as errors by default —\n // whitelist standard clean-close codes (1000 / 1001 / 1005).\n closeCodeIsError: (code) => code !== 1000 && code !== 1001 && code !== 1005,\n }).pipe(Effect.provideService(Socket.WebSocketConstructor, authedWsConstructor(cfg.apiKey)))\n const queue = yield* Queue.bounded<TranscriptEvent, Cause.Done>(64)\n const write = yield* socket.writer\n\n // Writer: config → drain audio → endTurn → closeStream. Inworld\n // emits `result.transcription` partials in real-time via VAD;\n // `endTurn` is sent on input-stream end to flush any tail audio\n // into a final transcript, then `closeStream` for graceful close.\n yield* Effect.gen(function* () {\n yield* write(configFrame(encoding, request))\n yield* Stream.runForEach(audioIn, (bytes) => write(audioChunkFrame(bytes)))\n yield* write(endTurnFrame)\n yield* write(closeStreamFrame)\n }).pipe(Effect.ignore, Effect.forkScoped)\n\n // `Queue.end` flushes pending events then fails the next take with\n // `Done` — clean stream end. `Queue.shutdown` would CLEAR queued\n // items and interrupt pending takes (wrong for graceful teardown).\n yield* socket\n .runString(handleServerMessage(queue))\n .pipe(Effect.ensuring(Queue.end(queue)), Effect.forkScoped)\n\n return Stream.fromQueue(queue)\n }),\n )\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,MAAM,qBAAqB,WACzB,IAAI,QAAQ,YAAY;CACtB,UAAU;CACV,YAAY;CACZ,QAAQ,kFAAkF,KAAK,UAAU,MAAM,EAAE;AACnH,CAAC;AAEH,MAAM,oBACJ,MAAM,KAAkB,CAAC,CAAC,KACxB,MAAM,KAAK;CAAE,WAAW;CAAO,UAAU;AAAY,SACnD,OAAO,QAAsB,UAAU,CACzC,GACA,MAAM,KAAK;CAAE,WAAW;CAAO,UAAU;AAAY,SACnD,OAAO,QAAsB,UAAU,CACzC,GACA,MAAM,KAAK,EAAE,WAAW,MAAM,SAAS,OAAO,QAAsB,KAAK,CAAC,GAC1E,MAAM,KAAK;CAAE,WAAW;CAAO,UAAU;AAAO,SAC9C,OAAO,QAAsB,UAAU,CACzC,GACA,MAAM,KAAK,EAAE,WAAW,OAAO,SAAS,OAAO,QAAsB,MAAM,CAAC,GAC5E,MAAM,QAAQ,MAAM,OAAO,KAAK,kBAAkB,CAAC,CAAC,CAAC,CACvD;AAMF,MAAM,cAAc,QAAgB;CAElC,OAAO,IADS,IAAI,WAAW,yBAAA,CAA0B,QAAQ,SAAS,IAC3D,EAAE;AACnB;AAEA,MAAM,eAAe,UAAwB,YAC3C,KAAK,UAAU,EACb,kBAAkB;CAChB,SAAS,QAAQ;CACjB,eAAe;CACf,iBAAiB,QAAQ,YAAY;CACrC,kBAAkB,QAAQ,YAAY,YAAY;CAGlD,UAAU,QAAQ,YAAY;CAE9B,GAAI,QAAQ,iBAAiB,KAAA,KAAa,EAAE,SAAS,QAAQ,aAAa;CAC1E,GAAI,QAAQ,mBAAmB,QAAQ,EAAE,uBAAuB,KAAK;AACvE,EACF,CAAC;AAEH,MAAM,mBAAmB,UACvB,KAAK,UAAU,EAAE,YAAY,EAAE,SAAS,SAAS,aAAa,KAAK,EAAE,EAAE,CAAC;AAE1E,MAAM,eAAe,KAAK,UAAU,EAAE,SAAS,CAAC,EAAE,CAAC;AACnD,MAAM,mBAAmB,KAAK,UAAU,EAAE,aAAa,CAAC,EAAE,CAAC;AAM3D,MAAM,WAAW,OAAO,OAAO;CAC7B,MAAM,OAAO;CACb,aAAa,OAAO,SAAS,OAAO,MAAM;CAC1C,WAAW,OAAO,SAAS,OAAO,MAAM;CACxC,YAAY,OAAO,SAAS,OAAO,MAAM;AAC3C,CAAC;AAED,MAAM,aAAa,OAAO,OAAO;CAC/B,eAAe,OAAO,SACpB,OAAO,OAAO;EACZ,YAAY,OAAO;EACnB,SAAS,OAAO,SAAS,OAAO,OAAO;EACvC,gBAAgB,OAAO,SAAS,OAAO,OAAO,OAAO,MAAM,QAAQ,CAAC,CAAC;CACvE,CAAC,CACH;CACA,eAAe,OAAO,SACpB,OAAO,OAAO;EACZ,aAAa,OAAO,SAAS,OAAO,MAAM;EAC1C,YAAY,OAAO,SAAS,OAAO,MAAM;CAC3C,CAAC,CACH;CACA,eAAe,OAAO,SACpB,OAAO,OAAO,EACZ,mBAAmB,OAAO,SAAS,OAAO,MAAM,EAClD,CAAC,CACH;CACA,QAAQ,OAAO,SAAS,OAAO,OAAO;AACxC,CAAC;AAED,MAAM,cAAc,OAAO,OAAO;CAChC,QAAQ,OAAO,SAAS,UAAU;CAClC,OAAO,OAAO,SAAS,OAAO,OAAO;AACvC,CAAC;AACD,MAAM,oBAAoB,OAAO,oBAAoB,WAAW;AAEhE,MAAM,oBAAoB,MACxB,EAAE,gBAAgB,KAAA,KAAa,EAAE,cAAc,KAAA,IAC3C,KAAA,IACA;CACE,MAAM,EAAE;CACR,cAAc,EAAE,cAAc;CAC9B,YAAY,EAAE,YAAY;CAC1B,GAAI,EAAE,eAAe,KAAA,KAAa,EAAE,YAAY,EAAE,WAAW;AAC/D;AAEN,MAAa,eAAe,UAAgE;CAC1F,IAAI,MAAM,UAAU,KAAA,GAClB,OAAO;EACL,MAAM;EACN,SAAS,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ,KAAK,UAAU,MAAM,KAAK;CACrF;CAEF,MAAM,SAAS,MAAM;CACrB,IAAI,WAAW,KAAA,GAAW,OAAO,KAAA;CACjC,IAAI,OAAO,kBAAkB,KAAA,GAAW;EACtC,MAAM,IAAI,OAAO;EACjB,MAAM,QAAQ,EAAE,gBACZ,IAAI,gBAAgB,CAAC,CACtB,QAAQ,MAA0B,MAAM,KAAA,CAAS;EACpD,OAAO,EAAE,YAAY,OACjB;GACE,MAAM;GACN,MAAM,EAAE;GACR,GAAI,UAAU,KAAA,KAAa,MAAM,SAAS,KAAK,EAAE,MAAM;EACzD,IACA;GACE,MAAM;GACN,MAAM,EAAE;GACR,GAAI,UAAU,KAAA,KAAa,MAAM,SAAS,KAAK,EAAE,MAAM;EACzD;CACN;CACA,IAAI,OAAO,kBAAkB,KAAA,GAC3B,OAAO;EACL,MAAM;EACN,YAAY,OAAO,cAAc,eAAe,KAAK;CACvD;CAEF,IAAI,OAAO,kBAAkB,KAAA,GAC3B,OAAO;EAAE,MAAM;EAAmB,WAAW;CAAE;AAGnD;AAEA,MAAM,uBAAuB,WAAqD,QAChF,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,MAAM,UAAU,GAAG;CACvC,IAAI,SAAS,KAAA,GAAW;CACxB,MAAM,UAAU,OAAO,kBAAkB,IAAI,CAAC,CAAC,KAAK,OAAO,MAAM;CACjE,IAAI,QAAQ,SAAS,QAAQ;CAC7B,MAAM,QAAQ,YAAY,QAAQ,KAAK;CACvC,IAAI,UAAU,KAAA,GAAW,OAAO,MAAM,MAAM,OAAO,KAAK;AAC1D,CAAC;AAMH,MAAa,uBACV,SAEC,SACA,YAEA,OAAO,OACL,OAAO,IAAI,aAAa;CACtB,OAAO,aAAa,gBAAgB,QAAQ,QAAQ;EAClD,UAAU;EACV,YAAY;EACZ,OAAO;EACP,QAAQ;CACV,CAAC;CACD,MAAM,WAAW,OAAO,kBAAkB,QAAQ,WAAW;CAC7D,MAAM,SAAS,OAAO,OAAO,cAAc,WAAW,GAAG,GAAG,EAG1D,mBAAmB,SAAS,SAAS,OAAQ,SAAS,QAAQ,SAAS,KACzE,CAAC,CAAC,CAAC,KAAK,OAAO,eAAe,OAAO,sBAAsB,oBAAoB,IAAI,MAAM,CAAC,CAAC;CAC3F,MAAM,QAAQ,OAAO,MAAM,QAAqC,EAAE;CAClE,MAAM,QAAQ,OAAO,OAAO;CAM5B,OAAO,OAAO,IAAI,aAAa;EAC7B,OAAO,MAAM,YAAY,UAAU,OAAO,CAAC;EAC3C,OAAO,OAAO,WAAW,UAAU,UAAU,MAAM,gBAAgB,KAAK,CAAC,CAAC;EAC1E,OAAO,MAAM,YAAY;EACzB,OAAO,MAAM,gBAAgB;CAC/B,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,OAAO,UAAU;CAKxC,OAAO,OACJ,UAAU,oBAAoB,KAAK,CAAC,CAAC,CACrC,KAAK,OAAO,SAAS,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,UAAU;CAE5D,OAAO,OAAO,UAAU,KAAK;AAC/B,CAAC,CACH"}
@@ -1,9 +1,8 @@
1
- import { a as InworldVoiceId, i as InworldTtsModel, n as InworldDeliveryMode } from "./models-CPLZDcgt.mjs";
1
+ import { a as InworldVoiceId, i as InworldTtsModel, n as InworldDeliveryMode } from "./models-DySX9PVy.mjs";
2
2
  import { Redacted, Stream } from "effect";
3
3
  import { CustomPronunciation } from "@effect-uai/core/SpeechSynthesizer";
4
4
  import * as AiError from "@effect-uai/core/AiError";
5
5
  import { AudioChunk, AudioFormat } from "@effect-uai/core/Audio";
6
-
7
6
  //#region src/realtimeTts.d.ts
8
7
  type Config = {
9
8
  readonly apiKey: Redacted.Redacted;
@@ -1 +1 @@
1
- {"version":3,"file":"realtimeTts.d.mts","names":[],"sources":["../src/realtimeTts.ts"],"mappings":";;;;;;;KA+BY,MAAA;EAAA,SAAoB,MAAA,EAAQ,QAAA,CAAS,QAAA;EAAA,SAAmB,OAAA;AAAA;;;;;KAMxD,uBAAA;EAAA,SACD,KAAA,EAAO,eAAA;EAAA,SACP,OAAA,EAAS,cAAA;EAAA,SACT,YAAA,GAAe,WAAA;EAAA,SACf,YAAA;EAAA,SACA,WAAA;EAAA,SACA,YAAA,GAAe,mBAAA;EAAA,SACf,sBAAA;EAAA,SACA,KAAA;EAGkD;;EAAA,SAAlD,cAAA,GAAiB,aAAA,CAAc,mBAAA;AAAA;AAAA,cAO7B,UAAA,GAAc,GAAA,EAAK,MAAA;AAAA,cA8EnB,eAAA,GACV,GAAA,EAAK,MAAA,YAEJ,MAAA,EAAQ,MAAA,CAAO,MAAA,SAAe,CAAA,EAAG,CAAA,GACjC,OAAA,EAAS,uBAAA,KACR,MAAA,CAAO,MAAA,CAAO,UAAA,EAAY,OAAA,CAAQ,OAAA,GAAU,CAAA,EAAG,CAAA"}
1
+ {"version":3,"file":"realtimeTts.d.mts","names":[],"sources":["../src/realtimeTts.ts"],"mappings":";;;;;;KA+BY;WAAoB,QAAQ,SAAS;WAAmB;;;;;;KAMxD;WACD,OAAO;WACP,SAAS;WACT,eAAe;WACf;WACA;WACA,eAAe;WACf;WACA;;;WAGA,iBAAiB,cAAc;;cAO7B,aAAU,KAAS;cA8EnB,kBAAe,KACpB,YACL,GAAG,GAAC,QACK,OAAO,eAAe,GAAG,IAAE,SAC1B,4BACR,OAAO,OAAO,YAAY,QAAQ,UAAU,GAAG"}
@@ -1 +1 @@
1
- {"version":3,"file":"realtimeTts.mjs","names":[],"sources":["../src/realtimeTts.ts"],"sourcesContent":["/**\n * Inworld Realtime TTS — `wss://api.inworld.ai/tts/v1/voice:streamBidirectional`.\n *\n * Auth: `Authorization: Basic <API_KEY>` on the WS upgrade header (matches\n * Inworld's own JS sample). The docs mention a `?Authorization=…` query\n * variant but the server rejects it in practice. Setting headers needs the\n * `ws` peer dep (Node/Bun); see `./wsAuth.ts`.\n *\n * Wire shape (single-context per call):\n * client → server:\n * `{ \"create\": { voiceId, modelId, audioConfig, ... } }`\n * `{ \"send_text\": { \"text\": \"...\" } }` (repeated)\n * `{ \"close_context\": {} }` (text stream end)\n * server → client:\n * `{ \"result\": { \"contextCreated\": {...} } }` (handshake ack)\n * `{ \"result\": { \"audioChunk\": { \"audioContent\": \"<b64>\" } } }` (×N)\n * `{ \"result\": { \"contextClosed\": {...} } }` (final)\n *\n * Multi-context (`contextId`) is not surfaced here — one logical\n * utterance per call.\n */\nimport { Cause, Effect, Queue, Redacted, Schema, Stream } from \"effect\"\nimport * as Socket from \"effect/unstable/socket/Socket\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioChunk, AudioFormat } from \"@effect-uai/core/Audio\"\nimport * as JSONL from \"@effect-uai/core/JSONL\"\nimport type { CustomPronunciation } from \"@effect-uai/core/SpeechSynthesizer\"\nimport { audioConfigFor, decodeAudioContent, defaultFormat } from \"./codec.js\"\nimport type { InworldDeliveryMode, InworldTtsModel, InworldVoiceId } from \"./models.js\"\nimport { authedWsConstructor } from \"./wsAuth.js\"\n\nexport type Config = { readonly apiKey: Redacted.Redacted; readonly baseUrl?: string }\n\n/**\n * Incremental-text-in request. Mirrors the sync request minus `text` (which\n * comes from the input stream).\n */\nexport type StreamSynthesizeRequest = {\n readonly model: InworldTtsModel\n readonly voiceId: InworldVoiceId\n readonly outputFormat?: AudioFormat\n readonly languageCode?: string\n readonly temperature?: number\n readonly deliveryMode?: InworldDeliveryMode\n readonly applyTextNormalization?: \"ON\" | \"OFF\"\n readonly speed?: number\n /** Carried from the Common request so the WS path can reject inline\n * pronunciations (no place to rewrite into a chunked text stream). */\n readonly pronunciations?: ReadonlyArray<CustomPronunciation>\n}\n\n// ---------------------------------------------------------------------------\n// URL + frame builders\n// ---------------------------------------------------------------------------\n\nexport const buildWsUrl = (cfg: Config) => {\n const wsBase = (cfg.baseUrl ?? \"https://api.inworld.ai\").replace(/^http/, \"ws\")\n return `${wsBase}/tts/v1/voice:streamBidirectional`\n}\n\n// TTS WS uses snake_case outbound (per Inworld's own JS sample). The\n// camelCase helper from `codec.ts` is built for the REST/JSON sync paths;\n// rewire the field names here for the WS path. Server responses come back\n// camelCase regardless — see `ResultBody` below.\nconst audioConfigSnake = (request: StreamSynthesizeRequest) =>\n Effect.map(audioConfigFor(request.outputFormat ?? defaultFormat, request.speed), (cfg) => ({\n audio_encoding: cfg.audioEncoding,\n ...(cfg.sampleRateHertz !== undefined && { sample_rate_hertz: cfg.sampleRateHertz }),\n ...(cfg.bitRate !== undefined && { bit_rate: cfg.bitRate }),\n ...(cfg.speakingRate !== undefined && { speaking_rate: cfg.speakingRate }),\n }))\n\nconst createFrame = (request: StreamSynthesizeRequest) =>\n Effect.map(audioConfigSnake(request), (audio_config) =>\n JSON.stringify({\n create: {\n voice_id: request.voiceId,\n model_id: request.model,\n audio_config,\n ...(request.languageCode !== undefined && { language: request.languageCode }),\n ...(request.deliveryMode !== undefined && { delivery_mode: request.deliveryMode }),\n ...(request.temperature !== undefined && { temperature: request.temperature }),\n ...(request.applyTextNormalization !== undefined && {\n apply_text_normalization: request.applyTextNormalization,\n }),\n },\n }),\n )\n\n// `flush_context: {}` inside `send_text` nudges the server to flush\n// pending audio promptly — matches the low-latency sample.\nconst sendTextFrame = (text: string) => JSON.stringify({ send_text: { text, flush_context: {} } })\nconst closeContextFrame = JSON.stringify({ close_context: {} })\n\n// ---------------------------------------------------------------------------\n// Wire schema (server → client)\n// ---------------------------------------------------------------------------\n\nconst ResultBody = Schema.Struct({\n audioChunk: Schema.optional(Schema.Struct({ audioContent: Schema.String })),\n contextCreated: Schema.optional(Schema.Unknown),\n flushCompleted: Schema.optional(Schema.Unknown),\n contextClosed: Schema.optional(Schema.Unknown),\n status: Schema.optional(Schema.Unknown),\n})\n\nconst ServerFrame = Schema.Struct({\n result: Schema.optional(ResultBody),\n error: Schema.optional(Schema.Unknown),\n})\nconst decodeServerFrame = Schema.decodeUnknownEffect(ServerFrame)\n\nconst handleServerFrame = (queue: Queue.Queue<AudioChunk, Cause.Done>) => (raw: string) =>\n Effect.gen(function* () {\n const json = yield* JSONL.parseSafe(raw)\n if (json === undefined) return\n const decoded = yield* decodeServerFrame(json).pipe(Effect.option)\n if (decoded._tag === \"None\") return\n const frame = decoded.value\n if (frame.error !== undefined) {\n yield* Effect.logWarning(\"[inworld-tts] server error frame\", { error: frame.error })\n return\n }\n const audio = frame.result?.audioChunk?.audioContent\n if (audio === undefined || audio === \"\") return\n const bytes = yield* decodeAudioContent(audio).pipe(Effect.option)\n if (bytes._tag === \"Some\") yield* Queue.offer(queue, { bytes: bytes.value })\n })\n\n// ---------------------------------------------------------------------------\n// Stream<string> → Stream<AudioChunk>\n// ---------------------------------------------------------------------------\n\nexport const streamSynthesis =\n (cfg: Config) =>\n <E, R>(\n textIn: Stream.Stream<string, E, R>,\n request: StreamSynthesizeRequest,\n ): Stream.Stream<AudioChunk, AiError.AiError | E, R> =>\n Stream.unwrap(\n Effect.gen(function* () {\n // Inline pronunciations are load-bearing (bucket 1) but there is no\n // single text to rewrite `/ipa/` into on a chunked stream. Reject\n // rather than silently drop; use sync `synthesize` for overrides.\n if (request.pronunciations !== undefined && request.pronunciations.length > 0) {\n return Stream.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"pronunciations\",\n reason:\n \"Inworld applies inline /ipa/ pronunciations on sync `synthesize` only; the incremental WS path streams text in chunks with no place to rewrite. Use `synthesize` for pronunciation overrides.\",\n }),\n )\n }\n const create = yield* createFrame(request)\n const socket = yield* Socket.makeWebSocket(buildWsUrl(cfg), {\n // Effect's Socket treats all close codes as errors by default —\n // whitelist standard clean-close codes (1000 / 1001 / 1005).\n closeCodeIsError: (code) => code !== 1000 && code !== 1001 && code !== 1005,\n }).pipe(Effect.provideService(Socket.WebSocketConstructor, authedWsConstructor(cfg.apiKey)))\n const queue = yield* Queue.bounded<AudioChunk, Cause.Done>(64)\n const write = yield* socket.writer\n\n // Writer: BOS `create` → drain text as `send_text` → `close_context`.\n // The reader fiber surfaces the remaining audio drained by the server\n // post-close and shuts the queue when the WS upstream closes.\n yield* Effect.gen(function* () {\n yield* write(create)\n yield* Stream.runForEach(textIn, (text) =>\n text.length === 0 ? Effect.void : write(sendTextFrame(text)),\n )\n yield* write(closeContextFrame)\n }).pipe(Effect.ignore, Effect.forkScoped)\n\n // `Queue.end` flushes pending chunks then fails the next take with\n // `Done` — clean stream end. `Queue.shutdown` would CLEAR queued items\n // and interrupt pending takes (wrong for graceful teardown).\n yield* socket\n .runString(handleServerFrame(queue))\n .pipe(Effect.ensuring(Queue.end(queue)), Effect.forkScoped)\n\n return Stream.fromQueue(queue)\n }),\n )\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuDA,MAAa,cAAc,QAAgB;AAEzC,QAAO,IADS,IAAI,WAAW,0BAA0B,QAAQ,SAAS,KAC1D,CAAC;;AAOnB,MAAM,oBAAoB,YACxB,OAAO,IAAI,eAAe,QAAQ,gBAAgB,eAAe,QAAQ,MAAM,GAAG,SAAS;CACzF,gBAAgB,IAAI;CACpB,GAAI,IAAI,oBAAoB,KAAA,KAAa,EAAE,mBAAmB,IAAI,iBAAiB;CACnF,GAAI,IAAI,YAAY,KAAA,KAAa,EAAE,UAAU,IAAI,SAAS;CAC1D,GAAI,IAAI,iBAAiB,KAAA,KAAa,EAAE,eAAe,IAAI,cAAc;CAC1E,EAAE;AAEL,MAAM,eAAe,YACnB,OAAO,IAAI,iBAAiB,QAAQ,GAAG,iBACrC,KAAK,UAAU,EACb,QAAQ;CACN,UAAU,QAAQ;CAClB,UAAU,QAAQ;CAClB;CACA,GAAI,QAAQ,iBAAiB,KAAA,KAAa,EAAE,UAAU,QAAQ,cAAc;CAC5E,GAAI,QAAQ,iBAAiB,KAAA,KAAa,EAAE,eAAe,QAAQ,cAAc;CACjF,GAAI,QAAQ,gBAAgB,KAAA,KAAa,EAAE,aAAa,QAAQ,aAAa;CAC7E,GAAI,QAAQ,2BAA2B,KAAA,KAAa,EAClD,0BAA0B,QAAQ,wBACnC;CACF,EACF,CAAC,CACH;AAIH,MAAM,iBAAiB,SAAiB,KAAK,UAAU,EAAE,WAAW;CAAE;CAAM,eAAe,EAAE;CAAE,EAAE,CAAC;AAClG,MAAM,oBAAoB,KAAK,UAAU,EAAE,eAAe,EAAE,EAAE,CAAC;AAM/D,MAAM,aAAa,OAAO,OAAO;CAC/B,YAAY,OAAO,SAAS,OAAO,OAAO,EAAE,cAAc,OAAO,QAAQ,CAAC,CAAC;CAC3E,gBAAgB,OAAO,SAAS,OAAO,QAAQ;CAC/C,gBAAgB,OAAO,SAAS,OAAO,QAAQ;CAC/C,eAAe,OAAO,SAAS,OAAO,QAAQ;CAC9C,QAAQ,OAAO,SAAS,OAAO,QAAQ;CACxC,CAAC;AAEF,MAAM,cAAc,OAAO,OAAO;CAChC,QAAQ,OAAO,SAAS,WAAW;CACnC,OAAO,OAAO,SAAS,OAAO,QAAQ;CACvC,CAAC;AACF,MAAM,oBAAoB,OAAO,oBAAoB,YAAY;AAEjE,MAAM,qBAAqB,WAAgD,QACzE,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,MAAM,UAAU,IAAI;AACxC,KAAI,SAAS,KAAA,EAAW;CACxB,MAAM,UAAU,OAAO,kBAAkB,KAAK,CAAC,KAAK,OAAO,OAAO;AAClE,KAAI,QAAQ,SAAS,OAAQ;CAC7B,MAAM,QAAQ,QAAQ;AACtB,KAAI,MAAM,UAAU,KAAA,GAAW;AAC7B,SAAO,OAAO,WAAW,oCAAoC,EAAE,OAAO,MAAM,OAAO,CAAC;AACpF;;CAEF,MAAM,QAAQ,MAAM,QAAQ,YAAY;AACxC,KAAI,UAAU,KAAA,KAAa,UAAU,GAAI;CACzC,MAAM,QAAQ,OAAO,mBAAmB,MAAM,CAAC,KAAK,OAAO,OAAO;AAClE,KAAI,MAAM,SAAS,OAAQ,QAAO,MAAM,MAAM,OAAO,EAAE,OAAO,MAAM,OAAO,CAAC;EAC5E;AAMJ,MAAa,mBACV,SAEC,QACA,YAEA,OAAO,OACL,OAAO,IAAI,aAAa;AAItB,KAAI,QAAQ,mBAAmB,KAAA,KAAa,QAAQ,eAAe,SAAS,EAC1E,QAAO,OAAO,KACZ,IAAI,QAAQ,YAAY;EACtB,UAAU;EACV,YAAY;EACZ,QACE;EACH,CAAC,CACH;CAEH,MAAM,SAAS,OAAO,YAAY,QAAQ;CAC1C,MAAM,SAAS,OAAO,OAAO,cAAc,WAAW,IAAI,EAAE,EAG1D,mBAAmB,SAAS,SAAS,OAAQ,SAAS,QAAQ,SAAS,MACxE,CAAC,CAAC,KAAK,OAAO,eAAe,OAAO,sBAAsB,oBAAoB,IAAI,OAAO,CAAC,CAAC;CAC5F,MAAM,QAAQ,OAAO,MAAM,QAAgC,GAAG;CAC9D,MAAM,QAAQ,OAAO,OAAO;AAK5B,QAAO,OAAO,IAAI,aAAa;AAC7B,SAAO,MAAM,OAAO;AACpB,SAAO,OAAO,WAAW,SAAS,SAChC,KAAK,WAAW,IAAI,OAAO,OAAO,MAAM,cAAc,KAAK,CAAC,CAC7D;AACD,SAAO,MAAM,kBAAkB;GAC/B,CAAC,KAAK,OAAO,QAAQ,OAAO,WAAW;AAKzC,QAAO,OACJ,UAAU,kBAAkB,MAAM,CAAC,CACnC,KAAK,OAAO,SAAS,MAAM,IAAI,MAAM,CAAC,EAAE,OAAO,WAAW;AAE7D,QAAO,OAAO,UAAU,MAAM;EAC9B,CACH"}
1
+ {"version":3,"file":"realtimeTts.mjs","names":[],"sources":["../src/realtimeTts.ts"],"sourcesContent":["/**\n * Inworld Realtime TTS — `wss://api.inworld.ai/tts/v1/voice:streamBidirectional`.\n *\n * Auth: `Authorization: Basic <API_KEY>` on the WS upgrade header (matches\n * Inworld's own JS sample). The docs mention a `?Authorization=…` query\n * variant but the server rejects it in practice. Setting headers needs the\n * `ws` peer dep (Node/Bun); see `./wsAuth.ts`.\n *\n * Wire shape (single-context per call):\n * client → server:\n * `{ \"create\": { voiceId, modelId, audioConfig, ... } }`\n * `{ \"send_text\": { \"text\": \"...\" } }` (repeated)\n * `{ \"close_context\": {} }` (text stream end)\n * server → client:\n * `{ \"result\": { \"contextCreated\": {...} } }` (handshake ack)\n * `{ \"result\": { \"audioChunk\": { \"audioContent\": \"<b64>\" } } }` (×N)\n * `{ \"result\": { \"contextClosed\": {...} } }` (final)\n *\n * Multi-context (`contextId`) is not surfaced here — one logical\n * utterance per call.\n */\nimport { Cause, Effect, Queue, Redacted, Schema, Stream } from \"effect\"\nimport * as Socket from \"effect/unstable/socket/Socket\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport type { AudioChunk, AudioFormat } from \"@effect-uai/core/Audio\"\nimport * as JSONL from \"@effect-uai/core/JSONL\"\nimport type { CustomPronunciation } from \"@effect-uai/core/SpeechSynthesizer\"\nimport { audioConfigFor, decodeAudioContent, defaultFormat } from \"./codec.js\"\nimport type { InworldDeliveryMode, InworldTtsModel, InworldVoiceId } from \"./models.js\"\nimport { authedWsConstructor } from \"./wsAuth.js\"\n\nexport type Config = { readonly apiKey: Redacted.Redacted; readonly baseUrl?: string }\n\n/**\n * Incremental-text-in request. Mirrors the sync request minus `text` (which\n * comes from the input stream).\n */\nexport type StreamSynthesizeRequest = {\n readonly model: InworldTtsModel\n readonly voiceId: InworldVoiceId\n readonly outputFormat?: AudioFormat\n readonly languageCode?: string\n readonly temperature?: number\n readonly deliveryMode?: InworldDeliveryMode\n readonly applyTextNormalization?: \"ON\" | \"OFF\"\n readonly speed?: number\n /** Carried from the Common request so the WS path can reject inline\n * pronunciations (no place to rewrite into a chunked text stream). */\n readonly pronunciations?: ReadonlyArray<CustomPronunciation>\n}\n\n// ---------------------------------------------------------------------------\n// URL + frame builders\n// ---------------------------------------------------------------------------\n\nexport const buildWsUrl = (cfg: Config) => {\n const wsBase = (cfg.baseUrl ?? \"https://api.inworld.ai\").replace(/^http/, \"ws\")\n return `${wsBase}/tts/v1/voice:streamBidirectional`\n}\n\n// TTS WS uses snake_case outbound (per Inworld's own JS sample). The\n// camelCase helper from `codec.ts` is built for the REST/JSON sync paths;\n// rewire the field names here for the WS path. Server responses come back\n// camelCase regardless — see `ResultBody` below.\nconst audioConfigSnake = (request: StreamSynthesizeRequest) =>\n Effect.map(audioConfigFor(request.outputFormat ?? defaultFormat, request.speed), (cfg) => ({\n audio_encoding: cfg.audioEncoding,\n ...(cfg.sampleRateHertz !== undefined && { sample_rate_hertz: cfg.sampleRateHertz }),\n ...(cfg.bitRate !== undefined && { bit_rate: cfg.bitRate }),\n ...(cfg.speakingRate !== undefined && { speaking_rate: cfg.speakingRate }),\n }))\n\nconst createFrame = (request: StreamSynthesizeRequest) =>\n Effect.map(audioConfigSnake(request), (audio_config) =>\n JSON.stringify({\n create: {\n voice_id: request.voiceId,\n model_id: request.model,\n audio_config,\n ...(request.languageCode !== undefined && { language: request.languageCode }),\n ...(request.deliveryMode !== undefined && { delivery_mode: request.deliveryMode }),\n ...(request.temperature !== undefined && { temperature: request.temperature }),\n ...(request.applyTextNormalization !== undefined && {\n apply_text_normalization: request.applyTextNormalization,\n }),\n },\n }),\n )\n\n// `flush_context: {}` inside `send_text` nudges the server to flush\n// pending audio promptly — matches the low-latency sample.\nconst sendTextFrame = (text: string) => JSON.stringify({ send_text: { text, flush_context: {} } })\nconst closeContextFrame = JSON.stringify({ close_context: {} })\n\n// ---------------------------------------------------------------------------\n// Wire schema (server → client)\n// ---------------------------------------------------------------------------\n\nconst ResultBody = Schema.Struct({\n audioChunk: Schema.optional(Schema.Struct({ audioContent: Schema.String })),\n contextCreated: Schema.optional(Schema.Unknown),\n flushCompleted: Schema.optional(Schema.Unknown),\n contextClosed: Schema.optional(Schema.Unknown),\n status: Schema.optional(Schema.Unknown),\n})\n\nconst ServerFrame = Schema.Struct({\n result: Schema.optional(ResultBody),\n error: Schema.optional(Schema.Unknown),\n})\nconst decodeServerFrame = Schema.decodeUnknownEffect(ServerFrame)\n\nconst handleServerFrame = (queue: Queue.Queue<AudioChunk, Cause.Done>) => (raw: string) =>\n Effect.gen(function* () {\n const json = yield* JSONL.parseSafe(raw)\n if (json === undefined) return\n const decoded = yield* decodeServerFrame(json).pipe(Effect.option)\n if (decoded._tag === \"None\") return\n const frame = decoded.value\n if (frame.error !== undefined) {\n yield* Effect.logWarning(\"[inworld-tts] server error frame\", { error: frame.error })\n return\n }\n const audio = frame.result?.audioChunk?.audioContent\n if (audio === undefined || audio === \"\") return\n const bytes = yield* decodeAudioContent(audio).pipe(Effect.option)\n if (bytes._tag === \"Some\") yield* Queue.offer(queue, { bytes: bytes.value })\n })\n\n// ---------------------------------------------------------------------------\n// Stream<string> → Stream<AudioChunk>\n// ---------------------------------------------------------------------------\n\nexport const streamSynthesis =\n (cfg: Config) =>\n <E, R>(\n textIn: Stream.Stream<string, E, R>,\n request: StreamSynthesizeRequest,\n ): Stream.Stream<AudioChunk, AiError.AiError | E, R> =>\n Stream.unwrap(\n Effect.gen(function* () {\n // Inline pronunciations are load-bearing (bucket 1) but there is no\n // single text to rewrite `/ipa/` into on a chunked stream. Reject\n // rather than silently drop; use sync `synthesize` for overrides.\n if (request.pronunciations !== undefined && request.pronunciations.length > 0) {\n return Stream.fail(\n new AiError.Unsupported({\n provider: \"inworld\",\n capability: \"pronunciations\",\n reason:\n \"Inworld applies inline /ipa/ pronunciations on sync `synthesize` only; the incremental WS path streams text in chunks with no place to rewrite. Use `synthesize` for pronunciation overrides.\",\n }),\n )\n }\n const create = yield* createFrame(request)\n const socket = yield* Socket.makeWebSocket(buildWsUrl(cfg), {\n // Effect's Socket treats all close codes as errors by default —\n // whitelist standard clean-close codes (1000 / 1001 / 1005).\n closeCodeIsError: (code) => code !== 1000 && code !== 1001 && code !== 1005,\n }).pipe(Effect.provideService(Socket.WebSocketConstructor, authedWsConstructor(cfg.apiKey)))\n const queue = yield* Queue.bounded<AudioChunk, Cause.Done>(64)\n const write = yield* socket.writer\n\n // Writer: BOS `create` → drain text as `send_text` → `close_context`.\n // The reader fiber surfaces the remaining audio drained by the server\n // post-close and shuts the queue when the WS upstream closes.\n yield* Effect.gen(function* () {\n yield* write(create)\n yield* Stream.runForEach(textIn, (text) =>\n text.length === 0 ? Effect.void : write(sendTextFrame(text)),\n )\n yield* write(closeContextFrame)\n }).pipe(Effect.ignore, Effect.forkScoped)\n\n // `Queue.end` flushes pending chunks then fails the next take with\n // `Done` — clean stream end. `Queue.shutdown` would CLEAR queued items\n // and interrupt pending takes (wrong for graceful teardown).\n yield* socket\n .runString(handleServerFrame(queue))\n .pipe(Effect.ensuring(Queue.end(queue)), Effect.forkScoped)\n\n return Stream.fromQueue(queue)\n }),\n )\n"],"mappings":"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"}
package/dist/wsAuth.d.mts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { Redacted } from "effect";
2
2
  import * as Socket from "effect/unstable/socket/Socket";
3
-
4
3
  //#region src/wsAuth.d.ts
5
4
  declare const authedWsConstructor: (apiKey: Redacted.Redacted) => Socket.WebSocketConstructor["Service"];
6
5
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"wsAuth.d.mts","names":[],"sources":["../src/wsAuth.ts"],"mappings":";;;;cAea,mBAAA,GACV,MAAA,EAAQ,QAAA,CAAS,QAAA,KAAW,MAAA,CAAO,oBAAA"}
1
+ {"version":3,"file":"wsAuth.d.mts","names":[],"sources":["../src/wsAuth.ts"],"mappings":";;;cAea,sBAAmB,QACrB,SAAS,aAAW,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"wsAuth.mjs","names":["WSWebSocket"],"sources":["../src/wsAuth.ts"],"sourcesContent":["/**\n * Inworld WS auth helper. The Inworld realtime endpoints (`/tts/...` and\n * `/stt/...`) require `Authorization: Basic <API_KEY>` on the WS upgrade\n * — the docs document a `?Authorization=…` query-param variant, but in\n * practice the server returns `authentication is required` for that\n * path. Header auth is what Inworld's own samples use.\n *\n * Headers on a WS upgrade aren't settable via `globalThis.WebSocket`, so\n * we use the `ws` peer dep (Node/Bun only).\n */\nimport { Redacted } from \"effect\"\nimport type * as Socket from \"effect/unstable/socket/Socket\"\nimport { WebSocket as WSWebSocket } from \"ws\"\nimport { authHeader } from \"./codec.js\"\n\nexport const authedWsConstructor =\n (apiKey: Redacted.Redacted): Socket.WebSocketConstructor[\"Service\"] =>\n (url) =>\n new WSWebSocket(url, undefined, {\n headers: { Authorization: authHeader(apiKey) },\n }) as unknown as globalThis.WebSocket\n"],"mappings":";;;AAeA,MAAa,uBACV,YACA,QACC,IAAIA,UAAY,KAAK,KAAA,GAAW,EAC9B,SAAS,EAAE,eAAe,WAAW,OAAO,EAAE,EAC/C,CAAC"}
1
+ {"version":3,"file":"wsAuth.mjs","names":["WSWebSocket"],"sources":["../src/wsAuth.ts"],"sourcesContent":["/**\n * Inworld WS auth helper. The Inworld realtime endpoints (`/tts/...` and\n * `/stt/...`) require `Authorization: Basic <API_KEY>` on the WS upgrade\n * — the docs document a `?Authorization=…` query-param variant, but in\n * practice the server returns `authentication is required` for that\n * path. Header auth is what Inworld's own samples use.\n *\n * Headers on a WS upgrade aren't settable via `globalThis.WebSocket`, so\n * we use the `ws` peer dep (Node/Bun only).\n */\nimport { Redacted } from \"effect\"\nimport type * as Socket from \"effect/unstable/socket/Socket\"\nimport { WebSocket as WSWebSocket } from \"ws\"\nimport { authHeader } from \"./codec.js\"\n\nexport const authedWsConstructor =\n (apiKey: Redacted.Redacted): Socket.WebSocketConstructor[\"Service\"] =>\n (url) =>\n new WSWebSocket(url, undefined, {\n headers: { Authorization: authHeader(apiKey) },\n }) as unknown as globalThis.WebSocket\n"],"mappings":";;;AAeA,MAAa,uBACV,YACA,QACC,IAAIA,UAAY,KAAK,KAAA,GAAW,EAC9B,SAAS,EAAE,eAAe,WAAW,MAAM,EAAE,EAC/C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-uai/inworld",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "Inworld speech-to-text and text-to-speech provider for @effect-uai/core.",
5
5
  "keywords": [
6
6
  "ai",
@@ -58,14 +58,14 @@
58
58
  },
59
59
  "devDependencies": {
60
60
  "@types/ws": "^8.5.13",
61
- "effect": "4.0.0-beta.94",
62
- "typescript": "^6.0.3",
61
+ "effect": "4.0.0-rc.111",
62
+ "typescript": "^7.0.2",
63
63
  "ws": "^8.18.0",
64
- "@effect-uai/core": "0.12.0"
64
+ "@effect-uai/core": "0.12.1"
65
65
  },
66
66
  "peerDependencies": {
67
67
  "@effect-uai/core": ">=0.2.0 <1",
68
- "effect": ">=4.0.0-beta.94 <5.0.0",
68
+ "effect": ">=4.0.0-rc.111 <5.0.0",
69
69
  "ws": "^8.0.0"
70
70
  },
71
71
  "peerDependenciesMeta": {
@@ -64,19 +64,15 @@ export const layer = (cfg: Config) =>
64
64
  Layer.effect(InworldSynthesizer, make(cfg)),
65
65
  Layer.effect(
66
66
  SpeechSynthesizer,
67
- Effect.map(
68
- make(cfg),
69
- (s): SpeechSynthesizerService => ({
70
- synthesize: (req: CommonSynthesizeRequest) =>
71
- s.synthesize(req as InworldSynthesizeRequest),
72
- streamSynthesis: (req: CommonSynthesizeRequest) =>
73
- s.streamSynthesis(req as InworldSynthesizeRequest),
74
- streamSynthesisFrom: (textIn, req: CommonStreamSynthesizeRequest) =>
75
- s.streamSynthesisFrom(textIn, req),
76
- synthesizeDialogue: s.synthesizeDialogue,
77
- streamSynthesizeDialogue: s.streamSynthesizeDialogue,
78
- }),
79
- ),
67
+ Effect.map(make(cfg), (s): SpeechSynthesizerService => ({
68
+ synthesize: (req: CommonSynthesizeRequest) => s.synthesize(req as InworldSynthesizeRequest),
69
+ streamSynthesis: (req: CommonSynthesizeRequest) =>
70
+ s.streamSynthesis(req as InworldSynthesizeRequest),
71
+ streamSynthesisFrom: (textIn, req: CommonStreamSynthesizeRequest) =>
72
+ s.streamSynthesisFrom(textIn, req),
73
+ synthesizeDialogue: s.synthesizeDialogue,
74
+ streamSynthesizeDialogue: s.streamSynthesizeDialogue,
75
+ })),
80
76
  ),
81
77
  Layer.succeed(TtsIncrementalText, undefined),
82
78
  )
@@ -51,14 +51,10 @@ export const layer = (cfg: Config) =>
51
51
  Layer.effect(InworldTranscriber, make(cfg)),
52
52
  Layer.effect(
53
53
  Transcriber,
54
- Effect.map(
55
- make(cfg),
56
- (s): TranscriberService => ({
57
- transcribe: (req: CommonTranscribeRequest) =>
58
- s.transcribe(req as InworldTranscribeRequest),
59
- streamTranscriptionFrom: s.streamTranscriptionFrom,
60
- }),
61
- ),
54
+ Effect.map(make(cfg), (s): TranscriberService => ({
55
+ transcribe: (req: CommonTranscribeRequest) => s.transcribe(req as InworldTranscribeRequest),
56
+ streamTranscriptionFrom: s.streamTranscriptionFrom,
57
+ })),
62
58
  ),
63
59
  Layer.succeed(SttStreaming, undefined),
64
60
  )
@@ -265,17 +265,13 @@ export const layer = (
265
265
  Layer.effect(InworldSynthesizer, make(cfg)),
266
266
  Layer.effect(
267
267
  SpeechSynthesizer,
268
- Effect.map(
269
- make(cfg),
270
- (s): SpeechSynthesizerService => ({
271
- synthesize: (req: CommonSynthesizeRequest) =>
272
- s.synthesize(req as InworldSynthesizeRequest),
273
- streamSynthesis: (req: CommonSynthesizeRequest) =>
274
- s.streamSynthesis(req as InworldSynthesizeRequest),
275
- streamSynthesisFrom: s.streamSynthesisFrom,
276
- synthesizeDialogue: s.synthesizeDialogue,
277
- streamSynthesizeDialogue: s.streamSynthesizeDialogue,
278
- }),
279
- ),
268
+ Effect.map(make(cfg), (s): SpeechSynthesizerService => ({
269
+ synthesize: (req: CommonSynthesizeRequest) => s.synthesize(req as InworldSynthesizeRequest),
270
+ streamSynthesis: (req: CommonSynthesizeRequest) =>
271
+ s.streamSynthesis(req as InworldSynthesizeRequest),
272
+ streamSynthesisFrom: s.streamSynthesisFrom,
273
+ synthesizeDialogue: s.synthesizeDialogue,
274
+ streamSynthesizeDialogue: s.streamSynthesizeDialogue,
275
+ })),
280
276
  ),
281
277
  )
@@ -216,13 +216,9 @@ export const layer = (
216
216
  Layer.effect(InworldTranscriber, make(cfg)),
217
217
  Layer.effect(
218
218
  Transcriber,
219
- Effect.map(
220
- make(cfg),
221
- (s): TranscriberService => ({
222
- transcribe: (req: CommonTranscribeRequest) =>
223
- s.transcribe(req as InworldTranscribeRequest),
224
- streamTranscriptionFrom: s.streamTranscriptionFrom,
225
- }),
226
- ),
219
+ Effect.map(make(cfg), (s): TranscriberService => ({
220
+ transcribe: (req: CommonTranscribeRequest) => s.transcribe(req as InworldTranscribeRequest),
221
+ streamTranscriptionFrom: s.streamTranscriptionFrom,
222
+ })),
227
223
  ),
228
224
  )
@@ -1 +0,0 @@
1
- {"version":3,"file":"codec-C-2ssVAz.d.mts","names":[],"sources":["../src/codec.ts"],"mappings":";;;;;;;;;cAUa,UAAA,GAAc,MAAA,EAAQ,QAAA,CAAS,QAAA;AAAA,KAMhC,WAAA;EAAA,SACD,aAAA,EAAe,oBAAA;EAAA,SACf,eAAA;EAAA,SACA,OAAA;EAAA,SACA,YAAA;AAAA;;;;;;;AAVX;;;cA6Ba,gBAAA,GACX,MAAA,EAAQ,WAAA,KACL,MAAA,CAAO,MAAA,CAAO,oBAAA,EAAsB,OAAA,CAAQ,OAAA;AAAA,cAoBpC,cAAA,GACX,MAAA,EAAQ,WAAA,EACR,YAAA,cACC,MAAA,CAAO,MAAA,CAAO,WAAA,EAAa,OAAA,CAAQ,OAAA;;cASzB,aAAA,EAAe,WAAA;AAAA,cAUf,kBAAA,GAAsB,GAAA,aAAc,MAAA,CAAO,MAAA,CAAO,UAAA,EAAY,OAAA,CAAQ,OAAA;AAAA,cAgBtE,eAAA,GAAkB,MAAA,UAAgB,IAAA,aAAiB,OAAA,CAAQ,OAAA;AAAA,cAwC3D,gBAAA,GAAoB,KAAA,cAAiB,OAAA,CAAQ,OAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"models-CPLZDcgt.d.mts","names":[],"sources":["../src/models.ts"],"mappings":";;AAYA;;;;;AAaA;;;;;AAWA;KAxBY,eAAA;;;;AAuCZ;;;KA1BY,cAAA;;AAmCZ;;;;;;;;KAxBY,eAAA;;;;;KAeA,mBAAA;;;;;;;;KASA,oBAAA"}