@effect-uai/core 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.
- package/dist/{AiError-Bf1pq4BB.d.mts → AiError-eLV9t1lU.d.mts} +12 -16
- package/dist/AiError-eLV9t1lU.d.mts.map +1 -0
- package/dist/{Audio-CR7CSljJ.d.mts → Audio-60lKKHxS.d.mts} +4 -5
- package/dist/Audio-60lKKHxS.d.mts.map +1 -0
- package/dist/{Image-C4vuBmu0.d.mts → Image-BK8-4H6s.d.mts} +12 -14
- package/dist/Image-BK8-4H6s.d.mts.map +1 -0
- package/dist/{Items-BKQgqJ8A.d.mts → Items-SfUabNuB.d.mts} +74 -76
- package/dist/Items-SfUabNuB.d.mts.map +1 -0
- package/dist/{Loop-D8nWpowc.d.mts → Loop-B54AB1ME.d.mts} +19 -21
- package/dist/Loop-B54AB1ME.d.mts.map +1 -0
- package/dist/{Media-D_CpcM1Z.d.mts → Media-DwgpifPD.d.mts} +1 -1
- package/dist/Media-DwgpifPD.d.mts.map +1 -0
- package/dist/{SandboxError-CIrVDOMV.d.mts → SandboxError-BN8b28Bh.d.mts} +11 -15
- package/dist/SandboxError-BN8b28Bh.d.mts.map +1 -0
- package/dist/{StructuredFormat-DHaUJBdd.d.mts → StructuredFormat-BlZhyOsi.d.mts} +3 -7
- package/dist/StructuredFormat-BlZhyOsi.d.mts.map +1 -0
- package/dist/{Tool-u5bag8SO.d.mts → Tool-DE-rnvkw.d.mts} +5 -8
- package/dist/Tool-DE-rnvkw.d.mts.map +1 -0
- package/dist/{ToolEvent-BBfOdhF_.d.mts → ToolEvent-D99MGQYH.d.mts} +56 -63
- package/dist/ToolEvent-D99MGQYH.d.mts.map +1 -0
- package/dist/{ToolResult-CRpmkBXR.d.mts → ToolResult-Cj8ChodL.d.mts} +49 -54
- package/dist/ToolResult-Cj8ChodL.d.mts.map +1 -0
- package/dist/{Toolkit-D4mQvhjq.d.mts → Toolkit-BEZrNPTI.d.mts} +13 -16
- package/dist/Toolkit-BEZrNPTI.d.mts.map +1 -0
- package/dist/browser/Browser.d.mts +11 -7
- package/dist/browser/Browser.d.mts.map +1 -1
- package/dist/browser/Browser.mjs +1 -1
- package/dist/browser/Browser.mjs.map +1 -1
- package/dist/browser/BrowserError.d.mts +9 -13
- package/dist/browser/BrowserError.d.mts.map +1 -1
- package/dist/browser/BrowserError.mjs +1 -1
- package/dist/browser/BrowserError.mjs.map +1 -1
- package/dist/browser/BrowserTool.d.mts +33 -36
- package/dist/browser/BrowserTool.d.mts.map +1 -1
- package/dist/browser/BrowserTool.mjs +1 -1
- package/dist/browser/BrowserTool.mjs.map +1 -1
- package/dist/capabilities/Capabilities.d.mts +8 -6
- package/dist/capabilities/Capabilities.d.mts.map +1 -1
- package/dist/capabilities/Capabilities.mjs +1 -1
- package/dist/capabilities/Capabilities.mjs.map +1 -1
- package/dist/dist-BaenoU1A.mjs +145 -0
- package/dist/dist-BaenoU1A.mjs.map +1 -0
- package/dist/{dist-C0m0QnUP.mjs → dist-nohcnkD6.mjs} +16 -15
- package/dist/dist-nohcnkD6.mjs.map +1 -0
- package/dist/domain/AiError.d.mts +1 -1
- package/dist/domain/AiError.mjs +1 -1
- package/dist/domain/AiError.mjs.map +1 -1
- package/dist/domain/Audio.d.mts +1 -1
- package/dist/domain/Audio.mjs +1 -1
- package/dist/domain/Citation.d.mts +0 -2
- package/dist/domain/Citation.d.mts.map +1 -1
- package/dist/domain/Citation.mjs +1 -1
- package/dist/domain/Image.d.mts +1 -1
- package/dist/domain/Image.mjs +1 -1
- package/dist/domain/Image.mjs.map +1 -1
- package/dist/domain/Items.d.mts +1 -1
- package/dist/domain/Items.mjs +1 -1
- package/dist/domain/Items.mjs.map +1 -1
- package/dist/domain/Media.d.mts +1 -1
- package/dist/domain/Media.mjs +1 -1
- package/dist/domain/Music.d.mts +18 -11
- package/dist/domain/Music.d.mts.map +1 -1
- package/dist/domain/Music.mjs +1 -1
- package/dist/domain/Music.mjs.map +1 -1
- package/dist/domain/Research.d.mts +3 -4
- package/dist/domain/Research.d.mts.map +1 -1
- package/dist/domain/Research.mjs +1 -1
- package/dist/domain/Transcript.d.mts +2 -3
- package/dist/domain/Transcript.d.mts.map +1 -1
- package/dist/domain/Transcript.mjs +1 -1
- package/dist/domain/Turn.d.mts +143 -164
- package/dist/domain/Turn.d.mts.map +1 -1
- package/dist/domain/Turn.mjs +1 -1
- package/dist/domain/Turn.mjs.map +1 -1
- package/dist/domain/Turn.test.d.mts +1 -1
- package/dist/domain/Turn.test.mjs +28 -18
- package/dist/domain/Turn.test.mjs.map +1 -1
- package/dist/embedding-model/Embedding.d.mts +1 -3
- package/dist/embedding-model/Embedding.d.mts.map +1 -1
- package/dist/embedding-model/Embedding.mjs +1 -1
- package/dist/embedding-model/EmbeddingModel.d.mts +1 -3
- package/dist/embedding-model/EmbeddingModel.d.mts.map +1 -1
- package/dist/embedding-model/EmbeddingModel.mjs +1 -1
- package/dist/embedding-model/EmbeddingModel.mjs.map +1 -1
- package/dist/embedding-model/EmbeddingModel.test.d.mts +1 -1
- package/dist/embedding-model/EmbeddingModel.test.mjs +14 -9
- package/dist/embedding-model/EmbeddingModel.test.mjs.map +1 -1
- package/dist/index.d.mts +12 -12
- package/dist/job/Job.d.mts +4 -4
- package/dist/job/Job.d.mts.map +1 -1
- package/dist/job/Job.mjs +1 -1
- package/dist/job/Job.mjs.map +1 -1
- package/dist/language-model/LanguageModel.d.mts +4 -6
- package/dist/language-model/LanguageModel.d.mts.map +1 -1
- package/dist/language-model/LanguageModel.mjs +1 -1
- package/dist/language-model/LanguageModel.mjs.map +1 -1
- package/dist/language-model/LanguageModel.test.d.mts +1 -1
- package/dist/language-model/LanguageModel.test.mjs +6 -3
- package/dist/language-model/LanguageModel.test.mjs.map +1 -1
- package/dist/loop/Loop.d.mts +1 -1
- package/dist/loop/Loop.mjs +1 -1
- package/dist/loop/Loop.mjs.map +1 -1
- package/dist/loop/Loop.test.d.mts +1 -1
- package/dist/loop/Loop.test.mjs +60 -34
- package/dist/loop/Loop.test.mjs.map +1 -1
- package/dist/{magic-string.es-Dk-MMA0F.mjs → magic-string.es-CB2hOw9v.mjs} +14 -13
- package/dist/{magic-string.es-Dk-MMA0F.mjs.map → magic-string.es-CB2hOw9v.mjs.map} +1 -1
- package/dist/math/Vector.d.mts +0 -2
- package/dist/math/Vector.d.mts.map +1 -1
- package/dist/math/Vector.mjs +1 -1
- package/dist/math/Vector.mjs.map +1 -1
- package/dist/music-generator/MusicGenerator.d.mts +2 -4
- package/dist/music-generator/MusicGenerator.d.mts.map +1 -1
- package/dist/music-generator/MusicGenerator.mjs +1 -1
- package/dist/music-generator/MusicGenerator.mjs.map +1 -1
- package/dist/music-generator/MusicGenerator.test.d.mts +1 -1
- package/dist/music-generator/MusicGenerator.test.mjs +19 -10
- package/dist/music-generator/MusicGenerator.test.mjs.map +1 -1
- package/dist/observability/Metrics.d.mts +10 -7
- package/dist/observability/Metrics.d.mts.map +1 -1
- package/dist/observability/Metrics.mjs +1 -1
- package/dist/observability/Metrics.mjs.map +1 -1
- package/dist/observability/Metrics.test.d.mts +1 -1
- package/dist/observability/Metrics.test.mjs +50 -28
- package/dist/observability/Metrics.test.mjs.map +1 -1
- package/dist/observability/Telemetry.d.mts +2 -3
- package/dist/observability/Telemetry.d.mts.map +1 -1
- package/dist/observability/Telemetry.mjs +1 -1
- package/dist/observability/Telemetry.mjs.map +1 -1
- package/dist/observability/Telemetry.test.d.mts +1 -1
- package/dist/observability/Telemetry.test.mjs +15 -7
- package/dist/observability/Telemetry.test.mjs.map +1 -1
- package/dist/research/DeepResearch.d.mts +1 -3
- package/dist/research/DeepResearch.d.mts.map +1 -1
- package/dist/research/DeepResearch.mjs +1 -1
- package/dist/research/DeepResearch.mjs.map +1 -1
- package/dist/retry/Retry.d.mts +2 -6
- package/dist/retry/Retry.d.mts.map +1 -1
- package/dist/retry/Retry.mjs +1 -1
- package/dist/retry/Retry.mjs.map +1 -1
- package/dist/retry/Retry.test.d.mts +1 -1
- package/dist/retry/Retry.test.mjs +6 -3
- package/dist/retry/Retry.test.mjs.map +1 -1
- package/dist/sandbox/Memory.d.mts +0 -2
- package/dist/sandbox/Memory.d.mts.map +1 -1
- package/dist/sandbox/Memory.mjs +4 -4
- package/dist/sandbox/Memory.mjs.map +1 -1
- package/dist/sandbox/Sandbox.d.mts +144 -156
- package/dist/sandbox/Sandbox.d.mts.map +1 -1
- package/dist/sandbox/Sandbox.mjs +1 -1
- package/dist/sandbox/Sandbox.mjs.map +1 -1
- package/dist/sandbox/SandboxError.d.mts +1 -1
- package/dist/sandbox/SandboxError.mjs +1 -1
- package/dist/sandbox/SandboxError.mjs.map +1 -1
- package/dist/sandbox/SandboxImage.d.mts +0 -2
- package/dist/sandbox/SandboxImage.d.mts.map +1 -1
- package/dist/sandbox/SandboxImage.mjs +1 -1
- package/dist/sandbox/SandboxImage.mjs.map +1 -1
- package/dist/sandbox/SandboxNetwork.d.mts +0 -2
- package/dist/sandbox/SandboxNetwork.d.mts.map +1 -1
- package/dist/sandbox/SandboxNetwork.mjs +1 -1
- package/dist/sandbox/SandboxNetwork.mjs.map +1 -1
- package/dist/speech-synthesizer/SpeechSynthesizer.d.mts +8 -7
- package/dist/speech-synthesizer/SpeechSynthesizer.d.mts.map +1 -1
- package/dist/speech-synthesizer/SpeechSynthesizer.mjs +1 -1
- package/dist/speech-synthesizer/SpeechSynthesizer.mjs.map +1 -1
- package/dist/speech-synthesizer/SpeechSynthesizer.test.d.mts +1 -1
- package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs +31 -16
- package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs.map +1 -1
- package/dist/streaming/JSONL.d.mts +1 -5
- package/dist/streaming/JSONL.d.mts.map +1 -1
- package/dist/streaming/JSONL.mjs +1 -1
- package/dist/streaming/JSONL.mjs.map +1 -1
- package/dist/streaming/JSONL.test.d.mts +1 -1
- package/dist/streaming/JSONL.test.mjs +16 -8
- package/dist/streaming/JSONL.test.mjs.map +1 -1
- package/dist/streaming/Lines.d.mts +0 -2
- package/dist/streaming/Lines.d.mts.map +1 -1
- package/dist/streaming/Lines.mjs +1 -1
- package/dist/streaming/Lines.mjs.map +1 -1
- package/dist/streaming/SSE.d.mts +0 -2
- package/dist/streaming/SSE.d.mts.map +1 -1
- package/dist/streaming/SSE.mjs +1 -1
- package/dist/streaming/SSE.mjs.map +1 -1
- package/dist/streaming/SSE.test.d.mts +1 -1
- package/dist/streaming/SSE.test.mjs +34 -17
- package/dist/streaming/SSE.test.mjs.map +1 -1
- package/dist/structured-format/StructuredFormat.d.mts +1 -1
- package/dist/structured-format/StructuredFormat.mjs +1 -1
- package/dist/structured-format/StructuredFormat.mjs.map +1 -1
- package/dist/structured-format/StructuredFormat.test.d.mts +1 -1
- package/dist/structured-format/StructuredFormat.test.mjs +7 -4
- package/dist/structured-format/StructuredFormat.test.mjs.map +1 -1
- package/dist/{dist-CcRV3-A5.mjs → test.DNmyFkvJ-YPzDR0Co.mjs} +1644 -5172
- package/dist/test.DNmyFkvJ-YPzDR0Co.mjs.map +1 -0
- package/dist/testing/MockMusicGenerator.d.mts +4 -3
- package/dist/testing/MockMusicGenerator.d.mts.map +1 -1
- package/dist/testing/MockMusicGenerator.mjs.map +1 -1
- package/dist/testing/MockProvider.d.mts +1 -2
- package/dist/testing/MockProvider.d.mts.map +1 -1
- package/dist/testing/MockProvider.mjs.map +1 -1
- package/dist/testing/MockSandbox.d.mts +256 -290
- package/dist/testing/MockSandbox.d.mts.map +1 -1
- package/dist/testing/MockSandbox.mjs.map +1 -1
- package/dist/testing/MockSpeechSynthesizer.d.mts +10 -6
- package/dist/testing/MockSpeechSynthesizer.d.mts.map +1 -1
- package/dist/testing/MockSpeechSynthesizer.mjs.map +1 -1
- package/dist/testing/MockTranscriber.d.mts +3 -2
- package/dist/testing/MockTranscriber.d.mts.map +1 -1
- package/dist/testing/MockTranscriber.mjs.map +1 -1
- package/dist/tool/Approval.d.mts +31 -36
- package/dist/tool/Approval.d.mts.map +1 -1
- package/dist/tool/Approval.mjs +1 -1
- package/dist/tool/Approval.mjs.map +1 -1
- package/dist/tool/Approval.test.d.mts +1 -1
- package/dist/tool/Approval.test.mjs +37 -24
- package/dist/tool/Approval.test.mjs.map +1 -1
- package/dist/tool/HistoryCheck.d.mts +2 -4
- package/dist/tool/HistoryCheck.d.mts.map +1 -1
- package/dist/tool/HistoryCheck.mjs +1 -1
- package/dist/tool/HistoryCheck.mjs.map +1 -1
- package/dist/tool/Tool.d.mts +1 -1
- package/dist/tool/Tool.mjs +4 -4
- package/dist/tool/Tool.mjs.map +1 -1
- package/dist/tool/Tool.test.d.mts +1 -1
- package/dist/tool/Tool.test.mjs +23 -11
- package/dist/tool/Tool.test.mjs.map +1 -1
- package/dist/tool/ToolEvent.d.mts +1 -1
- package/dist/tool/ToolEvent.mjs +1 -1
- package/dist/tool/ToolEvent.mjs.map +1 -1
- package/dist/tool/ToolResult.d.mts +1 -1
- package/dist/tool/ToolResult.mjs +1 -1
- package/dist/tool/ToolResult.mjs.map +1 -1
- package/dist/tool/Toolkit.d.mts +1 -1
- package/dist/tool/Toolkit.mjs +4 -3
- package/dist/tool/Toolkit.mjs.map +1 -1
- package/dist/tool/Toolkit.test.d.mts +1 -1
- package/dist/tool/Toolkit.test.mjs +40 -21
- package/dist/tool/Toolkit.test.mjs.map +1 -1
- package/dist/transcriber/Transcriber.d.mts +6 -6
- package/dist/transcriber/Transcriber.d.mts.map +1 -1
- package/dist/transcriber/Transcriber.mjs +1 -1
- package/dist/transcriber/Transcriber.mjs.map +1 -1
- package/dist/transcriber/Transcriber.test.d.mts +1 -1
- package/dist/transcriber/Transcriber.test.mjs +20 -10
- package/dist/transcriber/Transcriber.test.mjs.map +1 -1
- package/dist/utils-CiH_DjFW.mjs +3918 -0
- package/dist/utils-CiH_DjFW.mjs.map +1 -0
- package/dist/web-read/WebRead.d.mts +15 -9
- package/dist/web-read/WebRead.d.mts.map +1 -1
- package/dist/web-read/WebRead.mjs +1 -1
- package/dist/web-read/WebRead.mjs.map +1 -1
- package/dist/web-read/WebReadTool.d.mts +4 -5
- package/dist/web-read/WebReadTool.d.mts.map +1 -1
- package/dist/web-read/WebReadTool.mjs +1 -1
- package/dist/web-read/WebReadTool.mjs.map +1 -1
- package/dist/web-search/WebSearch.d.mts +22 -13
- package/dist/web-search/WebSearch.d.mts.map +1 -1
- package/dist/web-search/WebSearch.mjs +1 -1
- package/dist/web-search/WebSearch.mjs.map +1 -1
- package/dist/web-search/WebSearchTool.d.mts +6 -6
- package/dist/web-search/WebSearchTool.d.mts.map +1 -1
- package/dist/web-search/WebSearchTool.mjs +1 -1
- package/dist/web-search/WebSearchTool.mjs.map +1 -1
- package/package.json +4 -4
- package/src/loop/Loop.test.ts +13 -14
- package/src/loop/Loop.ts +74 -76
- package/src/testing/MockProvider.ts +8 -9
- package/src/tool/Tool.ts +13 -13
- package/dist/AiError-Bf1pq4BB.d.mts.map +0 -1
- package/dist/Audio-CR7CSljJ.d.mts.map +0 -1
- package/dist/Image-C4vuBmu0.d.mts.map +0 -1
- package/dist/Items-BKQgqJ8A.d.mts.map +0 -1
- package/dist/Loop-D8nWpowc.d.mts.map +0 -1
- package/dist/Media-D_CpcM1Z.d.mts.map +0 -1
- package/dist/SandboxError-CIrVDOMV.d.mts.map +0 -1
- package/dist/StructuredFormat-DHaUJBdd.d.mts.map +0 -1
- package/dist/Tool-u5bag8SO.d.mts.map +0 -1
- package/dist/ToolEvent-BBfOdhF_.d.mts.map +0 -1
- package/dist/ToolResult-CRpmkBXR.d.mts.map +0 -1
- package/dist/Toolkit-D4mQvhjq.d.mts.map +0 -1
- package/dist/dist-C0m0QnUP.mjs.map +0 -1
- package/dist/dist-CcRV3-A5.mjs.map +0 -1
- /package/dist/{chunk-uyGKjUfl.mjs → rolldown-runtime-EAsCxrDo.mjs} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SandboxError.mjs","names":[],"sources":["../../src/sandbox/SandboxError.ts"],"sourcesContent":["import { Data, Duration } from \"effect\"\n\n/**\n * Failed to provision a sandbox. Covers image pull failures, region\n * unavailability, the provider being unreachable, etc. The provider's\n * structured reason (if any) is on `reason`; the raw error from the\n * underlying SDK is on `raw`.\n */\nexport class SandboxCreateFailed extends Data.TaggedError(\"SandboxCreateFailed\")<{\n provider: string\n reason?: string\n raw: unknown\n}> {}\n\n/**\n * The requested sandbox id does not exist (or was already destroyed).\n * Distinct from `SandboxCreateFailed` — this is for `attach` / `destroy` /\n * `get`-style lookups against a stale id.\n */\nexport class SandboxNotFound extends Data.TaggedError(\"SandboxNotFound\")<{\n provider: string\n id: string\n}> {}\n\n/**\n * Caller tried to create a sandbox whose id is already taken. Providers\n * that keyed by name (Microsandbox, Modal) surface this when a previous\n * sandbox with the same name is still alive. Distinct from\n * `SandboxCreateFailed` so callers can retry with `replace` semantics.\n */\nexport class SandboxAlreadyExists extends Data.TaggedError(\"SandboxAlreadyExists\")<{\n provider: string\n id: string\n}> {}\n\n/**\n * A shell exec inside the sandbox failed at the transport / SDK layer —\n * i.e. the SDK couldn't deliver the command to the guest, or the guest\n * agent itself errored. A non-zero exit code from the guest's command\n * is NOT an error; it's an `ExecResult` with `exitCode !== 0`.\n */\nexport class SandboxExecFailed extends Data.TaggedError(\"SandboxExecFailed\")<{\n provider: string\n reason?: string\n raw: unknown\n}> {}\n\n/**\n * A sandbox operation (create, exec, file op) exceeded its time budget.\n * Carries the budget that was breached for observability.\n */\nexport class SandboxTimeout extends Data.TaggedError(\"SandboxTimeout\")<{\n provider: string\n operation: \"create\" | \"exec\" | \"filesystem\" | \"attach\"\n budget?: Duration.Duration\n raw?: unknown\n}> {}\n\n/**\n * Outbound network request from inside the sandbox was blocked by the\n * configured egress policy (host not on allowlist, CIDR mismatch, etc.).\n * Surfaced when the provider's SDK reports the denial back to the host\n * — many providers simply let the request fail inside the guest and\n * never report this to the host, in which case this error is never\n * raised by the adapter.\n */\nexport class SandboxNetworkPolicyDenied extends Data.TaggedError(\"SandboxNetworkPolicyDenied\")<{\n provider: string\n host?: string\n reason?: string\n raw: unknown\n}> {}\n\n/**\n * Provider rejected the create / exec because account / org / project\n * quota or concurrency limit was exceeded. Surfaced separately from\n * `SandboxCreateFailed` so callers can back off and retry intelligently.\n */\nexport class SandboxQuotaExceeded extends Data.TaggedError(\"SandboxQuotaExceeded\")<{\n provider: string\n reason?: string\n raw: unknown\n}> {}\n\n/**\n * Caller's request shape is malformed for the wired provider — e.g. a\n * Dockerfile passed to a provider that only accepts registry refs, a\n * hostname allowlist passed to a CIDR-only provider, etc. Adapters\n * should also reject these at the request-schema layer where possible;\n * this is the runtime fallback.\n */\nexport class SandboxInvalidRequest extends Data.TaggedError(\"SandboxInvalidRequest\")<{\n provider: string\n param?: string\n reason?: string\n raw?: unknown\n}> {}\n\n/**\n * Sandbox SDK could not authenticate against the provider. Subtype\n * mirrors the model-side `AiError.AuthFailed` shape for consistency.\n */\nexport type SandboxAuthSubtype = \"auth\" | \"permission\" | \"billing\" | \"quota\"\n\nexport class SandboxAuthFailed extends Data.TaggedError(\"SandboxAuthFailed\")<{\n provider: string\n subtype: SandboxAuthSubtype\n raw: unknown\n}> {}\n\n/**\n * The wired provider does not implement the requested capability for\n * this specific request. Distinct from `SandboxInvalidRequest` (the\n * request shape is malformed) and from compile-time capability\n * markers (`SandboxSnapshots`, `SandboxSecretInjection`, …) which gate\n * blanket provider-level gaps.\n *\n * Reserved for request-data-dependent gaps where the provider supports\n * the method in general but not for these inputs — e.g. passing\n * `hosts: [...]` to a CIDR-only allowlist provider, or passing\n * `dockerfile: ...` to a provider whose `SandboxCustomImage` marker\n * was provided but which only accepts a flat Dockerfile string.\n */\nexport class SandboxUnsupported extends Data.TaggedError(\"SandboxUnsupported\")<{\n provider: string\n capability: string\n reason?: string\n}> {}\n\nexport type SandboxError =\n | SandboxCreateFailed\n | SandboxNotFound\n | SandboxAlreadyExists\n | SandboxExecFailed\n | SandboxTimeout\n | SandboxNetworkPolicyDenied\n | SandboxQuotaExceeded\n | SandboxInvalidRequest\n | SandboxAuthFailed\n | SandboxUnsupported\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAQA,IAAa,sBAAb,cAAyC,KAAK,YAAY,
|
|
1
|
+
{"version":3,"file":"SandboxError.mjs","names":[],"sources":["../../src/sandbox/SandboxError.ts"],"sourcesContent":["import { Data, Duration } from \"effect\"\n\n/**\n * Failed to provision a sandbox. Covers image pull failures, region\n * unavailability, the provider being unreachable, etc. The provider's\n * structured reason (if any) is on `reason`; the raw error from the\n * underlying SDK is on `raw`.\n */\nexport class SandboxCreateFailed extends Data.TaggedError(\"SandboxCreateFailed\")<{\n provider: string\n reason?: string\n raw: unknown\n}> {}\n\n/**\n * The requested sandbox id does not exist (or was already destroyed).\n * Distinct from `SandboxCreateFailed` — this is for `attach` / `destroy` /\n * `get`-style lookups against a stale id.\n */\nexport class SandboxNotFound extends Data.TaggedError(\"SandboxNotFound\")<{\n provider: string\n id: string\n}> {}\n\n/**\n * Caller tried to create a sandbox whose id is already taken. Providers\n * that keyed by name (Microsandbox, Modal) surface this when a previous\n * sandbox with the same name is still alive. Distinct from\n * `SandboxCreateFailed` so callers can retry with `replace` semantics.\n */\nexport class SandboxAlreadyExists extends Data.TaggedError(\"SandboxAlreadyExists\")<{\n provider: string\n id: string\n}> {}\n\n/**\n * A shell exec inside the sandbox failed at the transport / SDK layer —\n * i.e. the SDK couldn't deliver the command to the guest, or the guest\n * agent itself errored. A non-zero exit code from the guest's command\n * is NOT an error; it's an `ExecResult` with `exitCode !== 0`.\n */\nexport class SandboxExecFailed extends Data.TaggedError(\"SandboxExecFailed\")<{\n provider: string\n reason?: string\n raw: unknown\n}> {}\n\n/**\n * A sandbox operation (create, exec, file op) exceeded its time budget.\n * Carries the budget that was breached for observability.\n */\nexport class SandboxTimeout extends Data.TaggedError(\"SandboxTimeout\")<{\n provider: string\n operation: \"create\" | \"exec\" | \"filesystem\" | \"attach\"\n budget?: Duration.Duration\n raw?: unknown\n}> {}\n\n/**\n * Outbound network request from inside the sandbox was blocked by the\n * configured egress policy (host not on allowlist, CIDR mismatch, etc.).\n * Surfaced when the provider's SDK reports the denial back to the host\n * — many providers simply let the request fail inside the guest and\n * never report this to the host, in which case this error is never\n * raised by the adapter.\n */\nexport class SandboxNetworkPolicyDenied extends Data.TaggedError(\"SandboxNetworkPolicyDenied\")<{\n provider: string\n host?: string\n reason?: string\n raw: unknown\n}> {}\n\n/**\n * Provider rejected the create / exec because account / org / project\n * quota or concurrency limit was exceeded. Surfaced separately from\n * `SandboxCreateFailed` so callers can back off and retry intelligently.\n */\nexport class SandboxQuotaExceeded extends Data.TaggedError(\"SandboxQuotaExceeded\")<{\n provider: string\n reason?: string\n raw: unknown\n}> {}\n\n/**\n * Caller's request shape is malformed for the wired provider — e.g. a\n * Dockerfile passed to a provider that only accepts registry refs, a\n * hostname allowlist passed to a CIDR-only provider, etc. Adapters\n * should also reject these at the request-schema layer where possible;\n * this is the runtime fallback.\n */\nexport class SandboxInvalidRequest extends Data.TaggedError(\"SandboxInvalidRequest\")<{\n provider: string\n param?: string\n reason?: string\n raw?: unknown\n}> {}\n\n/**\n * Sandbox SDK could not authenticate against the provider. Subtype\n * mirrors the model-side `AiError.AuthFailed` shape for consistency.\n */\nexport type SandboxAuthSubtype = \"auth\" | \"permission\" | \"billing\" | \"quota\"\n\nexport class SandboxAuthFailed extends Data.TaggedError(\"SandboxAuthFailed\")<{\n provider: string\n subtype: SandboxAuthSubtype\n raw: unknown\n}> {}\n\n/**\n * The wired provider does not implement the requested capability for\n * this specific request. Distinct from `SandboxInvalidRequest` (the\n * request shape is malformed) and from compile-time capability\n * markers (`SandboxSnapshots`, `SandboxSecretInjection`, …) which gate\n * blanket provider-level gaps.\n *\n * Reserved for request-data-dependent gaps where the provider supports\n * the method in general but not for these inputs — e.g. passing\n * `hosts: [...]` to a CIDR-only allowlist provider, or passing\n * `dockerfile: ...` to a provider whose `SandboxCustomImage` marker\n * was provided but which only accepts a flat Dockerfile string.\n */\nexport class SandboxUnsupported extends Data.TaggedError(\"SandboxUnsupported\")<{\n provider: string\n capability: string\n reason?: string\n}> {}\n\nexport type SandboxError =\n | SandboxCreateFailed\n | SandboxNotFound\n | SandboxAlreadyExists\n | SandboxExecFailed\n | SandboxTimeout\n | SandboxNetworkPolicyDenied\n | SandboxQuotaExceeded\n | SandboxInvalidRequest\n | SandboxAuthFailed\n | SandboxUnsupported\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAQA,IAAa,sBAAb,cAAyC,KAAK,YAAY,qBAAqB,CAAC,CAI7E,CAAC;;;;;;AAOJ,IAAa,kBAAb,cAAqC,KAAK,YAAY,iBAAiB,CAAC,CAGrE,CAAC;;;;;;;AAQJ,IAAa,uBAAb,cAA0C,KAAK,YAAY,sBAAsB,CAAC,CAG/E,CAAC;;;;;;;AAQJ,IAAa,oBAAb,cAAuC,KAAK,YAAY,mBAAmB,CAAC,CAIzE,CAAC;;;;;AAMJ,IAAa,iBAAb,cAAoC,KAAK,YAAY,gBAAgB,CAAC,CAKnE,CAAC;;;;;;;;;AAUJ,IAAa,6BAAb,cAAgD,KAAK,YAAY,4BAA4B,CAAC,CAK3F,CAAC;;;;;;AAOJ,IAAa,uBAAb,cAA0C,KAAK,YAAY,sBAAsB,CAAC,CAI/E,CAAC;;;;;;;;AASJ,IAAa,wBAAb,cAA2C,KAAK,YAAY,uBAAuB,CAAC,CAKjF,CAAC;AAQJ,IAAa,oBAAb,cAAuC,KAAK,YAAY,mBAAmB,CAAC,CAIzE,CAAC;;;;;;;;;;;;;;AAeJ,IAAa,qBAAb,cAAwC,KAAK,YAAY,oBAAoB,CAAC,CAI3E,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SandboxImage.d.mts","names":[],"sources":["../../src/sandbox/SandboxImage.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"SandboxImage.d.mts","names":[],"sources":["../../src/sandbox/SandboxImage.ts"],"mappings":";;;;;;;;;;;;;;;;;;;cAkBa,MAAM;cAEN,WAAQ,gBAAkB;cAE1B,WAAQ,IAAQ,wBAAsB;cAGtC,aAAU,qBAAuB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as __exportAll } from "../
|
|
1
|
+
import { n as __exportAll } from "../rolldown-runtime-EAsCxrDo.mjs";
|
|
2
2
|
import { ImageRef, SnapshotId } from "./Sandbox.mjs";
|
|
3
3
|
//#region src/sandbox/SandboxImage.ts
|
|
4
4
|
var SandboxImage_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SandboxImage.mjs","names":[],"sources":["../../src/sandbox/SandboxImage.ts"],"sourcesContent":["import { ImageRef, SnapshotId } from \"./Sandbox.js\"\n\n/**\n * Ergonomic constructors for {@link ImageRef}. `ImageRef.*` tagged\n * constructors still exist (and are what pattern-matching code uses);\n * these helpers are what end users reach for at the call site.\n *\n * @example\n * ```ts\n * import * as Image from \"@effect-uai/core/SandboxImage\"\n *\n * Image.auto // provider's house image\n * Image.registry(\"python:3.12\") // OCI registry ref\n * Image.snapshot(\"ml-warm-1\") // restore captured state (gated)\n * Image.dockerfile(\"FROM ubuntu...\") // build custom (gated)\n * ```\n */\n\nexport const auto: ImageRef = ImageRef.Default()\n\nexport const registry = (ref: string): ImageRef => ImageRef.Registry({ ref })\n\nexport const snapshot = (id: SnapshotId | string): ImageRef =>\n ImageRef.Snapshot({ id: SnapshotId(id) })\n\nexport const dockerfile = (contents: string): ImageRef => ImageRef.Dockerfile({ contents })\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAkBA,MAAa,OAAiB,SAAS,
|
|
1
|
+
{"version":3,"file":"SandboxImage.mjs","names":[],"sources":["../../src/sandbox/SandboxImage.ts"],"sourcesContent":["import { ImageRef, SnapshotId } from \"./Sandbox.js\"\n\n/**\n * Ergonomic constructors for {@link ImageRef}. `ImageRef.*` tagged\n * constructors still exist (and are what pattern-matching code uses);\n * these helpers are what end users reach for at the call site.\n *\n * @example\n * ```ts\n * import * as Image from \"@effect-uai/core/SandboxImage\"\n *\n * Image.auto // provider's house image\n * Image.registry(\"python:3.12\") // OCI registry ref\n * Image.snapshot(\"ml-warm-1\") // restore captured state (gated)\n * Image.dockerfile(\"FROM ubuntu...\") // build custom (gated)\n * ```\n */\n\nexport const auto: ImageRef = ImageRef.Default()\n\nexport const registry = (ref: string): ImageRef => ImageRef.Registry({ ref })\n\nexport const snapshot = (id: SnapshotId | string): ImageRef =>\n ImageRef.Snapshot({ id: SnapshotId(id) })\n\nexport const dockerfile = (contents: string): ImageRef => ImageRef.Dockerfile({ contents })\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAkBA,MAAa,OAAiB,SAAS,QAAQ;AAE/C,MAAa,YAAY,QAA0B,SAAS,SAAS,EAAE,IAAI,CAAC;AAE5E,MAAa,YAAY,OACvB,SAAS,SAAS,EAAE,IAAI,WAAW,EAAE,EAAE,CAAC;AAE1C,MAAa,cAAc,aAA+B,SAAS,WAAW,EAAE,SAAS,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SandboxNetwork.d.mts","names":[],"sources":["../../src/sandbox/SandboxNetwork.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"SandboxNetwork.d.mts","names":[],"sources":["../../src/sandbox/SandboxNetwork.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;cAoBa,MAAM;cAEN,SAAS;cAET,gBAAU,OAAc,0BAAwB;cAGhD,gBAAU,OAAc,0BAAwB;cAGhD,QAAK;WACP,QAAQ;WACR,QAAQ;MACf"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as __exportAll } from "../
|
|
1
|
+
import { n as __exportAll } from "../rolldown-runtime-EAsCxrDo.mjs";
|
|
2
2
|
import { NetworkPolicy } from "./Sandbox.mjs";
|
|
3
3
|
//#region src/sandbox/SandboxNetwork.ts
|
|
4
4
|
var SandboxNetwork_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SandboxNetwork.mjs","names":[],"sources":["../../src/sandbox/SandboxNetwork.ts"],"sourcesContent":["import { NetworkPolicy } from \"./Sandbox.js\"\n\n/**\n * Ergonomic constructors for {@link NetworkPolicy}. The tagged\n * constructors under `Sandbox.NetworkPolicy.*` still exist (and are\n * what pattern-matching code uses); these helpers are what end users\n * reach for at the call site.\n *\n * @example\n * ```ts\n * import * as Network from \"@effect-uai/core/SandboxNetwork\"\n *\n * Network.open // provider defaults apply\n * Network.blocked // airgapped — no egress\n * Network.allowHosts(\"api.openai.com\", \"github.com\")\n * Network.allowCidrs(\"10.0.0.0/8\")\n * Network.allow({ hosts: [...], cidrs: [...] }) // combined allowlist\n * ```\n */\n\nexport const open: NetworkPolicy = NetworkPolicy.Open()\n\nexport const blocked: NetworkPolicy = NetworkPolicy.Blocked()\n\nexport const allowHosts = (...hosts: ReadonlyArray<string>): NetworkPolicy =>\n NetworkPolicy.Allowlist({ hosts })\n\nexport const allowCidrs = (...cidrs: ReadonlyArray<string>): NetworkPolicy =>\n NetworkPolicy.Allowlist({ cidrs })\n\nexport const allow = (opts: {\n readonly hosts?: ReadonlyArray<string>\n readonly cidrs?: ReadonlyArray<string>\n}): NetworkPolicy => NetworkPolicy.Allowlist(opts)\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAoBA,MAAa,OAAsB,cAAc,
|
|
1
|
+
{"version":3,"file":"SandboxNetwork.mjs","names":[],"sources":["../../src/sandbox/SandboxNetwork.ts"],"sourcesContent":["import { NetworkPolicy } from \"./Sandbox.js\"\n\n/**\n * Ergonomic constructors for {@link NetworkPolicy}. The tagged\n * constructors under `Sandbox.NetworkPolicy.*` still exist (and are\n * what pattern-matching code uses); these helpers are what end users\n * reach for at the call site.\n *\n * @example\n * ```ts\n * import * as Network from \"@effect-uai/core/SandboxNetwork\"\n *\n * Network.open // provider defaults apply\n * Network.blocked // airgapped — no egress\n * Network.allowHosts(\"api.openai.com\", \"github.com\")\n * Network.allowCidrs(\"10.0.0.0/8\")\n * Network.allow({ hosts: [...], cidrs: [...] }) // combined allowlist\n * ```\n */\n\nexport const open: NetworkPolicy = NetworkPolicy.Open()\n\nexport const blocked: NetworkPolicy = NetworkPolicy.Blocked()\n\nexport const allowHosts = (...hosts: ReadonlyArray<string>): NetworkPolicy =>\n NetworkPolicy.Allowlist({ hosts })\n\nexport const allowCidrs = (...cidrs: ReadonlyArray<string>): NetworkPolicy =>\n NetworkPolicy.Allowlist({ cidrs })\n\nexport const allow = (opts: {\n readonly hosts?: ReadonlyArray<string>\n readonly cidrs?: ReadonlyArray<string>\n}): NetworkPolicy => NetworkPolicy.Allowlist(opts)\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAoBA,MAAa,OAAsB,cAAc,KAAK;AAEtD,MAAa,UAAyB,cAAc,QAAQ;AAE5D,MAAa,cAAc,GAAG,UAC5B,cAAc,UAAU,EAAE,MAAM,CAAC;AAEnC,MAAa,cAAc,GAAG,UAC5B,cAAc,UAAU,EAAE,MAAM,CAAC;AAEnC,MAAa,SAAS,SAGD,cAAc,UAAU,IAAI"}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { t as AiError } from "../AiError-
|
|
2
|
-
import { n as AudioChunk, r as AudioFormat, t as AudioBlob } from "../Audio-
|
|
1
|
+
import { t as AiError } from "../AiError-eLV9t1lU.mjs";
|
|
2
|
+
import { n as AudioChunk, r as AudioFormat, t as AudioBlob } from "../Audio-60lKKHxS.mjs";
|
|
3
3
|
import { Context, Effect, Stream } from "effect";
|
|
4
|
-
|
|
5
|
-
//#region src/speech-synthesizer/SpeechSynthesizer.d.ts
|
|
6
4
|
declare namespace SpeechSynthesizer_d_exports {
|
|
7
5
|
export { CommonStreamSynthesizeRequest, CommonSynthesizeDialogueRequest, CommonSynthesizeRequest, CustomPronunciation, DialogueTurn, MultiSpeakerTts, SpeechSynthesizer, SpeechSynthesizerService, TtsIncrementalText, streamSynthesis, streamSynthesisFrom, streamSynthesizeDialogue, synthesize, synthesizeDialogue };
|
|
8
6
|
}
|
|
@@ -18,7 +16,8 @@ declare namespace SpeechSynthesizer_d_exports {
|
|
|
18
16
|
* with `AiError.Unsupported` rather than silently degrading.
|
|
19
17
|
*/
|
|
20
18
|
type CustomPronunciation = {
|
|
21
|
-
readonly phrase: string;
|
|
19
|
+
readonly phrase: string;
|
|
20
|
+
/** IPA notation, e.g. `"ænˈθrɒpɪk"`. */
|
|
22
21
|
readonly pronunciation: string;
|
|
23
22
|
};
|
|
24
23
|
/**
|
|
@@ -29,7 +28,8 @@ type CustomPronunciation = {
|
|
|
29
28
|
* `voiceId`.
|
|
30
29
|
*/
|
|
31
30
|
type CommonSynthesizeRequest = {
|
|
32
|
-
readonly text: string;
|
|
31
|
+
readonly text: string;
|
|
32
|
+
/** Model identifier. Each provider narrows. */
|
|
33
33
|
readonly model: string;
|
|
34
34
|
/**
|
|
35
35
|
* Voice identifier. Per-provider request types narrow this to a
|
|
@@ -83,7 +83,8 @@ type CommonSynthesizeDialogueRequest = {
|
|
|
83
83
|
readonly pronunciations?: ReadonlyArray<CustomPronunciation>;
|
|
84
84
|
};
|
|
85
85
|
type SpeechSynthesizerService = {
|
|
86
|
-
/** One-shot. Full text in, full audio bytes out. Universally supported. */
|
|
86
|
+
/** One-shot. Full text in, full audio bytes out. Universally supported. */
|
|
87
|
+
readonly synthesize: (request: CommonSynthesizeRequest) => Effect.Effect<AudioBlob, AiError>;
|
|
87
88
|
/**
|
|
88
89
|
* Full text in, audio chunks streamed out (chunked HTTP). Universally
|
|
89
90
|
* supported across providers that offer any streaming TTS at all.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpeechSynthesizer.d.mts","names":[],"sources":["../../src/speech-synthesizer/SpeechSynthesizer.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"SpeechSynthesizer.d.mts","names":[],"sources":["../../src/speech-synthesizer/SpeechSynthesizer.ts"],"mappings":";;;;;;;;;;;;;;;;;KAeY;WACD;;WAEA;;;;;;;;;KAUC;WACD;;WAEA;;;;;;;WAOA;WACA,eAAe;WACf;WACA;;;;;;;WAOA,iBAAiB,cAAc;;;;;;;;;;;KAY9B,gCAAgC,KAAK;;;;;;;;KASrC;WACD;WACA;;;;;;;KAQC;WACD;WACA,OAAO,cAAc;WACrB,eAAe;WACf;WACA,iBAAiB,cAAc;;KAG9B;;WAED,aACP,SAAS,4BACN,OAAO,OAAO,WAAW;;;;;WAKrB,kBACP,SAAS,4BACN,OAAO,OAAO,YAAY;;;;;;;;;;;WAWtB,sBAAsB,GAAG,GAChC,QAAQ,OAAO,eAAe,GAAG,IACjC,SAAS,kCACN,OAAO,OAAO,YAAY,UAAkB,GAAG;;;;;;;WAO3C,qBACP,SAAS,oCACN,OAAO,OAAO,WAAW;;;;;;;;;WASrB,2BACP,SAAS,oCACN,OAAO,OAAO,YAAY;;;cAGpB,0BAA0B;;;;;;;;;;;;cAe1B,2BAA2B;;;;;;;;;;;cAa3B,wBAAwB;;cAKxB,aAAU,SACZ,4BACR,OAAO,OAAO,WAAW,SAAiB;;cAIhC,kBAAe,SACjB,4BACR,OAAO,OAAO,YAAY,SAAiB;;;;;;;;;;;;;;cAgBjC;GAET,SAAS,iCACP,GAAG,GACL,QAAQ,OAAO,eAAe,GAAG,OAC9B,OAAO,OAAO,YAAY,UAAkB,GAAG,IAAI,oBAAoB;GAC3E,GAAG,GACF,QAAQ,OAAO,eAAe,GAAG,IACjC,SAAS,gCACR,OAAO,OAAO,YAAY,UAAkB,GAAG,IAAI,oBAAoB;;;;;;cAiB/D,qBAAkB,SACpB,oCACR,OAAO,OAAO,WAAW,SAAiB,oBAAoB;;;;cAUpD,2BAAwB,SAC1B,oCACR,OAAO,OAAO,YAAY,SAAiB,oBAAoB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as __exportAll } from "../
|
|
1
|
+
import { n as __exportAll } from "../rolldown-runtime-EAsCxrDo.mjs";
|
|
2
2
|
import { Context, Effect, Function, Stream } from "effect";
|
|
3
3
|
//#region src/speech-synthesizer/SpeechSynthesizer.ts
|
|
4
4
|
var SpeechSynthesizer_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpeechSynthesizer.mjs","names":[],"sources":["../../src/speech-synthesizer/SpeechSynthesizer.ts"],"sourcesContent":["import { Context, Effect, Function, Stream } from \"effect\"\nimport * as AiError from \"../domain/AiError.js\"\nimport type { AudioBlob, AudioChunk, AudioFormat } from \"../domain/Audio.js\"\n\n/**\n * Per-phrase pronunciation override. `pronunciation` is always IPA, the\n * universal phonetic interchange format. Adapters translate to the\n * provider's wire form (inline `/ipa/` token, SSML `<phoneme>`, or a\n * structured field), converting IPA to X-SAMPA internally where the wire\n * requires it (Google, Azure).\n *\n * Pronunciations are load-bearing (the configured word is mispronounced\n * if dropped), so a provider with no stateless IPA path fails the call\n * with `AiError.Unsupported` rather than silently degrading.\n */\nexport type CustomPronunciation = {\n readonly phrase: string\n /** IPA notation, e.g. `\"ænˈθrɒpɪk\"`. */\n readonly pronunciation: string\n}\n\n/**\n * Cross-provider synthesis request. Provider-specific extensions\n * (ElevenLabs `stability` / `similarity_boost`, Cartesia `emotion`,\n * MiniMax `vol` / `pitch`, Azure SSML style tags) live on each\n * provider's typed request which extends this and narrows `model` and\n * `voiceId`.\n */\nexport type CommonSynthesizeRequest = {\n readonly text: string\n /** Model identifier. Each provider narrows. */\n readonly model: string\n /**\n * Voice identifier. Per-provider request types narrow this to a\n * typed literal union of stock voices + `(string & {})` escape for\n * custom cloned voice IDs. Providers without custom-voice support\n * (OpenAI, Deepgram Aura, AWS Polly) narrow to the stock-only union.\n */\n readonly voiceId: string\n readonly outputFormat?: AudioFormat\n readonly speed?: number\n readonly languageCode?: string\n /**\n * IPA phoneme overrides for specific phrases. Adapters render them to\n * the provider's wire form (inline token, SSML `<phoneme>`, structured\n * field). Load-bearing: a provider with no stateless IPA path fails\n * the call with `AiError.Unsupported` rather than mispronouncing.\n */\n readonly pronunciations?: ReadonlyArray<CustomPronunciation>\n}\n\n/**\n * Incremental-synthesis request — text arrives as `Stream<string>`.\n * Gated by the `TtsIncrementalText` capability marker; only providers\n * that ship the marker can be used.\n *\n * Multi-context features (Cartesia `context_id`, ElevenLabs `multi-\n * stream-input`) are NOT exposed here — one logical utterance per\n * call. Provider extensions can expose `forkContext` for that.\n */\nexport type CommonStreamSynthesizeRequest = Omit<CommonSynthesizeRequest, \"text\">\n\n/**\n * One turn in a multi-speaker dialogue. Just a voice and its line; the\n * only in-tree dialogue endpoint (ElevenLabs `/v1/text-to-dialogue`)\n * accepts `{ voice_id, text }` per turn. Per-turn styling knobs\n * (Hume Octave-2 `styleDescription` / `speed`) are provider-specific\n * and belong on a provider-typed turn extension, not here.\n */\nexport type DialogueTurn = {\n readonly voiceId: string\n readonly text: string\n}\n\n/**\n * Cross-provider dialogue request. Same return type as `synthesize` —\n * one continuous `AudioBlob`. Per-turn timing metadata is not exposed\n * in the common shape (only Hume returns it natively).\n */\nexport type CommonSynthesizeDialogueRequest = {\n readonly model: string\n readonly turns: ReadonlyArray<DialogueTurn>\n readonly outputFormat?: AudioFormat\n readonly languageCode?: string\n readonly pronunciations?: ReadonlyArray<CustomPronunciation>\n}\n\nexport type SpeechSynthesizerService = {\n /** One-shot. Full text in, full audio bytes out. Universally supported. */\n readonly synthesize: (\n request: CommonSynthesizeRequest,\n ) => Effect.Effect<AudioBlob, AiError.AiError>\n /**\n * Full text in, audio chunks streamed out (chunked HTTP). Universally\n * supported across providers that offer any streaming TTS at all.\n */\n readonly streamSynthesis: (\n request: CommonSynthesizeRequest,\n ) => Stream.Stream<AudioChunk, AiError.AiError>\n /**\n * Incremental text in (as a Stream), audio chunks streamed out. The\n * underlying WS connection is acquired on first pull and released\n * when the output stream is finalized via `Stream.scoped`.\n *\n * Gated by the `TtsIncrementalText` capability marker on the top-\n * level helper — providers without WS-style incremental input don't\n * ship the marker, so calls fail at `Effect.provide` with a type\n * error.\n */\n readonly streamSynthesisFrom: <E, R>(\n textIn: Stream.Stream<string, E, R>,\n request: CommonStreamSynthesizeRequest,\n ) => Stream.Stream<AudioChunk, AiError.AiError | E, R>\n /**\n * One-shot multi-speaker dialogue. Turn array in, single `AudioBlob`\n * out. Providers without native dialogue support return\n * `AiError.Unsupported` and do NOT ship the `MultiSpeakerTts` marker\n * — calls via the top-level helper become a compile-time error.\n */\n readonly synthesizeDialogue: (\n request: CommonSynthesizeDialogueRequest,\n ) => Effect.Effect<AudioBlob, AiError.AiError>\n /**\n * Chunked-streaming variant of `synthesizeDialogue`. Same input,\n * audio chunks emitted as the wire delivers them. Providers that\n * synthesize the whole dialogue server-side may fall back to a\n * single-chunk wrap of the sync result.\n *\n * Gated by `MultiSpeakerTts` at the top-level helper.\n */\n readonly streamSynthesizeDialogue: (\n request: CommonSynthesizeDialogueRequest,\n ) => Stream.Stream<AudioChunk, AiError.AiError>\n}\n\nexport class SpeechSynthesizer extends Context.Service<\n SpeechSynthesizer,\n SpeechSynthesizerService\n>()(\"@betalyra/effect-uai/SpeechSynthesizer\") {}\n\n/**\n * Capability marker — provided by provider layers whose\n * `streamSynthesisFrom` is wired up at the wire level. OpenAI, Azure\n * (wire), and AWS Polly non-Generative do not ship it. Calling\n * `streamSynthesisFrom` while only one of those Layers is in scope\n * fails at `Effect.provide` with a type error.\n *\n * Phantom — the value is `void`; providers register with\n * `Layer.succeed(TtsIncrementalText, undefined)`.\n */\nexport class TtsIncrementalText extends Context.Service<TtsIncrementalText, void>()(\n \"@betalyra/effect-uai/capability/TtsIncrementalText\",\n) {}\n\n/**\n * Capability marker for multi-speaker dialogue. Shipped by provider\n * Layers whose `synthesizeDialogue` is wired to a native multi-speaker\n * endpoint (ElevenLabs `/v1/text-to-dialogue`, Hume `/v0/tts` with\n * `utterances[]`, Google Cloud TTS Gemini TTS `multiSpeakerMarkup`).\n * Other providers leave the marker unregistered so the top-level\n * `synthesizeDialogue` / `streamSynthesizeDialogue` helpers fail to\n * satisfy R against those Layers — compile-time error.\n */\nexport class MultiSpeakerTts extends Context.Service<MultiSpeakerTts, void>()(\n \"@betalyra/effect-uai/capability/MultiSpeakerTts\",\n) {}\n\n/** One-shot synthesis. */\nexport const synthesize = (\n request: CommonSynthesizeRequest,\n): Effect.Effect<AudioBlob, AiError.AiError, SpeechSynthesizer> =>\n Effect.flatMap(SpeechSynthesizer, (s) => s.synthesize(request))\n\n/** Full text in, audio chunks out. */\nexport const streamSynthesis = (\n request: CommonSynthesizeRequest,\n): Stream.Stream<AudioChunk, AiError.AiError, SpeechSynthesizer> =>\n Stream.unwrap(Effect.map(SpeechSynthesizer, (s) => s.streamSynthesis(request)))\n\n/**\n * Incremental synthesis. Dual-arity: pipeable (data-last) and direct\n * (data-first). Requires `TtsIncrementalText` in R — providers without\n * incremental-text-in support are a type error at provide time.\n *\n * @example\n * ```ts\n * const audio = LanguageModel.streamTurn(turnReq).pipe(\n * Stream.filterMap(Turn.toTextDelta),\n * SpeechSynthesizer.streamSynthesisFrom(synthReq),\n * )\n * ```\n */\nexport const streamSynthesisFrom: {\n (\n request: CommonStreamSynthesizeRequest,\n ): <E, R>(\n textIn: Stream.Stream<string, E, R>,\n ) => Stream.Stream<AudioChunk, AiError.AiError | E, R | SpeechSynthesizer | TtsIncrementalText>\n <E, R>(\n textIn: Stream.Stream<string, E, R>,\n request: CommonStreamSynthesizeRequest,\n ): Stream.Stream<AudioChunk, AiError.AiError | E, R | SpeechSynthesizer | TtsIncrementalText>\n} = Function.dual(\n 2,\n <E, R>(textIn: Stream.Stream<string, E, R>, request: CommonStreamSynthesizeRequest) =>\n Stream.unwrap(\n Effect.gen(function* () {\n const s = yield* SpeechSynthesizer\n yield* TtsIncrementalText\n return s.streamSynthesisFrom(textIn, request)\n }),\n ),\n)\n\n/**\n * One-shot multi-speaker dialogue. Requires `MultiSpeakerTts` in R —\n * providers without dialogue support are a compile-time error.\n */\nexport const synthesizeDialogue = (\n request: CommonSynthesizeDialogueRequest,\n): Effect.Effect<AudioBlob, AiError.AiError, SpeechSynthesizer | MultiSpeakerTts> =>\n Effect.gen(function* () {\n const s = yield* SpeechSynthesizer\n yield* MultiSpeakerTts\n return yield* s.synthesizeDialogue(request)\n })\n\n/**\n * Chunked-streaming variant. Same R requirement as `synthesizeDialogue`.\n */\nexport const streamSynthesizeDialogue = (\n request: CommonSynthesizeDialogueRequest,\n): Stream.Stream<AudioChunk, AiError.AiError, SpeechSynthesizer | MultiSpeakerTts> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const s = yield* SpeechSynthesizer\n yield* MultiSpeakerTts\n return s.streamSynthesizeDialogue(request)\n }),\n )\n"],"mappings":";;;;;;;;;;;;;AAuIA,IAAa,oBAAb,cAAuC,QAAQ,SAG5C,CAAC,yCAAyC,CAAC;;;;;;;;;;;AAY9C,IAAa,qBAAb,cAAwC,QAAQ,SAAmC,CACjF,qDACD,CAAC;;;;;;;;;;AAWF,IAAa,kBAAb,cAAqC,QAAQ,SAAgC,CAC3E,kDACD,CAAC;;AAGF,MAAa,cACX,YAEA,OAAO,QAAQ,oBAAoB,MAAM,EAAE,WAAW,QAAQ,CAAC;;AAGjE,MAAa,mBACX,YAEA,OAAO,OAAO,OAAO,IAAI,oBAAoB,MAAM,EAAE,gBAAgB,QAAQ,CAAC,CAAC;;;;;;;;;;;;;;AAejF,MAAa,sBAUT,SAAS,KACX,IACO,QAAqC,YAC1C,OAAO,OACL,OAAO,IAAI,aAAa;CACtB,MAAM,IAAI,OAAO;AACjB,QAAO;AACP,QAAO,EAAE,oBAAoB,QAAQ,QAAQ;EAC7C,CACH,CACJ;;;;;AAMD,MAAa,sBACX,YAEA,OAAO,IAAI,aAAa;CACtB,MAAM,IAAI,OAAO;AACjB,QAAO;AACP,QAAO,OAAO,EAAE,mBAAmB,QAAQ;EAC3C;;;;AAKJ,MAAa,4BACX,YAEA,OAAO,OACL,OAAO,IAAI,aAAa;CACtB,MAAM,IAAI,OAAO;AACjB,QAAO;AACP,QAAO,EAAE,yBAAyB,QAAQ;EAC1C,CACH"}
|
|
1
|
+
{"version":3,"file":"SpeechSynthesizer.mjs","names":[],"sources":["../../src/speech-synthesizer/SpeechSynthesizer.ts"],"sourcesContent":["import { Context, Effect, Function, Stream } from \"effect\"\nimport * as AiError from \"../domain/AiError.js\"\nimport type { AudioBlob, AudioChunk, AudioFormat } from \"../domain/Audio.js\"\n\n/**\n * Per-phrase pronunciation override. `pronunciation` is always IPA, the\n * universal phonetic interchange format. Adapters translate to the\n * provider's wire form (inline `/ipa/` token, SSML `<phoneme>`, or a\n * structured field), converting IPA to X-SAMPA internally where the wire\n * requires it (Google, Azure).\n *\n * Pronunciations are load-bearing (the configured word is mispronounced\n * if dropped), so a provider with no stateless IPA path fails the call\n * with `AiError.Unsupported` rather than silently degrading.\n */\nexport type CustomPronunciation = {\n readonly phrase: string\n /** IPA notation, e.g. `\"ænˈθrɒpɪk\"`. */\n readonly pronunciation: string\n}\n\n/**\n * Cross-provider synthesis request. Provider-specific extensions\n * (ElevenLabs `stability` / `similarity_boost`, Cartesia `emotion`,\n * MiniMax `vol` / `pitch`, Azure SSML style tags) live on each\n * provider's typed request which extends this and narrows `model` and\n * `voiceId`.\n */\nexport type CommonSynthesizeRequest = {\n readonly text: string\n /** Model identifier. Each provider narrows. */\n readonly model: string\n /**\n * Voice identifier. Per-provider request types narrow this to a\n * typed literal union of stock voices + `(string & {})` escape for\n * custom cloned voice IDs. Providers without custom-voice support\n * (OpenAI, Deepgram Aura, AWS Polly) narrow to the stock-only union.\n */\n readonly voiceId: string\n readonly outputFormat?: AudioFormat\n readonly speed?: number\n readonly languageCode?: string\n /**\n * IPA phoneme overrides for specific phrases. Adapters render them to\n * the provider's wire form (inline token, SSML `<phoneme>`, structured\n * field). Load-bearing: a provider with no stateless IPA path fails\n * the call with `AiError.Unsupported` rather than mispronouncing.\n */\n readonly pronunciations?: ReadonlyArray<CustomPronunciation>\n}\n\n/**\n * Incremental-synthesis request — text arrives as `Stream<string>`.\n * Gated by the `TtsIncrementalText` capability marker; only providers\n * that ship the marker can be used.\n *\n * Multi-context features (Cartesia `context_id`, ElevenLabs `multi-\n * stream-input`) are NOT exposed here — one logical utterance per\n * call. Provider extensions can expose `forkContext` for that.\n */\nexport type CommonStreamSynthesizeRequest = Omit<CommonSynthesizeRequest, \"text\">\n\n/**\n * One turn in a multi-speaker dialogue. Just a voice and its line; the\n * only in-tree dialogue endpoint (ElevenLabs `/v1/text-to-dialogue`)\n * accepts `{ voice_id, text }` per turn. Per-turn styling knobs\n * (Hume Octave-2 `styleDescription` / `speed`) are provider-specific\n * and belong on a provider-typed turn extension, not here.\n */\nexport type DialogueTurn = {\n readonly voiceId: string\n readonly text: string\n}\n\n/**\n * Cross-provider dialogue request. Same return type as `synthesize` —\n * one continuous `AudioBlob`. Per-turn timing metadata is not exposed\n * in the common shape (only Hume returns it natively).\n */\nexport type CommonSynthesizeDialogueRequest = {\n readonly model: string\n readonly turns: ReadonlyArray<DialogueTurn>\n readonly outputFormat?: AudioFormat\n readonly languageCode?: string\n readonly pronunciations?: ReadonlyArray<CustomPronunciation>\n}\n\nexport type SpeechSynthesizerService = {\n /** One-shot. Full text in, full audio bytes out. Universally supported. */\n readonly synthesize: (\n request: CommonSynthesizeRequest,\n ) => Effect.Effect<AudioBlob, AiError.AiError>\n /**\n * Full text in, audio chunks streamed out (chunked HTTP). Universally\n * supported across providers that offer any streaming TTS at all.\n */\n readonly streamSynthesis: (\n request: CommonSynthesizeRequest,\n ) => Stream.Stream<AudioChunk, AiError.AiError>\n /**\n * Incremental text in (as a Stream), audio chunks streamed out. The\n * underlying WS connection is acquired on first pull and released\n * when the output stream is finalized via `Stream.scoped`.\n *\n * Gated by the `TtsIncrementalText` capability marker on the top-\n * level helper — providers without WS-style incremental input don't\n * ship the marker, so calls fail at `Effect.provide` with a type\n * error.\n */\n readonly streamSynthesisFrom: <E, R>(\n textIn: Stream.Stream<string, E, R>,\n request: CommonStreamSynthesizeRequest,\n ) => Stream.Stream<AudioChunk, AiError.AiError | E, R>\n /**\n * One-shot multi-speaker dialogue. Turn array in, single `AudioBlob`\n * out. Providers without native dialogue support return\n * `AiError.Unsupported` and do NOT ship the `MultiSpeakerTts` marker\n * — calls via the top-level helper become a compile-time error.\n */\n readonly synthesizeDialogue: (\n request: CommonSynthesizeDialogueRequest,\n ) => Effect.Effect<AudioBlob, AiError.AiError>\n /**\n * Chunked-streaming variant of `synthesizeDialogue`. Same input,\n * audio chunks emitted as the wire delivers them. Providers that\n * synthesize the whole dialogue server-side may fall back to a\n * single-chunk wrap of the sync result.\n *\n * Gated by `MultiSpeakerTts` at the top-level helper.\n */\n readonly streamSynthesizeDialogue: (\n request: CommonSynthesizeDialogueRequest,\n ) => Stream.Stream<AudioChunk, AiError.AiError>\n}\n\nexport class SpeechSynthesizer extends Context.Service<\n SpeechSynthesizer,\n SpeechSynthesizerService\n>()(\"@betalyra/effect-uai/SpeechSynthesizer\") {}\n\n/**\n * Capability marker — provided by provider layers whose\n * `streamSynthesisFrom` is wired up at the wire level. OpenAI, Azure\n * (wire), and AWS Polly non-Generative do not ship it. Calling\n * `streamSynthesisFrom` while only one of those Layers is in scope\n * fails at `Effect.provide` with a type error.\n *\n * Phantom — the value is `void`; providers register with\n * `Layer.succeed(TtsIncrementalText, undefined)`.\n */\nexport class TtsIncrementalText extends Context.Service<TtsIncrementalText, void>()(\n \"@betalyra/effect-uai/capability/TtsIncrementalText\",\n) {}\n\n/**\n * Capability marker for multi-speaker dialogue. Shipped by provider\n * Layers whose `synthesizeDialogue` is wired to a native multi-speaker\n * endpoint (ElevenLabs `/v1/text-to-dialogue`, Hume `/v0/tts` with\n * `utterances[]`, Google Cloud TTS Gemini TTS `multiSpeakerMarkup`).\n * Other providers leave the marker unregistered so the top-level\n * `synthesizeDialogue` / `streamSynthesizeDialogue` helpers fail to\n * satisfy R against those Layers — compile-time error.\n */\nexport class MultiSpeakerTts extends Context.Service<MultiSpeakerTts, void>()(\n \"@betalyra/effect-uai/capability/MultiSpeakerTts\",\n) {}\n\n/** One-shot synthesis. */\nexport const synthesize = (\n request: CommonSynthesizeRequest,\n): Effect.Effect<AudioBlob, AiError.AiError, SpeechSynthesizer> =>\n Effect.flatMap(SpeechSynthesizer, (s) => s.synthesize(request))\n\n/** Full text in, audio chunks out. */\nexport const streamSynthesis = (\n request: CommonSynthesizeRequest,\n): Stream.Stream<AudioChunk, AiError.AiError, SpeechSynthesizer> =>\n Stream.unwrap(Effect.map(SpeechSynthesizer, (s) => s.streamSynthesis(request)))\n\n/**\n * Incremental synthesis. Dual-arity: pipeable (data-last) and direct\n * (data-first). Requires `TtsIncrementalText` in R — providers without\n * incremental-text-in support are a type error at provide time.\n *\n * @example\n * ```ts\n * const audio = LanguageModel.streamTurn(turnReq).pipe(\n * Stream.filterMap(Turn.toTextDelta),\n * SpeechSynthesizer.streamSynthesisFrom(synthReq),\n * )\n * ```\n */\nexport const streamSynthesisFrom: {\n (\n request: CommonStreamSynthesizeRequest,\n ): <E, R>(\n textIn: Stream.Stream<string, E, R>,\n ) => Stream.Stream<AudioChunk, AiError.AiError | E, R | SpeechSynthesizer | TtsIncrementalText>\n <E, R>(\n textIn: Stream.Stream<string, E, R>,\n request: CommonStreamSynthesizeRequest,\n ): Stream.Stream<AudioChunk, AiError.AiError | E, R | SpeechSynthesizer | TtsIncrementalText>\n} = Function.dual(\n 2,\n <E, R>(textIn: Stream.Stream<string, E, R>, request: CommonStreamSynthesizeRequest) =>\n Stream.unwrap(\n Effect.gen(function* () {\n const s = yield* SpeechSynthesizer\n yield* TtsIncrementalText\n return s.streamSynthesisFrom(textIn, request)\n }),\n ),\n)\n\n/**\n * One-shot multi-speaker dialogue. Requires `MultiSpeakerTts` in R —\n * providers without dialogue support are a compile-time error.\n */\nexport const synthesizeDialogue = (\n request: CommonSynthesizeDialogueRequest,\n): Effect.Effect<AudioBlob, AiError.AiError, SpeechSynthesizer | MultiSpeakerTts> =>\n Effect.gen(function* () {\n const s = yield* SpeechSynthesizer\n yield* MultiSpeakerTts\n return yield* s.synthesizeDialogue(request)\n })\n\n/**\n * Chunked-streaming variant. Same R requirement as `synthesizeDialogue`.\n */\nexport const streamSynthesizeDialogue = (\n request: CommonSynthesizeDialogueRequest,\n): Stream.Stream<AudioChunk, AiError.AiError, SpeechSynthesizer | MultiSpeakerTts> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const s = yield* SpeechSynthesizer\n yield* MultiSpeakerTts\n return s.streamSynthesizeDialogue(request)\n }),\n )\n"],"mappings":";;;;;;;;;;;;;AAuIA,IAAa,oBAAb,cAAuC,QAAQ,QAG7C,CAAC,CAAC,wCAAwC,CAAC,CAAC,CAAC;;;;;;;;;;;AAY/C,IAAa,qBAAb,cAAwC,QAAQ,QAAkC,CAAC,CACjF,oDACF,CAAC,CAAC,CAAC;;;;;;;;;;AAWH,IAAa,kBAAb,cAAqC,QAAQ,QAA+B,CAAC,CAC3E,iDACF,CAAC,CAAC,CAAC;;AAGH,MAAa,cACX,YAEA,OAAO,QAAQ,oBAAoB,MAAM,EAAE,WAAW,OAAO,CAAC;;AAGhE,MAAa,mBACX,YAEA,OAAO,OAAO,OAAO,IAAI,oBAAoB,MAAM,EAAE,gBAAgB,OAAO,CAAC,CAAC;;;;;;;;;;;;;;AAehF,MAAa,sBAUT,SAAS,KACX,IACO,QAAqC,YAC1C,OAAO,OACL,OAAO,IAAI,aAAa;CACtB,MAAM,IAAI,OAAO;CACjB,OAAO;CACP,OAAO,EAAE,oBAAoB,QAAQ,OAAO;AAC9C,CAAC,CACH,CACJ;;;;;AAMA,MAAa,sBACX,YAEA,OAAO,IAAI,aAAa;CACtB,MAAM,IAAI,OAAO;CACjB,OAAO;CACP,OAAO,OAAO,EAAE,mBAAmB,OAAO;AAC5C,CAAC;;;;AAKH,MAAa,4BACX,YAEA,OAAO,OACL,OAAO,IAAI,aAAa;CACtB,MAAM,IAAI,OAAO;CACjB,OAAO;CACP,OAAO,EAAE,yBAAyB,OAAO;AAC3C,CAAC,CACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { streamSynthesis, streamSynthesisFrom, streamSynthesizeDialogue, synthesize, synthesizeDialogue } from "./SpeechSynthesizer.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { m as it, o as describe } from "../utils-CiH_DjFW.mjs";
|
|
3
|
+
import { n as globalExpect } from "../test.DNmyFkvJ-YPzDR0Co.mjs";
|
|
4
|
+
import { t as import_dist } from "../dist-BaenoU1A.mjs";
|
|
3
5
|
import { layer, layerWithoutIncremental, layerWithoutMultiSpeaker } from "../testing/MockSpeechSynthesizer.mjs";
|
|
4
6
|
import { Duration, Effect, Stream } from "effect";
|
|
5
7
|
//#region src/speech-synthesizer/SpeechSynthesizer.test.ts
|
|
@@ -43,7 +45,8 @@ describe("SpeechSynthesizer.streamSynthesis", () => {
|
|
|
43
45
|
model: "mock-tts",
|
|
44
46
|
voiceId: "stock-voice"
|
|
45
47
|
}));
|
|
46
|
-
|
|
48
|
+
const out = await Effect.runPromise(program.pipe(Effect.provide(mock.layer)));
|
|
49
|
+
globalExpect(out.map((c) => Array.from(c.bytes))).toEqual([
|
|
47
50
|
[1],
|
|
48
51
|
[2],
|
|
49
52
|
[3]
|
|
@@ -56,31 +59,36 @@ describe("SpeechSynthesizer capability marker (compile-time)", () => {
|
|
|
56
59
|
voiceId: "v"
|
|
57
60
|
};
|
|
58
61
|
it("requires `TtsIncrementalText` on the R channel of streamSynthesisFrom", () => {
|
|
59
|
-
|
|
62
|
+
const audio = Stream.fromIterable(["a"]).pipe(streamSynthesisFrom(ssfReq));
|
|
63
|
+
(0, import_dist.expectTypeOf)(audio).toEqualTypeOf();
|
|
60
64
|
});
|
|
61
65
|
it("does NOT require `TtsIncrementalText` for sync `synthesize`", () => {
|
|
62
|
-
|
|
66
|
+
const eff = synthesize({
|
|
63
67
|
text: "hi",
|
|
64
68
|
model: "m",
|
|
65
69
|
voiceId: "v"
|
|
66
|
-
})
|
|
70
|
+
});
|
|
71
|
+
(0, import_dist.expectTypeOf)(eff).toEqualTypeOf();
|
|
67
72
|
});
|
|
68
73
|
it("does NOT require `TtsIncrementalText` for full-text `streamSynthesis`", () => {
|
|
69
|
-
|
|
74
|
+
const audio = streamSynthesis({
|
|
70
75
|
text: "hi",
|
|
71
76
|
model: "m",
|
|
72
77
|
voiceId: "v"
|
|
73
|
-
})
|
|
78
|
+
});
|
|
79
|
+
(0, import_dist.expectTypeOf)(audio).toEqualTypeOf();
|
|
74
80
|
});
|
|
75
81
|
it("a layer without the marker leaves `TtsIncrementalText` unsatisfied in R", () => {
|
|
76
82
|
const noMarker = layerWithoutIncremental({});
|
|
77
83
|
const audio = Stream.fromIterable(["a"]).pipe(streamSynthesisFrom(ssfReq));
|
|
78
|
-
|
|
84
|
+
const program = Stream.runDrain(audio).pipe(Effect.provide(noMarker.layer));
|
|
85
|
+
(0, import_dist.expectTypeOf)(program).toEqualTypeOf();
|
|
79
86
|
});
|
|
80
87
|
it("a full layer (with marker) clears R to never", () => {
|
|
81
88
|
const fullMock = layer({ streamSynthesisFromChunks: [[]] });
|
|
82
89
|
const audio = Stream.fromIterable(["a"]).pipe(streamSynthesisFrom(ssfReq));
|
|
83
|
-
|
|
90
|
+
const program = Stream.runDrain(audio).pipe(Effect.provide(fullMock.layer));
|
|
91
|
+
(0, import_dist.expectTypeOf)(program).toEqualTypeOf();
|
|
84
92
|
});
|
|
85
93
|
});
|
|
86
94
|
describe("SpeechSynthesizer.synthesizeDialogue", () => {
|
|
@@ -96,7 +104,8 @@ describe("SpeechSynthesizer.synthesizeDialogue", () => {
|
|
|
96
104
|
};
|
|
97
105
|
it("returns the scripted AudioBlob", async () => {
|
|
98
106
|
const mock = layer({ dialogueBlobs: [blob] });
|
|
99
|
-
|
|
107
|
+
const result = await Effect.runPromise(synthesizeDialogue(dialogueReq).pipe(Effect.provide(mock.layer)));
|
|
108
|
+
globalExpect(result.bytes).toEqual(blob.bytes);
|
|
100
109
|
});
|
|
101
110
|
it("records the request on the synthesizeDialogue call channel", async () => {
|
|
102
111
|
const mock = layer({ dialogueBlobs: [blob] });
|
|
@@ -111,7 +120,8 @@ describe("SpeechSynthesizer.synthesizeDialogue", () => {
|
|
|
111
120
|
});
|
|
112
121
|
it("emits scripted chunks for streamSynthesizeDialogue", async () => {
|
|
113
122
|
const mock = layer({ streamSynthesizeDialogueChunks: [[chunk(7), chunk(8)]] });
|
|
114
|
-
|
|
123
|
+
const out = await Effect.runPromise(Stream.runCollect(streamSynthesizeDialogue(dialogueReq)).pipe(Effect.provide(mock.layer)));
|
|
124
|
+
globalExpect(out.map((c) => Array.from(c.bytes))).toEqual([[7], [8]]);
|
|
115
125
|
});
|
|
116
126
|
});
|
|
117
127
|
describe("MultiSpeakerTts capability marker (compile-time)", () => {
|
|
@@ -123,18 +133,22 @@ describe("MultiSpeakerTts capability marker (compile-time)", () => {
|
|
|
123
133
|
}]
|
|
124
134
|
};
|
|
125
135
|
it("requires `MultiSpeakerTts` on the R channel of synthesizeDialogue", () => {
|
|
126
|
-
|
|
136
|
+
const eff = synthesizeDialogue(dialogueReq);
|
|
137
|
+
(0, import_dist.expectTypeOf)(eff).toEqualTypeOf();
|
|
127
138
|
});
|
|
128
139
|
it("requires `MultiSpeakerTts` on the R channel of streamSynthesizeDialogue", () => {
|
|
129
|
-
|
|
140
|
+
const s = streamSynthesizeDialogue(dialogueReq);
|
|
141
|
+
(0, import_dist.expectTypeOf)(s).toEqualTypeOf();
|
|
130
142
|
});
|
|
131
143
|
it("a layer without the marker leaves `MultiSpeakerTts` unsatisfied in R", () => {
|
|
132
144
|
const noMarker = layerWithoutMultiSpeaker({});
|
|
133
|
-
|
|
145
|
+
const program = synthesizeDialogue(dialogueReq).pipe(Effect.provide(noMarker.layer));
|
|
146
|
+
(0, import_dist.expectTypeOf)(program).toEqualTypeOf();
|
|
134
147
|
});
|
|
135
148
|
it("a full layer (with marker) clears R to never", () => {
|
|
136
149
|
const fullMock = layer({ dialogueBlobs: [blob] });
|
|
137
|
-
|
|
150
|
+
const program = synthesizeDialogue(dialogueReq).pipe(Effect.provide(fullMock.layer));
|
|
151
|
+
(0, import_dist.expectTypeOf)(program).toEqualTypeOf();
|
|
138
152
|
});
|
|
139
153
|
});
|
|
140
154
|
describe("SpeechSynthesizer.streamSynthesisFrom", () => {
|
|
@@ -145,7 +159,8 @@ describe("SpeechSynthesizer.streamSynthesisFrom", () => {
|
|
|
145
159
|
it("pipes an LLM-style text stream into audio chunks", async () => {
|
|
146
160
|
const mock = layer({ streamSynthesisFromChunks: [[chunk(10), chunk(20)]] });
|
|
147
161
|
const audio = Stream.fromIterable(["Hello, ", "world."]).pipe(streamSynthesisFrom(ssfReq));
|
|
148
|
-
|
|
162
|
+
const out = await Effect.runPromise(Stream.runCollect(audio).pipe(Effect.provide(mock.layer)));
|
|
163
|
+
globalExpect(out.map((c) => Array.from(c.bytes))).toEqual([[10], [20]]);
|
|
149
164
|
});
|
|
150
165
|
it("records the request on the streamSynthesisFrom call channel", async () => {
|
|
151
166
|
const mock = layer({ streamSynthesisFromChunks: [[chunk(42)]] });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpeechSynthesizer.test.mjs","names":["MockSpeechSynthesizer.layer","SpeechSynthesizer.synthesize","SpeechSynthesizer.streamSynthesis","SpeechSynthesizer.streamSynthesisFrom","MockSpeechSynthesizer.layerWithoutIncremental","SpeechSynthesizer.synthesizeDialogue","SpeechSynthesizer.streamSynthesizeDialogue","MockSpeechSynthesizer.layerWithoutMultiSpeaker"],"sources":["../../src/speech-synthesizer/SpeechSynthesizer.test.ts"],"sourcesContent":["import { Duration, Effect, Stream } from \"effect\"\nimport { describe, expect, expectTypeOf, it } from \"vitest\"\nimport type * as AiError from \"../domain/AiError.js\"\nimport type { AudioBlob, AudioChunk, AudioFormat } from \"../domain/Audio.js\"\nimport * as MockSpeechSynthesizer from \"../testing/MockSpeechSynthesizer.js\"\nimport * as SpeechSynthesizer from \"./SpeechSynthesizer.js\"\n\nconst pcmFormat: AudioFormat = {\n container: \"raw\",\n encoding: \"pcm_s16le\",\n sampleRate: 24000,\n}\n\nconst blob: AudioBlob = {\n format: pcmFormat,\n bytes: new Uint8Array([0xde, 0xad, 0xbe, 0xef]),\n duration: Duration.millis(500),\n}\n\nconst chunk = (n: number): AudioChunk => ({ bytes: new Uint8Array([n]) })\n\ndescribe(\"SpeechSynthesizer.synthesize\", () => {\n it(\"returns the scripted AudioBlob\", async () => {\n const mock = MockSpeechSynthesizer.layer({ blobs: [blob] })\n const program = SpeechSynthesizer.synthesize({\n text: \"hi\",\n model: \"mock-tts\",\n voiceId: \"stock-voice\",\n })\n const result = await Effect.runPromise(program.pipe(Effect.provide(mock.layer)))\n expect(result.bytes).toEqual(blob.bytes)\n expect(result.duration).toEqual(Duration.millis(500))\n })\n})\n\ndescribe(\"SpeechSynthesizer.streamSynthesis\", () => {\n it(\"emits scripted chunks for full-text-in streaming\", async () => {\n const mock = MockSpeechSynthesizer.layer({\n streamSynthesisChunks: [[chunk(1), chunk(2), chunk(3)]],\n })\n const program = Stream.runCollect(\n SpeechSynthesizer.streamSynthesis({\n text: \"hi\",\n model: \"mock-tts\",\n voiceId: \"stock-voice\",\n }),\n )\n const out = await Effect.runPromise(program.pipe(Effect.provide(mock.layer)))\n expect(out.map((c) => Array.from(c.bytes))).toEqual([[1], [2], [3]])\n })\n})\n\ndescribe(\"SpeechSynthesizer capability marker (compile-time)\", () => {\n const ssfReq: SpeechSynthesizer.CommonStreamSynthesizeRequest = {\n model: \"mock-tts\",\n voiceId: \"v\",\n }\n\n it(\"requires `TtsIncrementalText` on the R channel of streamSynthesisFrom\", () => {\n const tokens: Stream.Stream<string> = Stream.fromIterable([\"a\"])\n const audio = tokens.pipe(SpeechSynthesizer.streamSynthesisFrom(ssfReq))\n expectTypeOf(audio).toEqualTypeOf<\n Stream.Stream<\n AudioChunk,\n AiError.AiError,\n SpeechSynthesizer.SpeechSynthesizer | SpeechSynthesizer.TtsIncrementalText\n >\n >()\n })\n\n it(\"does NOT require `TtsIncrementalText` for sync `synthesize`\", () => {\n const eff = SpeechSynthesizer.synthesize({ text: \"hi\", model: \"m\", voiceId: \"v\" })\n expectTypeOf(eff).toEqualTypeOf<\n Effect.Effect<AudioBlob, AiError.AiError, SpeechSynthesizer.SpeechSynthesizer>\n >()\n })\n\n it(\"does NOT require `TtsIncrementalText` for full-text `streamSynthesis`\", () => {\n const audio = SpeechSynthesizer.streamSynthesis({ text: \"hi\", model: \"m\", voiceId: \"v\" })\n expectTypeOf(audio).toEqualTypeOf<\n Stream.Stream<AudioChunk, AiError.AiError, SpeechSynthesizer.SpeechSynthesizer>\n >()\n })\n\n it(\"a layer without the marker leaves `TtsIncrementalText` unsatisfied in R\", () => {\n const noMarker = MockSpeechSynthesizer.layerWithoutIncremental({})\n const tokens: Stream.Stream<string> = Stream.fromIterable([\"a\"])\n const audio = tokens.pipe(SpeechSynthesizer.streamSynthesisFrom(ssfReq))\n const program = Stream.runDrain(audio).pipe(Effect.provide(noMarker.layer))\n // `SpeechSynthesizer` is provided by the layer; `TtsIncrementalText` is not,\n // so it remains in R — calling `Effect.runPromise(program)` would be a type\n // error because runPromise requires `R = never`.\n expectTypeOf(program).toEqualTypeOf<\n Effect.Effect<void, AiError.AiError, SpeechSynthesizer.TtsIncrementalText>\n >()\n })\n\n it(\"a full layer (with marker) clears R to never\", () => {\n const fullMock = MockSpeechSynthesizer.layer({\n streamSynthesisFromChunks: [[]],\n })\n const tokens: Stream.Stream<string> = Stream.fromIterable([\"a\"])\n const audio = tokens.pipe(SpeechSynthesizer.streamSynthesisFrom(ssfReq))\n const program = Stream.runDrain(audio).pipe(Effect.provide(fullMock.layer))\n expectTypeOf(program).toEqualTypeOf<Effect.Effect<void, AiError.AiError, never>>()\n })\n})\n\ndescribe(\"SpeechSynthesizer.synthesizeDialogue\", () => {\n const dialogueReq: SpeechSynthesizer.CommonSynthesizeDialogueRequest = {\n model: \"mock-tts\",\n turns: [\n { voiceId: \"voice-a\", text: \"Hi\" },\n { voiceId: \"voice-b\", text: \"Hello\" },\n ],\n }\n\n it(\"returns the scripted AudioBlob\", async () => {\n const mock = MockSpeechSynthesizer.layer({ dialogueBlobs: [blob] })\n const result = await Effect.runPromise(\n SpeechSynthesizer.synthesizeDialogue(dialogueReq).pipe(Effect.provide(mock.layer)),\n )\n expect(result.bytes).toEqual(blob.bytes)\n })\n\n it(\"records the request on the synthesizeDialogue call channel\", async () => {\n const mock = MockSpeechSynthesizer.layer({ dialogueBlobs: [blob] })\n const program = Effect.gen(function* () {\n yield* SpeechSynthesizer.synthesizeDialogue(dialogueReq)\n return yield* mock.recorder\n })\n const rec = await Effect.runPromise(program.pipe(Effect.provide(mock.layer)))\n expect(rec.synthesizeDialogueCalls.length).toBe(1)\n expect(rec.synthesizeDialogueCalls[0]!.turns.length).toBe(2)\n expect(rec.synthesizeCalls.length).toBe(0)\n })\n\n it(\"emits scripted chunks for streamSynthesizeDialogue\", async () => {\n const mock = MockSpeechSynthesizer.layer({\n streamSynthesizeDialogueChunks: [[chunk(7), chunk(8)]],\n })\n const out = await Effect.runPromise(\n Stream.runCollect(SpeechSynthesizer.streamSynthesizeDialogue(dialogueReq)).pipe(\n Effect.provide(mock.layer),\n ),\n )\n expect(out.map((c) => Array.from(c.bytes))).toEqual([[7], [8]])\n })\n})\n\ndescribe(\"MultiSpeakerTts capability marker (compile-time)\", () => {\n const dialogueReq: SpeechSynthesizer.CommonSynthesizeDialogueRequest = {\n model: \"mock-tts\",\n turns: [{ voiceId: \"a\", text: \"Hi\" }],\n }\n\n it(\"requires `MultiSpeakerTts` on the R channel of synthesizeDialogue\", () => {\n const eff = SpeechSynthesizer.synthesizeDialogue(dialogueReq)\n expectTypeOf(eff).toEqualTypeOf<\n Effect.Effect<\n AudioBlob,\n AiError.AiError,\n SpeechSynthesizer.SpeechSynthesizer | SpeechSynthesizer.MultiSpeakerTts\n >\n >()\n })\n\n it(\"requires `MultiSpeakerTts` on the R channel of streamSynthesizeDialogue\", () => {\n const s = SpeechSynthesizer.streamSynthesizeDialogue(dialogueReq)\n expectTypeOf(s).toEqualTypeOf<\n Stream.Stream<\n AudioChunk,\n AiError.AiError,\n SpeechSynthesizer.SpeechSynthesizer | SpeechSynthesizer.MultiSpeakerTts\n >\n >()\n })\n\n it(\"a layer without the marker leaves `MultiSpeakerTts` unsatisfied in R\", () => {\n const noMarker = MockSpeechSynthesizer.layerWithoutMultiSpeaker({})\n const program = SpeechSynthesizer.synthesizeDialogue(dialogueReq).pipe(\n Effect.provide(noMarker.layer),\n )\n expectTypeOf(program).toEqualTypeOf<\n Effect.Effect<AudioBlob, AiError.AiError, SpeechSynthesizer.MultiSpeakerTts>\n >()\n })\n\n it(\"a full layer (with marker) clears R to never\", () => {\n const fullMock = MockSpeechSynthesizer.layer({ dialogueBlobs: [blob] })\n const program = SpeechSynthesizer.synthesizeDialogue(dialogueReq).pipe(\n Effect.provide(fullMock.layer),\n )\n expectTypeOf(program).toEqualTypeOf<Effect.Effect<AudioBlob, AiError.AiError, never>>()\n })\n})\n\ndescribe(\"SpeechSynthesizer.streamSynthesisFrom\", () => {\n const ssfReq: SpeechSynthesizer.CommonStreamSynthesizeRequest = {\n model: \"mock-tts\",\n voiceId: \"stock-voice\",\n }\n\n it(\"pipes an LLM-style text stream into audio chunks\", async () => {\n const mock = MockSpeechSynthesizer.layer({\n streamSynthesisFromChunks: [[chunk(10), chunk(20)]],\n })\n const tokens = Stream.fromIterable([\"Hello, \", \"world.\"])\n const audio = tokens.pipe(SpeechSynthesizer.streamSynthesisFrom(ssfReq))\n const out = await Effect.runPromise(Stream.runCollect(audio).pipe(Effect.provide(mock.layer)))\n expect(out.map((c) => Array.from(c.bytes))).toEqual([[10], [20]])\n })\n\n it(\"records the request on the streamSynthesisFrom call channel\", async () => {\n const mock = MockSpeechSynthesizer.layer({\n streamSynthesisFromChunks: [[chunk(42)]],\n })\n const program = Effect.gen(function* () {\n yield* Stream.runDrain(\n Stream.fromIterable([\"x\"]).pipe(SpeechSynthesizer.streamSynthesisFrom(ssfReq)),\n )\n return yield* mock.recorder\n })\n const rec = await Effect.runPromise(program.pipe(Effect.provide(mock.layer)))\n expect(rec.streamSynthesisFromCalls.length).toBe(1)\n expect(rec.streamSynthesisFromCalls[0]!.voiceId).toBe(\"stock-voice\")\n expect(rec.synthesizeCalls.length).toBe(0)\n expect(rec.streamSynthesisCalls.length).toBe(0)\n })\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SpeechSynthesizer.test.mjs","names":["MockSpeechSynthesizer.layer","SpeechSynthesizer.synthesize","SpeechSynthesizer.streamSynthesis","SpeechSynthesizer.streamSynthesisFrom","MockSpeechSynthesizer.layerWithoutIncremental","SpeechSynthesizer.synthesizeDialogue","SpeechSynthesizer.streamSynthesizeDialogue","MockSpeechSynthesizer.layerWithoutMultiSpeaker"],"sources":["../../src/speech-synthesizer/SpeechSynthesizer.test.ts"],"sourcesContent":["import { Duration, Effect, Stream } from \"effect\"\nimport { describe, expect, expectTypeOf, it } from \"vitest\"\nimport type * as AiError from \"../domain/AiError.js\"\nimport type { AudioBlob, AudioChunk, AudioFormat } from \"../domain/Audio.js\"\nimport * as MockSpeechSynthesizer from \"../testing/MockSpeechSynthesizer.js\"\nimport * as SpeechSynthesizer from \"./SpeechSynthesizer.js\"\n\nconst pcmFormat: AudioFormat = {\n container: \"raw\",\n encoding: \"pcm_s16le\",\n sampleRate: 24000,\n}\n\nconst blob: AudioBlob = {\n format: pcmFormat,\n bytes: new Uint8Array([0xde, 0xad, 0xbe, 0xef]),\n duration: Duration.millis(500),\n}\n\nconst chunk = (n: number): AudioChunk => ({ bytes: new Uint8Array([n]) })\n\ndescribe(\"SpeechSynthesizer.synthesize\", () => {\n it(\"returns the scripted AudioBlob\", async () => {\n const mock = MockSpeechSynthesizer.layer({ blobs: [blob] })\n const program = SpeechSynthesizer.synthesize({\n text: \"hi\",\n model: \"mock-tts\",\n voiceId: \"stock-voice\",\n })\n const result = await Effect.runPromise(program.pipe(Effect.provide(mock.layer)))\n expect(result.bytes).toEqual(blob.bytes)\n expect(result.duration).toEqual(Duration.millis(500))\n })\n})\n\ndescribe(\"SpeechSynthesizer.streamSynthesis\", () => {\n it(\"emits scripted chunks for full-text-in streaming\", async () => {\n const mock = MockSpeechSynthesizer.layer({\n streamSynthesisChunks: [[chunk(1), chunk(2), chunk(3)]],\n })\n const program = Stream.runCollect(\n SpeechSynthesizer.streamSynthesis({\n text: \"hi\",\n model: \"mock-tts\",\n voiceId: \"stock-voice\",\n }),\n )\n const out = await Effect.runPromise(program.pipe(Effect.provide(mock.layer)))\n expect(out.map((c) => Array.from(c.bytes))).toEqual([[1], [2], [3]])\n })\n})\n\ndescribe(\"SpeechSynthesizer capability marker (compile-time)\", () => {\n const ssfReq: SpeechSynthesizer.CommonStreamSynthesizeRequest = {\n model: \"mock-tts\",\n voiceId: \"v\",\n }\n\n it(\"requires `TtsIncrementalText` on the R channel of streamSynthesisFrom\", () => {\n const tokens: Stream.Stream<string> = Stream.fromIterable([\"a\"])\n const audio = tokens.pipe(SpeechSynthesizer.streamSynthesisFrom(ssfReq))\n expectTypeOf(audio).toEqualTypeOf<\n Stream.Stream<\n AudioChunk,\n AiError.AiError,\n SpeechSynthesizer.SpeechSynthesizer | SpeechSynthesizer.TtsIncrementalText\n >\n >()\n })\n\n it(\"does NOT require `TtsIncrementalText` for sync `synthesize`\", () => {\n const eff = SpeechSynthesizer.synthesize({ text: \"hi\", model: \"m\", voiceId: \"v\" })\n expectTypeOf(eff).toEqualTypeOf<\n Effect.Effect<AudioBlob, AiError.AiError, SpeechSynthesizer.SpeechSynthesizer>\n >()\n })\n\n it(\"does NOT require `TtsIncrementalText` for full-text `streamSynthesis`\", () => {\n const audio = SpeechSynthesizer.streamSynthesis({ text: \"hi\", model: \"m\", voiceId: \"v\" })\n expectTypeOf(audio).toEqualTypeOf<\n Stream.Stream<AudioChunk, AiError.AiError, SpeechSynthesizer.SpeechSynthesizer>\n >()\n })\n\n it(\"a layer without the marker leaves `TtsIncrementalText` unsatisfied in R\", () => {\n const noMarker = MockSpeechSynthesizer.layerWithoutIncremental({})\n const tokens: Stream.Stream<string> = Stream.fromIterable([\"a\"])\n const audio = tokens.pipe(SpeechSynthesizer.streamSynthesisFrom(ssfReq))\n const program = Stream.runDrain(audio).pipe(Effect.provide(noMarker.layer))\n // `SpeechSynthesizer` is provided by the layer; `TtsIncrementalText` is not,\n // so it remains in R — calling `Effect.runPromise(program)` would be a type\n // error because runPromise requires `R = never`.\n expectTypeOf(program).toEqualTypeOf<\n Effect.Effect<void, AiError.AiError, SpeechSynthesizer.TtsIncrementalText>\n >()\n })\n\n it(\"a full layer (with marker) clears R to never\", () => {\n const fullMock = MockSpeechSynthesizer.layer({\n streamSynthesisFromChunks: [[]],\n })\n const tokens: Stream.Stream<string> = Stream.fromIterable([\"a\"])\n const audio = tokens.pipe(SpeechSynthesizer.streamSynthesisFrom(ssfReq))\n const program = Stream.runDrain(audio).pipe(Effect.provide(fullMock.layer))\n expectTypeOf(program).toEqualTypeOf<Effect.Effect<void, AiError.AiError, never>>()\n })\n})\n\ndescribe(\"SpeechSynthesizer.synthesizeDialogue\", () => {\n const dialogueReq: SpeechSynthesizer.CommonSynthesizeDialogueRequest = {\n model: \"mock-tts\",\n turns: [\n { voiceId: \"voice-a\", text: \"Hi\" },\n { voiceId: \"voice-b\", text: \"Hello\" },\n ],\n }\n\n it(\"returns the scripted AudioBlob\", async () => {\n const mock = MockSpeechSynthesizer.layer({ dialogueBlobs: [blob] })\n const result = await Effect.runPromise(\n SpeechSynthesizer.synthesizeDialogue(dialogueReq).pipe(Effect.provide(mock.layer)),\n )\n expect(result.bytes).toEqual(blob.bytes)\n })\n\n it(\"records the request on the synthesizeDialogue call channel\", async () => {\n const mock = MockSpeechSynthesizer.layer({ dialogueBlobs: [blob] })\n const program = Effect.gen(function* () {\n yield* SpeechSynthesizer.synthesizeDialogue(dialogueReq)\n return yield* mock.recorder\n })\n const rec = await Effect.runPromise(program.pipe(Effect.provide(mock.layer)))\n expect(rec.synthesizeDialogueCalls.length).toBe(1)\n expect(rec.synthesizeDialogueCalls[0]!.turns.length).toBe(2)\n expect(rec.synthesizeCalls.length).toBe(0)\n })\n\n it(\"emits scripted chunks for streamSynthesizeDialogue\", async () => {\n const mock = MockSpeechSynthesizer.layer({\n streamSynthesizeDialogueChunks: [[chunk(7), chunk(8)]],\n })\n const out = await Effect.runPromise(\n Stream.runCollect(SpeechSynthesizer.streamSynthesizeDialogue(dialogueReq)).pipe(\n Effect.provide(mock.layer),\n ),\n )\n expect(out.map((c) => Array.from(c.bytes))).toEqual([[7], [8]])\n })\n})\n\ndescribe(\"MultiSpeakerTts capability marker (compile-time)\", () => {\n const dialogueReq: SpeechSynthesizer.CommonSynthesizeDialogueRequest = {\n model: \"mock-tts\",\n turns: [{ voiceId: \"a\", text: \"Hi\" }],\n }\n\n it(\"requires `MultiSpeakerTts` on the R channel of synthesizeDialogue\", () => {\n const eff = SpeechSynthesizer.synthesizeDialogue(dialogueReq)\n expectTypeOf(eff).toEqualTypeOf<\n Effect.Effect<\n AudioBlob,\n AiError.AiError,\n SpeechSynthesizer.SpeechSynthesizer | SpeechSynthesizer.MultiSpeakerTts\n >\n >()\n })\n\n it(\"requires `MultiSpeakerTts` on the R channel of streamSynthesizeDialogue\", () => {\n const s = SpeechSynthesizer.streamSynthesizeDialogue(dialogueReq)\n expectTypeOf(s).toEqualTypeOf<\n Stream.Stream<\n AudioChunk,\n AiError.AiError,\n SpeechSynthesizer.SpeechSynthesizer | SpeechSynthesizer.MultiSpeakerTts\n >\n >()\n })\n\n it(\"a layer without the marker leaves `MultiSpeakerTts` unsatisfied in R\", () => {\n const noMarker = MockSpeechSynthesizer.layerWithoutMultiSpeaker({})\n const program = SpeechSynthesizer.synthesizeDialogue(dialogueReq).pipe(\n Effect.provide(noMarker.layer),\n )\n expectTypeOf(program).toEqualTypeOf<\n Effect.Effect<AudioBlob, AiError.AiError, SpeechSynthesizer.MultiSpeakerTts>\n >()\n })\n\n it(\"a full layer (with marker) clears R to never\", () => {\n const fullMock = MockSpeechSynthesizer.layer({ dialogueBlobs: [blob] })\n const program = SpeechSynthesizer.synthesizeDialogue(dialogueReq).pipe(\n Effect.provide(fullMock.layer),\n )\n expectTypeOf(program).toEqualTypeOf<Effect.Effect<AudioBlob, AiError.AiError, never>>()\n })\n})\n\ndescribe(\"SpeechSynthesizer.streamSynthesisFrom\", () => {\n const ssfReq: SpeechSynthesizer.CommonStreamSynthesizeRequest = {\n model: \"mock-tts\",\n voiceId: \"stock-voice\",\n }\n\n it(\"pipes an LLM-style text stream into audio chunks\", async () => {\n const mock = MockSpeechSynthesizer.layer({\n streamSynthesisFromChunks: [[chunk(10), chunk(20)]],\n })\n const tokens = Stream.fromIterable([\"Hello, \", \"world.\"])\n const audio = tokens.pipe(SpeechSynthesizer.streamSynthesisFrom(ssfReq))\n const out = await Effect.runPromise(Stream.runCollect(audio).pipe(Effect.provide(mock.layer)))\n expect(out.map((c) => Array.from(c.bytes))).toEqual([[10], [20]])\n })\n\n it(\"records the request on the streamSynthesisFrom call channel\", async () => {\n const mock = MockSpeechSynthesizer.layer({\n streamSynthesisFromChunks: [[chunk(42)]],\n })\n const program = Effect.gen(function* () {\n yield* Stream.runDrain(\n Stream.fromIterable([\"x\"]).pipe(SpeechSynthesizer.streamSynthesisFrom(ssfReq)),\n )\n return yield* mock.recorder\n })\n const rec = await Effect.runPromise(program.pipe(Effect.provide(mock.layer)))\n expect(rec.streamSynthesisFromCalls.length).toBe(1)\n expect(rec.streamSynthesisFromCalls[0]!.voiceId).toBe(\"stock-voice\")\n expect(rec.synthesizeCalls.length).toBe(0)\n expect(rec.streamSynthesisCalls.length).toBe(0)\n })\n})\n"],"mappings":"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"}
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import { Effect, Schema, Stream } from "effect";
|
|
2
|
-
import * as _$effect_Cause0 from "effect/Cause";
|
|
3
|
-
import * as _$effect_Types0 from "effect/Types";
|
|
4
|
-
|
|
5
|
-
//#region src/streaming/JSONL.d.ts
|
|
6
2
|
declare namespace JSONL_d_exports {
|
|
7
3
|
export { JsonParseError, fromBytes, parse, parseSafe, toBytes };
|
|
8
4
|
}
|
|
9
|
-
declare const JsonParseError_base: new <A extends Record<string, any> = {}>(args:
|
|
5
|
+
declare const JsonParseError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
10
6
|
readonly _tag: "JsonParseError";
|
|
11
7
|
} & Readonly<A>;
|
|
12
8
|
declare class JsonParseError extends JsonParseError_base<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSONL.d.mts","names":[],"sources":["../../src/streaming/JSONL.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"JSONL.d.mts","names":[],"sources":["../../src/streaming/JSONL.ts"],"mappings":";;;;;;;cAEa,uBAAuB;WACzB;WACA;;;;;;;;cAaE,YAAa,GAAG,GAAC,MACtB,OAAO,OAAO,YAAY,GAAG,OAClC,OAAO,eAAe,GAAG;;;;;;cAYf,QAAS,GAAG,GAAC,QAAU,OAAO,MAAM,GAAG,QAE1C,GAAG,GAAC,MAAQ,OAAO,eAAe,GAAG,OAAK,OAAO,OAAO,GAAG,iBAAiB,GAAG;;;;;;;cAgB5E,YAAS,gBAAkB,OAAO;;;;;cASlC,UACV,GAAG,GAAC,QAAU,OAAO,MAAM,GAAG,QAC9B,GAAG,GAAC,MAAQ,OAAO,OAAO,GAAG,GAAG,OAAK,OAAO,OAAO,YAAY,GAAG"}
|
package/dist/streaming/JSONL.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as __exportAll } from "../
|
|
1
|
+
import { n as __exportAll } from "../rolldown-runtime-EAsCxrDo.mjs";
|
|
2
2
|
import { Channel, Data, Effect, Schema, Stream } from "effect";
|
|
3
3
|
//#region src/streaming/JSONL.ts
|
|
4
4
|
var JSONL_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSONL.mjs","names":[],"sources":["../../src/streaming/JSONL.ts"],"sourcesContent":["import { Channel, Data, Effect, Schema, Stream } from \"effect\"\n\nexport class JsonParseError extends Data.TaggedError(\"JsonParseError\")<{\n readonly line: string\n readonly cause: unknown\n}> {}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Decode a `Stream<Uint8Array>` into a `Stream<string>` of newline-delimited\n * lines. Empty lines are skipped. Buffers across chunk boundaries; a final\n * line without a trailing newline is emitted at clean stream end, while a\n * buffered partial line is discarded if the stream fails.\n */\nexport const fromBytes = <E, R>(\n self: Stream.Stream<Uint8Array, E, R>,\n): Stream.Stream<string, E, R> =>\n self.pipe(\n Stream.decodeText,\n Stream.pipeThroughChannel(Channel.splitLines()),\n Stream.filter((line) => line.length > 0),\n )\n\n/**\n * Validate each JSONL line against a Schema. JSON parse errors and Schema\n * decode errors both surface as a `JsonParseError` so callers can `catchTag`\n * uniformly.\n */\nexport const parse = <A, I>(schema: Schema.Codec<A, I>) => {\n const decode = Schema.decodeUnknownEffect(Schema.fromJsonString(schema))\n return <E, R>(self: Stream.Stream<string, E, R>): Stream.Stream<A, JsonParseError | E, R> =>\n self.pipe(\n Stream.mapEffect((line) =>\n decode(line).pipe(Effect.mapError((cause) => new JsonParseError({ line, cause }))),\n ),\n )\n}\n\nconst decodeUnknownFromJson = Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Unknown))\n\n/**\n * Best-effort parse of a single JSON frame. Returns the parsed value or\n * `undefined` on malformed input. Realtime WS adapters use this to skip\n * non-JSON or partially-received frames silently rather than fail the\n * entire session over one bad frame.\n */\nexport const parseSafe = (raw: string): Effect.Effect<unknown> =>\n decodeUnknownFromJson(raw).pipe(Effect.orElseSucceed(() => undefined))\n\nconst encoder = new TextEncoder()\n\n/**\n * Serialize a stream of values to JSONL bytes. Encodes each value via\n * `Schema.encodeUnknownSync`. Each line ends with `\\n`.\n */\nexport const toBytes =\n <A, I>(schema: Schema.Codec<A, I>) =>\n <E, R>(self: Stream.Stream<A, E, R>): Stream.Stream<Uint8Array, E, R> =>\n self.pipe(\n Stream.map((value) => {\n const encoded = Schema.encodeUnknownSync(schema)(value)\n return encoder.encode(JSON.stringify(encoded) + \"\\n\")\n }),\n )\n"],"mappings":";;;;;;;;;;AAEA,IAAa,iBAAb,cAAoC,KAAK,YAAY,
|
|
1
|
+
{"version":3,"file":"JSONL.mjs","names":[],"sources":["../../src/streaming/JSONL.ts"],"sourcesContent":["import { Channel, Data, Effect, Schema, Stream } from \"effect\"\n\nexport class JsonParseError extends Data.TaggedError(\"JsonParseError\")<{\n readonly line: string\n readonly cause: unknown\n}> {}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Decode a `Stream<Uint8Array>` into a `Stream<string>` of newline-delimited\n * lines. Empty lines are skipped. Buffers across chunk boundaries; a final\n * line without a trailing newline is emitted at clean stream end, while a\n * buffered partial line is discarded if the stream fails.\n */\nexport const fromBytes = <E, R>(\n self: Stream.Stream<Uint8Array, E, R>,\n): Stream.Stream<string, E, R> =>\n self.pipe(\n Stream.decodeText,\n Stream.pipeThroughChannel(Channel.splitLines()),\n Stream.filter((line) => line.length > 0),\n )\n\n/**\n * Validate each JSONL line against a Schema. JSON parse errors and Schema\n * decode errors both surface as a `JsonParseError` so callers can `catchTag`\n * uniformly.\n */\nexport const parse = <A, I>(schema: Schema.Codec<A, I>) => {\n const decode = Schema.decodeUnknownEffect(Schema.fromJsonString(schema))\n return <E, R>(self: Stream.Stream<string, E, R>): Stream.Stream<A, JsonParseError | E, R> =>\n self.pipe(\n Stream.mapEffect((line) =>\n decode(line).pipe(Effect.mapError((cause) => new JsonParseError({ line, cause }))),\n ),\n )\n}\n\nconst decodeUnknownFromJson = Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Unknown))\n\n/**\n * Best-effort parse of a single JSON frame. Returns the parsed value or\n * `undefined` on malformed input. Realtime WS adapters use this to skip\n * non-JSON or partially-received frames silently rather than fail the\n * entire session over one bad frame.\n */\nexport const parseSafe = (raw: string): Effect.Effect<unknown> =>\n decodeUnknownFromJson(raw).pipe(Effect.orElseSucceed(() => undefined))\n\nconst encoder = new TextEncoder()\n\n/**\n * Serialize a stream of values to JSONL bytes. Encodes each value via\n * `Schema.encodeUnknownSync`. Each line ends with `\\n`.\n */\nexport const toBytes =\n <A, I>(schema: Schema.Codec<A, I>) =>\n <E, R>(self: Stream.Stream<A, E, R>): Stream.Stream<Uint8Array, E, R> =>\n self.pipe(\n Stream.map((value) => {\n const encoded = Schema.encodeUnknownSync(schema)(value)\n return encoder.encode(JSON.stringify(encoded) + \"\\n\")\n }),\n )\n"],"mappings":";;;;;;;;;;AAEA,IAAa,iBAAb,cAAoC,KAAK,YAAY,gBAAgB,CAAC,CAGnE,CAAC;;;;;;;AAYJ,MAAa,aACX,SAEA,KAAK,KACH,OAAO,YACP,OAAO,mBAAmB,QAAQ,WAAW,CAAC,GAC9C,OAAO,QAAQ,SAAS,KAAK,SAAS,CAAC,CACzC;;;;;;AAOF,MAAa,SAAe,WAA+B;CACzD,MAAM,SAAS,OAAO,oBAAoB,OAAO,eAAe,MAAM,CAAC;CACvE,QAAc,SACZ,KAAK,KACH,OAAO,WAAW,SAChB,OAAO,IAAI,CAAC,CAAC,KAAK,OAAO,UAAU,UAAU,IAAI,eAAe;EAAE;EAAM;CAAM,CAAC,CAAC,CAAC,CACnF,CACF;AACJ;AAEA,MAAM,wBAAwB,OAAO,oBAAoB,OAAO,eAAe,OAAO,OAAO,CAAC;;;;;;;AAQ9F,MAAa,aAAa,QACxB,sBAAsB,GAAG,CAAC,CAAC,KAAK,OAAO,oBAAoB,KAAA,CAAS,CAAC;AAEvE,MAAM,UAAU,IAAI,YAAY;;;;;AAMhC,MAAa,WACJ,YACA,SACL,KAAK,KACH,OAAO,KAAK,UAAU;CACpB,MAAM,UAAU,OAAO,kBAAkB,MAAM,CAAC,CAAC,KAAK;CACtD,OAAO,QAAQ,OAAO,KAAK,UAAU,OAAO,IAAI,IAAI;AACtD,CAAC,CACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { fromBytes, parse, toBytes } from "./JSONL.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { m as it, o as describe } from "../utils-CiH_DjFW.mjs";
|
|
3
|
+
import { n as globalExpect } from "../test.DNmyFkvJ-YPzDR0Co.mjs";
|
|
3
4
|
import { Effect, Result, Schema, Stream } from "effect";
|
|
4
5
|
//#region src/streaming/JSONL.test.ts
|
|
5
6
|
const enc = new TextEncoder();
|
|
@@ -16,30 +17,36 @@ const Patch = Schema.Struct({
|
|
|
16
17
|
});
|
|
17
18
|
describe("JSONL.fromBytes", () => {
|
|
18
19
|
it("emits one string per line", async () => {
|
|
19
|
-
|
|
20
|
+
const out = await collect(fromBytes(bytesOf("a\nb\nc\n")));
|
|
21
|
+
globalExpect(out).toEqual([
|
|
20
22
|
"a",
|
|
21
23
|
"b",
|
|
22
24
|
"c"
|
|
23
25
|
]);
|
|
24
26
|
});
|
|
25
27
|
it("buffers lines across chunk boundaries", async () => {
|
|
26
|
-
|
|
28
|
+
const out = await collect(fromBytes(bytesOf("ab", "c\nde", "f\n")));
|
|
29
|
+
globalExpect(out).toEqual(["abc", "def"]);
|
|
27
30
|
});
|
|
28
31
|
it("flushes a trailing line without a final newline", async () => {
|
|
29
|
-
|
|
32
|
+
const out = await collect(fromBytes(bytesOf("a\nb")));
|
|
33
|
+
globalExpect(out).toEqual(["a", "b"]);
|
|
30
34
|
});
|
|
31
35
|
it("ignores blank lines", async () => {
|
|
32
|
-
|
|
36
|
+
const out = await collect(fromBytes(bytesOf("a\n\n\nb\n")));
|
|
37
|
+
globalExpect(out).toEqual(["a", "b"]);
|
|
33
38
|
});
|
|
34
39
|
it("discards a buffered partial line when the upstream fails mid-stream", async () => {
|
|
35
|
-
const
|
|
40
|
+
const failing = Stream.concat(bytesOf("{\"n\":1}\n{\"n\":2"), Stream.fail("boom"));
|
|
41
|
+
const { seen, failures } = await runUntilEnd(fromBytes(failing));
|
|
36
42
|
globalExpect(seen).toEqual(["{\"n\":1}"]);
|
|
37
43
|
globalExpect(failures).toEqual(["boom"]);
|
|
38
44
|
});
|
|
39
45
|
});
|
|
40
46
|
describe("JSONL.parse", () => {
|
|
41
47
|
it("decodes well-formed JSON lines through a Schema", async () => {
|
|
42
|
-
|
|
48
|
+
const out = await collect(bytesOf(`{"op":"add","value":1}\n{"op":"sub","value":2}\n`).pipe(fromBytes, parse(Patch)));
|
|
49
|
+
globalExpect(out).toEqual([{
|
|
43
50
|
op: "add",
|
|
44
51
|
value: 1
|
|
45
52
|
}, {
|
|
@@ -70,7 +77,8 @@ describe("JSONL round-trip", () => {
|
|
|
70
77
|
op: "b",
|
|
71
78
|
value: 2
|
|
72
79
|
}];
|
|
73
|
-
|
|
80
|
+
const out = await collect(Stream.fromIterable(values).pipe(toBytes(Patch), fromBytes, parse(Patch)));
|
|
81
|
+
globalExpect(out).toEqual(values);
|
|
74
82
|
});
|
|
75
83
|
});
|
|
76
84
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSONL.test.mjs","names":["JSONL.fromBytes","JSONL.parse","JSONL.toBytes"],"sources":["../../src/streaming/JSONL.test.ts"],"sourcesContent":["import { Effect, Result, Schema, Stream } from \"effect\"\nimport { describe, expect, it } from \"vitest\"\nimport * as JSONL from \"./JSONL.js\"\n\nconst enc = new TextEncoder()\nconst bytesOf = (...chunks: ReadonlyArray<string>) =>\n Stream.fromIterable(chunks.map((c) => enc.encode(c)))\n\nconst collect = <A, E>(s: Stream.Stream<A, E>) => Effect.runPromise(Stream.runCollect(s))\n\nconst runUntilEnd = <A, E>(s: Stream.Stream<A, E>) =>\n Effect.runPromise(\n s.pipe(\n Stream.result,\n Stream.runCollect,\n Effect.map((results) => ({\n seen: results.filter(Result.isSuccess).map((r) => r.success),\n failures: results.filter(Result.isFailure).map((r) => r.failure),\n })),\n ),\n )\n\nconst collectResult = <A, E>(s: Stream.Stream<A, E>) =>\n Effect.runPromise(Effect.result(Stream.runCollect(s)))\n\nconst Patch = Schema.Struct({ op: Schema.String, value: Schema.Number })\n\ndescribe(\"JSONL.fromBytes\", () => {\n it(\"emits one string per line\", async () => {\n const out = await collect(JSONL.fromBytes(bytesOf(\"a\\nb\\nc\\n\")))\n expect(out).toEqual([\"a\", \"b\", \"c\"])\n })\n\n it(\"buffers lines across chunk boundaries\", async () => {\n const out = await collect(JSONL.fromBytes(bytesOf(\"ab\", \"c\\nde\", \"f\\n\")))\n expect(out).toEqual([\"abc\", \"def\"])\n })\n\n it(\"flushes a trailing line without a final newline\", async () => {\n const out = await collect(JSONL.fromBytes(bytesOf(\"a\\nb\")))\n expect(out).toEqual([\"a\", \"b\"])\n })\n\n it(\"ignores blank lines\", async () => {\n const out = await collect(JSONL.fromBytes(bytesOf(\"a\\n\\n\\nb\\n\")))\n expect(out).toEqual([\"a\", \"b\"])\n })\n\n it(\"discards a buffered partial line when the upstream fails mid-stream\", async () => {\n const failing = Stream.concat(bytesOf('{\"n\":1}\\n{\"n\":2'), Stream.fail(\"boom\" as const))\n const { seen, failures } = await runUntilEnd(JSONL.fromBytes(failing))\n expect(seen).toEqual(['{\"n\":1}'])\n expect(failures).toEqual([\"boom\"])\n })\n})\n\ndescribe(\"JSONL.parse\", () => {\n it(\"decodes well-formed JSON lines through a Schema\", async () => {\n const out = await collect(\n bytesOf(`{\"op\":\"add\",\"value\":1}\\n{\"op\":\"sub\",\"value\":2}\\n`).pipe(\n JSONL.fromBytes,\n JSONL.parse(Patch),\n ),\n )\n expect(out).toEqual([\n { op: \"add\", value: 1 },\n { op: \"sub\", value: 2 },\n ])\n })\n\n it(\"fails with JsonParseError on malformed JSON\", async () => {\n const result = await collectResult(\n bytesOf(`{\"op\":\"add\",\"value\":1}\\nNOT_JSON\\n`).pipe(JSONL.fromBytes, JSONL.parse(Patch)),\n )\n expect(Result.isFailure(result)).toBe(true)\n if (Result.isFailure(result)) {\n expect(result.failure._tag).toBe(\"JsonParseError\")\n expect(result.failure.line).toBe(\"NOT_JSON\")\n }\n })\n\n it(\"fails with JsonParseError on schema mismatch\", async () => {\n const result = await collectResult(\n bytesOf(`{\"op\":\"add\",\"value\":\"not a number\"}\\n`).pipe(JSONL.fromBytes, JSONL.parse(Patch)),\n )\n expect(Result.isFailure(result)).toBe(true)\n if (Result.isFailure(result)) {\n expect(result.failure._tag).toBe(\"JsonParseError\")\n }\n })\n})\n\ndescribe(\"JSONL round-trip\", () => {\n it(\"toBytes then fromBytes/parse recovers the values\", async () => {\n const values = [\n { op: \"a\", value: 1 },\n { op: \"b\", value: 2 },\n ]\n const out = await collect(\n Stream.fromIterable(values).pipe(JSONL.toBytes(Patch), JSONL.fromBytes, JSONL.parse(Patch)),\n )\n expect(out).toEqual(values)\n })\n})\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"JSONL.test.mjs","names":["JSONL.fromBytes","JSONL.parse","JSONL.toBytes"],"sources":["../../src/streaming/JSONL.test.ts"],"sourcesContent":["import { Effect, Result, Schema, Stream } from \"effect\"\nimport { describe, expect, it } from \"vitest\"\nimport * as JSONL from \"./JSONL.js\"\n\nconst enc = new TextEncoder()\nconst bytesOf = (...chunks: ReadonlyArray<string>) =>\n Stream.fromIterable(chunks.map((c) => enc.encode(c)))\n\nconst collect = <A, E>(s: Stream.Stream<A, E>) => Effect.runPromise(Stream.runCollect(s))\n\nconst runUntilEnd = <A, E>(s: Stream.Stream<A, E>) =>\n Effect.runPromise(\n s.pipe(\n Stream.result,\n Stream.runCollect,\n Effect.map((results) => ({\n seen: results.filter(Result.isSuccess).map((r) => r.success),\n failures: results.filter(Result.isFailure).map((r) => r.failure),\n })),\n ),\n )\n\nconst collectResult = <A, E>(s: Stream.Stream<A, E>) =>\n Effect.runPromise(Effect.result(Stream.runCollect(s)))\n\nconst Patch = Schema.Struct({ op: Schema.String, value: Schema.Number })\n\ndescribe(\"JSONL.fromBytes\", () => {\n it(\"emits one string per line\", async () => {\n const out = await collect(JSONL.fromBytes(bytesOf(\"a\\nb\\nc\\n\")))\n expect(out).toEqual([\"a\", \"b\", \"c\"])\n })\n\n it(\"buffers lines across chunk boundaries\", async () => {\n const out = await collect(JSONL.fromBytes(bytesOf(\"ab\", \"c\\nde\", \"f\\n\")))\n expect(out).toEqual([\"abc\", \"def\"])\n })\n\n it(\"flushes a trailing line without a final newline\", async () => {\n const out = await collect(JSONL.fromBytes(bytesOf(\"a\\nb\")))\n expect(out).toEqual([\"a\", \"b\"])\n })\n\n it(\"ignores blank lines\", async () => {\n const out = await collect(JSONL.fromBytes(bytesOf(\"a\\n\\n\\nb\\n\")))\n expect(out).toEqual([\"a\", \"b\"])\n })\n\n it(\"discards a buffered partial line when the upstream fails mid-stream\", async () => {\n const failing = Stream.concat(bytesOf('{\"n\":1}\\n{\"n\":2'), Stream.fail(\"boom\" as const))\n const { seen, failures } = await runUntilEnd(JSONL.fromBytes(failing))\n expect(seen).toEqual(['{\"n\":1}'])\n expect(failures).toEqual([\"boom\"])\n })\n})\n\ndescribe(\"JSONL.parse\", () => {\n it(\"decodes well-formed JSON lines through a Schema\", async () => {\n const out = await collect(\n bytesOf(`{\"op\":\"add\",\"value\":1}\\n{\"op\":\"sub\",\"value\":2}\\n`).pipe(\n JSONL.fromBytes,\n JSONL.parse(Patch),\n ),\n )\n expect(out).toEqual([\n { op: \"add\", value: 1 },\n { op: \"sub\", value: 2 },\n ])\n })\n\n it(\"fails with JsonParseError on malformed JSON\", async () => {\n const result = await collectResult(\n bytesOf(`{\"op\":\"add\",\"value\":1}\\nNOT_JSON\\n`).pipe(JSONL.fromBytes, JSONL.parse(Patch)),\n )\n expect(Result.isFailure(result)).toBe(true)\n if (Result.isFailure(result)) {\n expect(result.failure._tag).toBe(\"JsonParseError\")\n expect(result.failure.line).toBe(\"NOT_JSON\")\n }\n })\n\n it(\"fails with JsonParseError on schema mismatch\", async () => {\n const result = await collectResult(\n bytesOf(`{\"op\":\"add\",\"value\":\"not a number\"}\\n`).pipe(JSONL.fromBytes, JSONL.parse(Patch)),\n )\n expect(Result.isFailure(result)).toBe(true)\n if (Result.isFailure(result)) {\n expect(result.failure._tag).toBe(\"JsonParseError\")\n }\n })\n})\n\ndescribe(\"JSONL round-trip\", () => {\n it(\"toBytes then fromBytes/parse recovers the values\", async () => {\n const values = [\n { op: \"a\", value: 1 },\n { op: \"b\", value: 2 },\n ]\n const out = await collect(\n Stream.fromIterable(values).pipe(JSONL.toBytes(Patch), JSONL.fromBytes, JSONL.parse(Patch)),\n )\n expect(out).toEqual(values)\n })\n})\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Lines.d.mts","names":[],"sources":["../../src/streaming/Lines.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"Lines.d.mts","names":[],"sources":["../../src/streaming/Lines.ts"],"mappings":";;;;;;;;;;;;;;;cAaa,QAAS,GAAG,GAAC,MAAQ,OAAO,eAAe,GAAG,OAAK,OAAO,eAAe,GAAG;;;;;;cAQ5E,cAAe,GAAG,GAAC,MAAQ,OAAO,eAAe,GAAG,OAAK,OAAO,eAAe,GAAG"}
|
package/dist/streaming/Lines.mjs
CHANGED