@effect-uai/inworld 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/InworldRealtimeSynthesizer.d.mts +1 -1
  2. package/dist/InworldRealtimeSynthesizer.mjs +2 -2
  3. package/dist/InworldRealtimeSynthesizer.mjs.map +1 -1
  4. package/dist/InworldRealtimeTranscriber.d.mts +1 -1
  5. package/dist/InworldRealtimeTranscriber.mjs +2 -2
  6. package/dist/InworldRealtimeTranscriber.mjs.map +1 -1
  7. package/dist/InworldSynthesizer.d.mts +1 -1
  8. package/dist/InworldSynthesizer.mjs +2 -2
  9. package/dist/InworldSynthesizer.mjs.map +1 -1
  10. package/dist/InworldTranscriber.d.mts +1 -1
  11. package/dist/InworldTranscriber.d.mts.map +1 -1
  12. package/dist/InworldTranscriber.mjs +5 -4
  13. package/dist/InworldTranscriber.mjs.map +1 -1
  14. package/dist/codec-BU4azW_k.d.mts.map +1 -1
  15. package/dist/codec.mjs +4 -3
  16. package/dist/codec.mjs.map +1 -1
  17. package/dist/dist-Cu2gIMHV.mjs +17453 -0
  18. package/dist/dist-Cu2gIMHV.mjs.map +1 -0
  19. package/dist/dist-DHer1cql.mjs +1533 -0
  20. package/dist/dist-DHer1cql.mjs.map +1 -0
  21. package/dist/realtimeStt.d.mts +6 -0
  22. package/dist/realtimeStt.d.mts.map +1 -1
  23. package/dist/realtimeStt.mjs +18 -19
  24. package/dist/realtimeStt.mjs.map +1 -1
  25. package/dist/realtimeStt.test.d.mts +1 -0
  26. package/dist/realtimeStt.test.mjs +83 -0
  27. package/dist/realtimeStt.test.mjs.map +1 -0
  28. package/dist/realtimeTts.d.mts +6 -0
  29. package/dist/realtimeTts.d.mts.map +1 -1
  30. package/dist/realtimeTts.mjs +18 -17
  31. package/dist/realtimeTts.mjs.map +1 -1
  32. package/dist/realtimeTts.test.d.mts +1 -0
  33. package/dist/realtimeTts.test.mjs +70 -0
  34. package/dist/realtimeTts.test.mjs.map +1 -0
  35. package/dist/{rolldown-runtime-D7D4PA-g.mjs → rolldown-runtime-EAsCxrDo.mjs} +2 -1
  36. package/dist/wsAuth.d.mts +1 -1
  37. package/dist/wsAuth.mjs.map +1 -1
  38. package/package.json +4 -4
  39. package/src/InworldRealtimeSynthesizer.ts +1 -1
  40. package/src/InworldRealtimeTranscriber.ts +1 -1
  41. package/src/InworldSynthesizer.ts +1 -1
  42. package/src/InworldTranscriber.ts +4 -3
  43. package/src/codec.ts +3 -2
  44. package/src/realtimeStt.test.ts +82 -0
  45. package/src/realtimeStt.ts +46 -36
  46. package/src/realtimeTts.test.ts +74 -0
  47. package/src/realtimeTts.ts +52 -36
  48. package/src/wsAuth.ts +1 -1
@@ -1,6 +1,6 @@
1
1
  import { Config, InworldSynthesizeRequest, InworldSynthesizer, InworldSynthesizerService } from "./InworldSynthesizer.mjs";
2
2
  import { Effect, Layer, Stream } from "effect";
3
- import { HttpClient } from "effect/unstable/http";
3
+ import { HttpClient } from "effect/http";
4
4
  import { CommonStreamSynthesizeRequest, SpeechSynthesizer, TtsIncrementalText } from "@effect-uai/core/SpeechSynthesizer";
5
5
  declare namespace InworldRealtimeSynthesizer_d_exports {
6
6
  export { Config, InworldSynthesizeRequest, InworldSynthesizer, InworldSynthesizerService, layer, make };
@@ -1,8 +1,8 @@
1
- import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
1
+ import { n as __exportAll } from "./rolldown-runtime-EAsCxrDo.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";
5
- import { HttpClient } from "effect/unstable/http";
5
+ import { HttpClient } from "effect/http";
6
6
  import { SpeechSynthesizer, TtsIncrementalText } from "@effect-uai/core/SpeechSynthesizer";
7
7
  //#region src/InworldRealtimeSynthesizer.ts
8
8
  /**
@@ -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(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
+ {"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/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,6 +1,6 @@
1
1
  import { Config, InworldTranscribeRequest, InworldTranscriber, InworldTranscriberService } from "./InworldTranscriber.mjs";
2
2
  import { Effect, Layer } from "effect";
3
- import { HttpClient } from "effect/unstable/http";
3
+ import { HttpClient } from "effect/http";
4
4
  import { SttStreaming, Transcriber } from "@effect-uai/core/Transcriber";
5
5
  declare namespace InworldRealtimeTranscriber_d_exports {
6
6
  export { Config, InworldTranscribeRequest, InworldTranscriber, InworldTranscriberService, layer, make };
@@ -1,8 +1,8 @@
1
- import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
1
+ import { n as __exportAll } from "./rolldown-runtime-EAsCxrDo.mjs";
2
2
  import { InworldTranscriber, transcribeImpl } from "./InworldTranscriber.mjs";
3
3
  import { streamTranscription } from "./realtimeStt.mjs";
4
4
  import { Effect, Layer } from "effect";
5
- import { HttpClient } from "effect/unstable/http";
5
+ import { HttpClient } from "effect/http";
6
6
  import { SttStreaming, Transcriber } from "@effect-uai/core/Transcriber";
7
7
  //#region src/InworldRealtimeTranscriber.ts
8
8
  /**
@@ -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(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
+ {"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/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,7 +1,7 @@
1
1
  import { a as InworldVoiceId, i as InworldTtsModel, n as InworldDeliveryMode } from "./models-DySX9PVy.mjs";
2
2
  import { t as AudioConfig } from "./codec-BU4azW_k.mjs";
3
3
  import { Context, Effect, Layer, Redacted, Stream } from "effect";
4
- import { HttpClient } from "effect/unstable/http";
4
+ import { HttpClient } from "effect/http";
5
5
  import { CommonSynthesizeRequest, SpeechSynthesizer, SpeechSynthesizerService } from "@effect-uai/core/SpeechSynthesizer";
6
6
  import * as AiError from "@effect-uai/core/AiError";
7
7
  import { AudioBlob, AudioChunk } from "@effect-uai/core/Audio";
@@ -1,7 +1,7 @@
1
- import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
1
+ import { n as __exportAll } from "./rolldown-runtime-EAsCxrDo.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
- import { HttpClient, HttpClientRequest } from "effect/unstable/http";
4
+ import { HttpClient, HttpClientRequest } from "effect/http";
5
5
  import { SpeechSynthesizer } from "@effect-uai/core/SpeechSynthesizer";
6
6
  import * as AiError from "@effect-uai/core/AiError";
7
7
  import * as JSONL from "@effect-uai/core/JSONL";
@@ -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(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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiEA,IAAa,qBAAb,cAAwC,QAAQ,QAG9C,CAAC,CAAC,2DAA2D,CAAC,CAAC,CAAC;;;;;;;AAclE,MAAM,kBAAkB,MAAsB,EAAE,QAAQ,uBAAuB,MAAM;AAErF,MAAM,uBACJ,MACA,mBACW;CACX,IAAI,mBAAmB,KAAA,GAAW,OAAO;CACzC,OAAOA,MAAI,OAAO,gBAAgB,OAAO,KAAK,MAC5C,IAAI,QAAQ,IAAI,OAAO,MAAM,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,IAAI,EAAE,cAAc,EAAE,CAC1F;AACF;;AAGA,MAAa,aAAa,MACxB,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,EAAE,gBAAgB;CACjC,MAAM,cAAc,OAAO,eAAe,QAAQ,EAAE,KAAK;CAazD,OAAO;EAAE,MAAA;GAXP,MAAM,oBAAoB,EAAE,MAAM,EAAE,cAAc;GAClD,SAAS,EAAE;GACX,SAAS,EAAE;GACX;GACA,GAAI,EAAE,iBAAiB,KAAA,KAAa,EAAE,UAAU,EAAE,aAAa;GAC/D,GAAI,EAAE,iBAAiB,KAAA,KAAa,EAAE,cAAc,EAAE,aAAa;GACnE,GAAI,EAAE,gBAAgB,KAAA,KAAa,EAAE,aAAa,EAAE,YAAY;GAChE,GAAI,EAAE,2BAA2B,KAAA,KAAa,EAC5C,wBAAwB,EAAE,uBAC5B;EAEU;EAAG;CAAO;AACxB,CAAC;AAMH,MAAM,eAAe,OAAO,OAAO,EAAE,cAAc,OAAO,OAAO,CAAC;AAClE,MAAM,qBAAqB,OAAO,oBAAoB,YAAY;AAElE,MAAM,aAAa,OAAO,OAAO;CAC/B,QAAQ,OAAO,SAAS,OAAO,OAAO,EAAE,cAAc,OAAO,SAAS,OAAO,MAAM,EAAE,CAAC,CAAC;CACvF,OAAO,OAAO,SAAS,OAAO,OAAO;AACvC,CAAC;AAMD,MAAM,WAAW,QAAgB,IAAI,WAAW;AAEhD,MAAM,gBAAgB,KAAa,MAAgD,SACjF,kBAAkB,KAAK,GAAG,QAAQ,GAAG,IAAI,MAAM,CAAC,CAAC,KAC/C,kBAAkB,UAAU,iBAAiB,WAAW,IAAI,MAAM,CAAC,GACnE,kBAAkB,eAAe,IAAI,CACvC;;AAGF,MAAa,kBAAkB,SAAiB,YAC9C,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,WAAW;CACjC,MAAM,EAAE,MAAM,WAAW,OAAO,UAAU,OAAO;CACjD,MAAM,cAAc,aAAa,KAAK,iBAAiB,IAAI;CAC3D,MAAM,WAAW,OAAO,OAAO,QAAQ,WAAW,CAAC,CAAC,KAAK,OAAO,SAAS,gBAAgB,CAAC;CAC1F,IAAI,SAAS,UAAU,KAAK;EAC1B,MAAM,OAAO,OAAO,SAAS,KAAK,KAAK,OAAO,oBAAoB,EAAE,CAAC;EACrE,OAAO,OAAO,OAAO,KAAK,gBAAgB,SAAS,QAAQ,IAAI,CAAC;CAClE;CACA,MAAM,OAAO,OAAO,SAAS,KAAK,KAAK,OAAO,SAAS,gBAAgB,CAAC;CACxE,MAAM,OAAO,OAAO,mBAAmB,IAAI,CAAC,CAAC,KAC3C,OAAO,UACJ,UACC,IAAI,QAAQ,iBAAiB;EAC3B,UAAU;EACV,KAAK;GAAE,SAAS;GAA4C;GAAO;EAAK;CAC1E,CAAC,CACL,CACF;CAEA,OAAO;EAAE;EAAQ,OAAA,OADI,mBAAmB,KAAK,YAAY;CAClC;AACzB,CAAC;AAEH,MAAM,gBAAgB,SAA6E;CACjG,IAAI,KAAK,UAAU,KAAA,GACjB,OAAO,OAAO,KAAK,IAAI,QAAQ,iBAAiB;EAAE,UAAU;EAAW,KAAK,KAAK;CAAM,CAAC,CAAC;CAE3F,MAAM,MAAM,KAAK,QAAQ;CACzB,IAAI,QAAQ,KAAA,GAAW,OAAO,OAAO;CACrC,OAAO,OAAO,WACZ,mBAAmB,GAAG,CAAC,CAAC,KAAK,OAAO,KAAK,WAAuB,EAAE,MAAM,EAAE,CAAC,CAC7E;AACF;;AAGA,MAAa,uBAAuB,SAAiB,YACnD,OAAO,OACL,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,WAAW;CACjC,MAAM,EAAE,SAAS,OAAO,UAAU,OAAO;CACzC,MAAM,cAAc,aAAa,KAAK,wBAAwB,IAAI;CAClE,MAAM,WAAW,OAAO,OAAO,QAAQ,WAAW,CAAC,CAAC,KAAK,OAAO,SAAS,gBAAgB,CAAC;CAC1F,IAAI,SAAS,UAAU,KAAK;EAC1B,MAAM,OAAO,OAAO,SAAS,KAAK,KAAK,OAAO,oBAAoB,EAAE,CAAC;EACrE,OAAO,OAAO,KAAK,gBAAgB,SAAS,QAAQ,IAAI,CAAC;CAC3D;CACA,OAAO,SAAS,OAAO,KACrB,OAAO,SAAS,gBAAgB,GAChC,MAAM,WACN,MAAM,MAAM,UAAU,GACtB,OAAO,UACJ,UACC,IAAI,QAAQ,iBAAiB;EAC3B,UAAU;EACV,KAAK;GAAE,SAAS;GAAuB;EAAM;CAC/C,CAAC,CACL,GACA,OAAO,QAAQ,YAAY,CAC7B;AACF,CAAC,CACH;AAEF,MAAM,qBACJ,SACA,aACsD;CAStD,OARgE,OAAO,KACrE,IAAI,QAAQ,YAAY;EACtB,UAAU;EACV,YAAY;EACZ,QACE;CACJ,CAAC,CAEO;AACZ;;AAGA,MAAa,gCACX,OAAO,KACL,IAAI,QAAQ,YAAY;CACtB,UAAU;CACV,YAAY;CACZ,QAAQ;AACV,CAAC,CACH;;AAGF,MAAa,sCAET,OAAO,KACL,IAAI,QAAQ,YAAY;CACtB,UAAU;CACV,YAAY;CACZ,QAAQ;AACV,CAAC,CACH;AAMJ,MAAa,QACX,QAEA,OAAO,IAAI,WAAW,aAAa,YAAY;CAC7C,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,qBAAqB;CACrB,oBAAoB;CACpB,0BAA0B;AAC5B,EAAE;;;;;;AAOJ,MAAa,SACX,QAEA,MAAM,MACJ,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,qBAAqB,EAAE;CACvB,oBAAoB,EAAE;CACtB,0BAA0B,EAAE;AAC9B,EAAE,CACJ,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/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,6 +1,6 @@
1
1
  import { r as InworldSttModel } from "./models-DySX9PVy.mjs";
2
2
  import { Context, Effect, Layer, Redacted, Schema } from "effect";
3
- import { HttpClient } from "effect/unstable/http";
3
+ import { HttpClient } from "effect/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";
@@ -1 +1 @@
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
+ {"version":3,"file":"InworldTranscriber.d.mts","names":[],"sources":["../src/InworldTranscriber.ts"],"mappings":";;;;;;;;;;;;;;KAmCY,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,8 +1,9 @@
1
- import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
1
+ import { n as __exportAll } from "./rolldown-runtime-EAsCxrDo.mjs";
2
2
  import { authHeader, httpStatusError, transportFailure } from "./codec.mjs";
3
- import { Context, Effect, Encoding, Layer, Match, Schema, Stream } from "effect";
4
- import { HttpClient, HttpClientRequest } from "effect/unstable/http";
3
+ import { Context, Effect, Layer, Match, Schema, Stream } from "effect";
4
+ import { HttpClient, HttpClientRequest } from "effect/http";
5
5
  import * as AiError from "@effect-uai/core/AiError";
6
+ import { Base64 } from "effect/encoding";
6
7
  import { Transcriber } from "@effect-uai/core/Transcriber";
7
8
  import * as Capabilities from "@effect-uai/core/Capabilities";
8
9
  //#region src/InworldTranscriber.ts
@@ -28,7 +29,7 @@ const urlNotSupported = new AiError.InvalidRequest({
28
29
  param: "audio",
29
30
  raw: "Inworld accepts only inline base64. Fetch the URL yourself and pass `{ _tag: \"bytes\", bytes, mimeType }`."
30
31
  });
31
- const audioToBase64 = Match.type().pipe(Match.tag("bytes", (a) => Effect.succeed(Encoding.encodeBase64(a.bytes))), Match.tag("base64", (a) => Effect.succeed(a.base64)), Match.tag("url", () => Effect.fail(urlNotSupported)), Match.exhaustive);
32
+ const audioToBase64 = Match.type().pipe(Match.tag("bytes", (a) => Effect.succeed(Base64.encode(a.bytes))), Match.tag("base64", (a) => Effect.succeed(a.base64)), Match.tag("url", () => Effect.fail(urlNotSupported)), Match.exhaustive);
32
33
  const buildBody = (request) => Effect.gen(function* () {
33
34
  const content = yield* audioToBase64(request.audio);
34
35
  yield* Capabilities.warnDroppedWhen(request.prompt, {
@@ -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(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
+ {"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, Layer, Match, Redacted, Schema, Stream } from \"effect\"\nimport { Base64 } from \"effect/encoding\"\nimport { HttpClient, HttpClientRequest } from \"effect/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(Base64.encode(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 +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"}
1
+ {"version":3,"file":"codec-BU4azW_k.d.mts","names":[],"sources":["../src/codec.ts"],"mappings":";;;;;;;cAWa,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.mjs CHANGED
@@ -1,6 +1,7 @@
1
- import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { Effect, Encoding, Match, Redacted, Result } from "effect";
1
+ import { n as __exportAll } from "./rolldown-runtime-EAsCxrDo.mjs";
2
+ import { Effect, Match, Redacted, Result } from "effect";
3
3
  import * as AiError from "@effect-uai/core/AiError";
4
+ import { Base64 } from "effect/encoding";
4
5
  //#region src/codec.ts
5
6
  var codec_exports = /* @__PURE__ */ __exportAll({
6
7
  audioConfigFor: () => audioConfigFor,
@@ -51,7 +52,7 @@ const defaultFormat = {
51
52
  encoding: "mp3",
52
53
  sampleRate: 24e3
53
54
  };
54
- const decodeAudioContent = (b64) => Result.match(Encoding.decodeBase64(b64), {
55
+ const decodeAudioContent = (b64) => Result.match(Base64.decode(b64), {
55
56
  onSuccess: Effect.succeed,
56
57
  onFailure: (cause) => Effect.fail(new AiError.GenerationFailed({
57
58
  provider: "inworld",
@@ -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,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"}
1
+ {"version":3,"file":"codec.mjs","names":[],"sources":["../src/codec.ts"],"sourcesContent":["import { Effect, Match, Redacted, Result } from \"effect\"\nimport { Base64 } from \"effect/encoding\"\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(Base64.decode(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":";;;;;;;;;;;;;;AAWA,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,OAAO,OAAO,GAAG,GAAG;CAC/B,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"}