@effect-uai/core 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/README.md +1 -1
  2. package/dist/{AiError-CqmYjXyx.d.mts → AiError-csR8Bhxx.d.mts} +26 -4
  3. package/dist/{AiError-CqmYjXyx.d.mts.map → AiError-csR8Bhxx.d.mts.map} +1 -1
  4. package/dist/Audio-BfCTGnH3.d.mts +61 -0
  5. package/dist/Audio-BfCTGnH3.d.mts.map +1 -0
  6. package/dist/Image-DxyXqzAM.d.mts +61 -0
  7. package/dist/Image-DxyXqzAM.d.mts.map +1 -0
  8. package/dist/{Items-D1C2686t.d.mts → Items-Hg5AsYxl.d.mts} +132 -80
  9. package/dist/Items-Hg5AsYxl.d.mts.map +1 -0
  10. package/dist/Media-D_CpcM1Z.d.mts +57 -0
  11. package/dist/Media-D_CpcM1Z.d.mts.map +1 -0
  12. package/dist/{StructuredFormat-B5ueioNr.d.mts → StructuredFormat-Cl41C56K.d.mts} +5 -5
  13. package/dist/StructuredFormat-Cl41C56K.d.mts.map +1 -0
  14. package/dist/{Tool-5wxOCuOh.d.mts → Tool-B8B5qVEy.d.mts} +13 -13
  15. package/dist/Tool-B8B5qVEy.d.mts.map +1 -0
  16. package/dist/{Turn-Bi83du4I.d.mts → Turn-7geUcKsf.d.mts} +5 -11
  17. package/dist/Turn-7geUcKsf.d.mts.map +1 -0
  18. package/dist/{chunk-CfYAbeIz.mjs → chunk-uyGKjUfl.mjs} +2 -1
  19. package/dist/dist-DV5ISja1.mjs +13782 -0
  20. package/dist/dist-DV5ISja1.mjs.map +1 -0
  21. package/dist/domain/AiError.d.mts +2 -2
  22. package/dist/domain/AiError.mjs +19 -3
  23. package/dist/domain/AiError.mjs.map +1 -1
  24. package/dist/domain/Audio.d.mts +2 -0
  25. package/dist/domain/Audio.mjs +14 -0
  26. package/dist/domain/Audio.mjs.map +1 -0
  27. package/dist/domain/Image.d.mts +2 -0
  28. package/dist/domain/Image.mjs +58 -0
  29. package/dist/domain/Image.mjs.map +1 -0
  30. package/dist/domain/Items.d.mts +2 -2
  31. package/dist/domain/Items.mjs +19 -42
  32. package/dist/domain/Items.mjs.map +1 -1
  33. package/dist/domain/Media.d.mts +2 -0
  34. package/dist/domain/Media.mjs +14 -0
  35. package/dist/domain/Media.mjs.map +1 -0
  36. package/dist/domain/Music.d.mts +116 -0
  37. package/dist/domain/Music.d.mts.map +1 -0
  38. package/dist/domain/Music.mjs +29 -0
  39. package/dist/domain/Music.mjs.map +1 -0
  40. package/dist/domain/Transcript.d.mts +95 -0
  41. package/dist/domain/Transcript.d.mts.map +1 -0
  42. package/dist/domain/Transcript.mjs +22 -0
  43. package/dist/domain/Transcript.mjs.map +1 -0
  44. package/dist/domain/Turn.d.mts +1 -1
  45. package/dist/domain/Turn.mjs +1 -1
  46. package/dist/embedding-model/Embedding.d.mts +107 -0
  47. package/dist/embedding-model/Embedding.d.mts.map +1 -0
  48. package/dist/embedding-model/Embedding.mjs +18 -0
  49. package/dist/embedding-model/Embedding.mjs.map +1 -0
  50. package/dist/embedding-model/EmbeddingModel.d.mts +97 -0
  51. package/dist/embedding-model/EmbeddingModel.d.mts.map +1 -0
  52. package/dist/embedding-model/EmbeddingModel.mjs +17 -0
  53. package/dist/embedding-model/EmbeddingModel.mjs.map +1 -0
  54. package/dist/index.d.mts +21 -7
  55. package/dist/index.mjs +16 -2
  56. package/dist/language-model/LanguageModel.d.mts +12 -20
  57. package/dist/language-model/LanguageModel.d.mts.map +1 -1
  58. package/dist/language-model/LanguageModel.mjs +3 -20
  59. package/dist/language-model/LanguageModel.mjs.map +1 -1
  60. package/dist/loop/Loop.d.mts +31 -7
  61. package/dist/loop/Loop.d.mts.map +1 -1
  62. package/dist/loop/Loop.mjs +39 -6
  63. package/dist/loop/Loop.mjs.map +1 -1
  64. package/dist/loop/Loop.test.d.mts +1 -0
  65. package/dist/loop/Loop.test.mjs +411 -0
  66. package/dist/loop/Loop.test.mjs.map +1 -0
  67. package/dist/magic-string.es-BgIV5Mu3.mjs +1013 -0
  68. package/dist/magic-string.es-BgIV5Mu3.mjs.map +1 -0
  69. package/dist/math/Vector.d.mts +47 -0
  70. package/dist/math/Vector.d.mts.map +1 -0
  71. package/dist/math/Vector.mjs +117 -0
  72. package/dist/math/Vector.mjs.map +1 -0
  73. package/dist/music-generator/MusicGenerator.d.mts +77 -0
  74. package/dist/music-generator/MusicGenerator.d.mts.map +1 -0
  75. package/dist/music-generator/MusicGenerator.mjs +51 -0
  76. package/dist/music-generator/MusicGenerator.mjs.map +1 -0
  77. package/dist/music-generator/MusicGenerator.test.d.mts +1 -0
  78. package/dist/music-generator/MusicGenerator.test.mjs +154 -0
  79. package/dist/music-generator/MusicGenerator.test.mjs.map +1 -0
  80. package/dist/observability/Metrics.d.mts +2 -2
  81. package/dist/observability/Metrics.d.mts.map +1 -1
  82. package/dist/observability/Metrics.mjs +1 -1
  83. package/dist/observability/Metrics.mjs.map +1 -1
  84. package/dist/speech-synthesizer/SpeechSynthesizer.d.mts +96 -0
  85. package/dist/speech-synthesizer/SpeechSynthesizer.d.mts.map +1 -0
  86. package/dist/speech-synthesizer/SpeechSynthesizer.mjs +48 -0
  87. package/dist/speech-synthesizer/SpeechSynthesizer.mjs.map +1 -0
  88. package/dist/speech-synthesizer/SpeechSynthesizer.test.d.mts +1 -0
  89. package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs +112 -0
  90. package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs.map +1 -0
  91. package/dist/streaming/JSONL.d.mts +10 -3
  92. package/dist/streaming/JSONL.d.mts.map +1 -1
  93. package/dist/streaming/JSONL.mjs +13 -2
  94. package/dist/streaming/JSONL.mjs.map +1 -1
  95. package/dist/streaming/JSONL.test.d.mts +1 -0
  96. package/dist/streaming/JSONL.test.mjs +70 -0
  97. package/dist/streaming/JSONL.test.mjs.map +1 -0
  98. package/dist/streaming/Lines.mjs +1 -1
  99. package/dist/streaming/SSE.d.mts +2 -2
  100. package/dist/streaming/SSE.d.mts.map +1 -1
  101. package/dist/streaming/SSE.mjs +1 -1
  102. package/dist/streaming/SSE.mjs.map +1 -1
  103. package/dist/streaming/SSE.test.d.mts +1 -0
  104. package/dist/streaming/SSE.test.mjs +72 -0
  105. package/dist/streaming/SSE.test.mjs.map +1 -0
  106. package/dist/structured-format/StructuredFormat.d.mts +1 -1
  107. package/dist/structured-format/StructuredFormat.mjs +1 -1
  108. package/dist/structured-format/StructuredFormat.mjs.map +1 -1
  109. package/dist/testing/MockMusicGenerator.d.mts +39 -0
  110. package/dist/testing/MockMusicGenerator.d.mts.map +1 -0
  111. package/dist/testing/MockMusicGenerator.mjs +96 -0
  112. package/dist/testing/MockMusicGenerator.mjs.map +1 -0
  113. package/dist/testing/MockProvider.d.mts +6 -6
  114. package/dist/testing/MockProvider.d.mts.map +1 -1
  115. package/dist/testing/MockProvider.mjs.map +1 -1
  116. package/dist/testing/MockSpeechSynthesizer.d.mts +37 -0
  117. package/dist/testing/MockSpeechSynthesizer.d.mts.map +1 -0
  118. package/dist/testing/MockSpeechSynthesizer.mjs +95 -0
  119. package/dist/testing/MockSpeechSynthesizer.mjs.map +1 -0
  120. package/dist/testing/MockTranscriber.d.mts +37 -0
  121. package/dist/testing/MockTranscriber.d.mts.map +1 -0
  122. package/dist/testing/MockTranscriber.mjs +77 -0
  123. package/dist/testing/MockTranscriber.mjs.map +1 -0
  124. package/dist/tool/HistoryCheck.d.mts +6 -3
  125. package/dist/tool/HistoryCheck.d.mts.map +1 -1
  126. package/dist/tool/HistoryCheck.mjs +7 -1
  127. package/dist/tool/HistoryCheck.mjs.map +1 -1
  128. package/dist/tool/Outcome.d.mts +138 -2
  129. package/dist/tool/Outcome.d.mts.map +1 -0
  130. package/dist/tool/Outcome.mjs +32 -10
  131. package/dist/tool/Outcome.mjs.map +1 -1
  132. package/dist/tool/Resolvers.d.mts +11 -8
  133. package/dist/tool/Resolvers.d.mts.map +1 -1
  134. package/dist/tool/Resolvers.mjs +10 -1
  135. package/dist/tool/Resolvers.mjs.map +1 -1
  136. package/dist/tool/Resolvers.test.d.mts +1 -0
  137. package/dist/tool/Resolvers.test.mjs +317 -0
  138. package/dist/tool/Resolvers.test.mjs.map +1 -0
  139. package/dist/tool/Tool.d.mts +1 -1
  140. package/dist/tool/Tool.mjs +1 -1
  141. package/dist/tool/Tool.mjs.map +1 -1
  142. package/dist/tool/ToolEvent.d.mts +151 -2
  143. package/dist/tool/ToolEvent.d.mts.map +1 -0
  144. package/dist/tool/ToolEvent.mjs +30 -4
  145. package/dist/tool/ToolEvent.mjs.map +1 -1
  146. package/dist/tool/Toolkit.d.mts +19 -10
  147. package/dist/tool/Toolkit.d.mts.map +1 -1
  148. package/dist/tool/Toolkit.mjs +5 -5
  149. package/dist/tool/Toolkit.mjs.map +1 -1
  150. package/dist/tool/Toolkit.test.d.mts +1 -0
  151. package/dist/tool/Toolkit.test.mjs +113 -0
  152. package/dist/tool/Toolkit.test.mjs.map +1 -0
  153. package/dist/transcriber/Transcriber.d.mts +101 -0
  154. package/dist/transcriber/Transcriber.d.mts.map +1 -0
  155. package/dist/transcriber/Transcriber.mjs +49 -0
  156. package/dist/transcriber/Transcriber.mjs.map +1 -0
  157. package/dist/transcriber/Transcriber.test.d.mts +1 -0
  158. package/dist/transcriber/Transcriber.test.mjs +130 -0
  159. package/dist/transcriber/Transcriber.test.mjs.map +1 -0
  160. package/package.json +65 -13
  161. package/src/domain/AiError.ts +21 -0
  162. package/src/domain/Audio.ts +88 -0
  163. package/src/domain/Image.ts +75 -0
  164. package/src/domain/Items.ts +18 -47
  165. package/src/domain/Media.ts +61 -0
  166. package/src/domain/Music.ts +121 -0
  167. package/src/domain/Transcript.ts +83 -0
  168. package/src/embedding-model/Embedding.ts +117 -0
  169. package/src/embedding-model/EmbeddingModel.ts +107 -0
  170. package/src/index.ts +15 -1
  171. package/src/language-model/LanguageModel.ts +2 -22
  172. package/src/loop/Loop.test.ts +114 -2
  173. package/src/loop/Loop.ts +69 -5
  174. package/src/math/Vector.ts +138 -0
  175. package/src/music-generator/MusicGenerator.test.ts +170 -0
  176. package/src/music-generator/MusicGenerator.ts +123 -0
  177. package/src/observability/Metrics.ts +1 -1
  178. package/src/speech-synthesizer/SpeechSynthesizer.test.ts +141 -0
  179. package/src/speech-synthesizer/SpeechSynthesizer.ts +131 -0
  180. package/src/streaming/JSONL.ts +12 -0
  181. package/src/streaming/SSE.ts +1 -1
  182. package/src/structured-format/StructuredFormat.ts +2 -2
  183. package/src/testing/MockMusicGenerator.ts +170 -0
  184. package/src/testing/MockProvider.ts +2 -2
  185. package/src/testing/MockSpeechSynthesizer.ts +165 -0
  186. package/src/testing/MockTranscriber.ts +139 -0
  187. package/src/tool/HistoryCheck.ts +2 -5
  188. package/src/tool/Outcome.ts +36 -36
  189. package/src/tool/Resolvers.test.ts +11 -35
  190. package/src/tool/Resolvers.ts +5 -14
  191. package/src/tool/Tool.ts +9 -9
  192. package/src/tool/ToolEvent.ts +28 -24
  193. package/src/tool/Toolkit.test.ts +97 -2
  194. package/src/tool/Toolkit.ts +57 -33
  195. package/src/transcriber/Transcriber.test.ts +125 -0
  196. package/src/transcriber/Transcriber.ts +127 -0
  197. package/dist/Items-D1C2686t.d.mts.map +0 -1
  198. package/dist/Outcome-GiaNvt7i.d.mts +0 -32
  199. package/dist/Outcome-GiaNvt7i.d.mts.map +0 -1
  200. package/dist/StructuredFormat-B5ueioNr.d.mts.map +0 -1
  201. package/dist/Tool-5wxOCuOh.d.mts.map +0 -1
  202. package/dist/ToolEvent-wTMgb2GO.d.mts +0 -29
  203. package/dist/ToolEvent-wTMgb2GO.d.mts.map +0 -1
  204. package/dist/Turn-Bi83du4I.d.mts.map +0 -1
  205. package/dist/match/Match.d.mts +0 -16
  206. package/dist/match/Match.d.mts.map +0 -1
  207. package/dist/match/Match.mjs +0 -15
  208. package/dist/match/Match.mjs.map +0 -1
  209. package/src/match/Match.ts +0 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-uai/core",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Low-level primitives (loop, conversation, items, tools, streaming codecs) for building AI agents with Effect.",
5
5
  "keywords": [
6
6
  "agents",
@@ -20,6 +20,12 @@
20
20
  "url": "https://github.com/betalyra/effect-uai",
21
21
  "directory": "packages/core"
22
22
  },
23
+ "files": [
24
+ "dist",
25
+ "src",
26
+ "README.md",
27
+ "LICENSE"
28
+ ],
23
29
  "type": "module",
24
30
  "main": "./dist/index.mjs",
25
31
  "types": "./dist/index.d.mts",
@@ -32,25 +38,65 @@
32
38
  "types": "./dist/domain/AiError.d.mts",
33
39
  "import": "./dist/domain/AiError.mjs"
34
40
  },
41
+ "./Audio": {
42
+ "types": "./dist/domain/Audio.d.mts",
43
+ "import": "./dist/domain/Audio.mjs"
44
+ },
45
+ "./Image": {
46
+ "types": "./dist/domain/Image.d.mts",
47
+ "import": "./dist/domain/Image.mjs"
48
+ },
35
49
  "./Items": {
36
50
  "types": "./dist/domain/Items.d.mts",
37
51
  "import": "./dist/domain/Items.mjs"
38
52
  },
53
+ "./Media": {
54
+ "types": "./dist/domain/Media.d.mts",
55
+ "import": "./dist/domain/Media.mjs"
56
+ },
57
+ "./Music": {
58
+ "types": "./dist/domain/Music.d.mts",
59
+ "import": "./dist/domain/Music.mjs"
60
+ },
61
+ "./Transcript": {
62
+ "types": "./dist/domain/Transcript.d.mts",
63
+ "import": "./dist/domain/Transcript.mjs"
64
+ },
39
65
  "./Turn": {
40
66
  "types": "./dist/domain/Turn.d.mts",
41
67
  "import": "./dist/domain/Turn.mjs"
42
68
  },
69
+ "./Embedding": {
70
+ "types": "./dist/embedding-model/Embedding.d.mts",
71
+ "import": "./dist/embedding-model/Embedding.mjs"
72
+ },
73
+ "./EmbeddingModel": {
74
+ "types": "./dist/embedding-model/EmbeddingModel.d.mts",
75
+ "import": "./dist/embedding-model/EmbeddingModel.mjs"
76
+ },
43
77
  "./LanguageModel": {
44
78
  "types": "./dist/language-model/LanguageModel.d.mts",
45
79
  "import": "./dist/language-model/LanguageModel.mjs"
46
80
  },
81
+ "./MusicGenerator": {
82
+ "types": "./dist/music-generator/MusicGenerator.d.mts",
83
+ "import": "./dist/music-generator/MusicGenerator.mjs"
84
+ },
85
+ "./SpeechSynthesizer": {
86
+ "types": "./dist/speech-synthesizer/SpeechSynthesizer.d.mts",
87
+ "import": "./dist/speech-synthesizer/SpeechSynthesizer.mjs"
88
+ },
89
+ "./Transcriber": {
90
+ "types": "./dist/transcriber/Transcriber.d.mts",
91
+ "import": "./dist/transcriber/Transcriber.mjs"
92
+ },
47
93
  "./Loop": {
48
94
  "types": "./dist/loop/Loop.d.mts",
49
95
  "import": "./dist/loop/Loop.mjs"
50
96
  },
51
- "./Match": {
52
- "types": "./dist/match/Match.d.mts",
53
- "import": "./dist/match/Match.mjs"
97
+ "./Vector": {
98
+ "types": "./dist/math/Vector.d.mts",
99
+ "import": "./dist/math/Vector.mjs"
54
100
  },
55
101
  "./Tool": {
56
102
  "types": "./dist/tool/Tool.d.mts",
@@ -99,27 +145,33 @@
99
145
  "./testing/MockProvider": {
100
146
  "types": "./dist/testing/MockProvider.d.mts",
101
147
  "import": "./dist/testing/MockProvider.mjs"
148
+ },
149
+ "./testing/MockMusicGenerator": {
150
+ "types": "./dist/testing/MockMusicGenerator.d.mts",
151
+ "import": "./dist/testing/MockMusicGenerator.mjs"
152
+ },
153
+ "./testing/MockSpeechSynthesizer": {
154
+ "types": "./dist/testing/MockSpeechSynthesizer.d.mts",
155
+ "import": "./dist/testing/MockSpeechSynthesizer.mjs"
156
+ },
157
+ "./testing/MockTranscriber": {
158
+ "types": "./dist/testing/MockTranscriber.d.mts",
159
+ "import": "./dist/testing/MockTranscriber.mjs"
102
160
  }
103
161
  },
104
- "files": [
105
- "dist",
106
- "src",
107
- "README.md",
108
- "LICENSE"
109
- ],
110
162
  "publishConfig": {
111
163
  "access": "public"
112
164
  },
113
165
  "dependencies": {
114
166
  "@standard-schema/spec": "^1.1.0"
115
167
  },
116
- "peerDependencies": {
117
- "effect": "4.0.0-beta.57"
118
- },
119
168
  "devDependencies": {
120
169
  "effect": "4.0.0-beta.57",
121
170
  "typescript": "^6.0.3"
122
171
  },
172
+ "peerDependencies": {
173
+ "effect": "4.0.0-beta.57"
174
+ },
123
175
  "scripts": {
124
176
  "build": "tsdown",
125
177
  "typecheck": "tsc --noEmit"
@@ -80,6 +80,26 @@ export class IncompleteTurn extends Data.TaggedError("IncompleteTurn")<{
80
80
  raw?: unknown
81
81
  }> {}
82
82
 
83
+ /**
84
+ * The provider does not implement the requested capability for this
85
+ * specific request. Distinct from `InvalidRequest` (the request shape is
86
+ * malformed) and `AuthFailed` (the request was rejected).
87
+ *
88
+ * Reserved for request-data-dependent gaps where the provider supports
89
+ * the method in general but not for these inputs — e.g. Google's
90
+ * `streamSynthesisFrom` works only for Chirp 3 HD voices; calling it
91
+ * with a Neural2 voice ID fails `Unsupported`.
92
+ *
93
+ * Blanket provider-level gaps (e.g. OpenAI has no incremental-text-in
94
+ * TTS at all) are gated at compile time via capability marker tags
95
+ * (`TtsIncrementalText`, `SttStreaming`) on the R channel instead.
96
+ */
97
+ export class Unsupported extends Data.TaggedError("Unsupported")<{
98
+ provider: string
99
+ capability: string
100
+ reason?: string
101
+ }> {}
102
+
83
103
  export type AiError =
84
104
  | RateLimited
85
105
  | Unavailable
@@ -91,3 +111,4 @@ export type AiError =
91
111
  | Cancelled
92
112
  | IncompleteTurn
93
113
  | GenerationFailed
114
+ | Unsupported
@@ -0,0 +1,88 @@
1
+ import type { MediaBase64, MediaBytes, MediaUrl } from "./Media.js"
2
+
3
+ /**
4
+ * MIME types we care about across STT input and TTS output. Container-
5
+ * level only — sample rate / encoding flavours live on `AudioFormat`.
6
+ *
7
+ * Per-provider request types narrow this further. The `(string & {})`
8
+ * tail keeps autocomplete on the literals while still accepting any
9
+ * string, so unusual formats work without an SDK update.
10
+ */
11
+ export type AudioMimeType =
12
+ | "audio/mpeg"
13
+ | "audio/wav"
14
+ | "audio/x-wav"
15
+ | "audio/ogg"
16
+ | "audio/opus"
17
+ | "audio/flac"
18
+ | "audio/aac"
19
+ | "audio/mp4"
20
+ | "audio/webm"
21
+ | "audio/L16"
22
+ | "audio/pcm"
23
+ | "audio/mulaw"
24
+ | "audio/alaw"
25
+ // eslint-disable-next-line @typescript-eslint/ban-types
26
+ | (string & {})
27
+
28
+ /**
29
+ * Audio at rest — instantiates `MediaSource` with the audio MIME union.
30
+ * Used for sync STT input.
31
+ *
32
+ * URL variant is best-effort: some providers (OpenAI, Cartesia, Azure
33
+ * short-audio) reject URL ingestion and the adapter must upload via the
34
+ * `bytes` or `base64` variant instead. Adapter layers reject unsupported
35
+ * shapes up front with `AiError.InvalidRequest`.
36
+ */
37
+ export type AudioSource =
38
+ | MediaUrl<AudioMimeType>
39
+ | MediaBase64<AudioMimeType>
40
+ | MediaBytes<AudioMimeType>
41
+
42
+ export const isAudioUrl = (s: AudioSource): s is MediaUrl<AudioMimeType> => s._tag === "url"
43
+ export const isAudioBase64 = (s: AudioSource): s is MediaBase64<AudioMimeType> =>
44
+ s._tag === "base64"
45
+ export const isAudioBytes = (s: AudioSource): s is MediaBytes<AudioMimeType> => s._tag === "bytes"
46
+
47
+ /**
48
+ * Structural audio format. Used both as TTS output spec and as STT
49
+ * streaming-input declaration. Providers that use compound slugs
50
+ * (`mp3_44100_128`, `audio-16khz-128kbitrate-mono-mp3`,
51
+ * `aura-2-thalia-en`) are encoded at the adapter layer.
52
+ */
53
+ export type AudioFormat = {
54
+ readonly container: "mp3" | "wav" | "ogg" | "opus" | "flac" | "aac" | "webm" | "raw"
55
+ readonly encoding:
56
+ | "pcm_s16le"
57
+ | "pcm_f32le"
58
+ | "pcm_mulaw"
59
+ | "pcm_alaw"
60
+ | "mp3"
61
+ | "opus"
62
+ | "vorbis"
63
+ | "flac"
64
+ | "aac"
65
+ readonly sampleRate: 8000 | 16000 | 22050 | 24000 | 32000 | 44100 | 48000
66
+ /** mp3 / opus only. */
67
+ readonly bitRate?: number
68
+ readonly channels?: 1 | 2
69
+ }
70
+
71
+ /**
72
+ * Streamed audio chunk. `bytes` carries the codec-encoded payload as
73
+ * declared on the stream's `AudioFormat`. No per-chunk timestamp here —
74
+ * providers that emit timing do so via `TranscriptEvent.words[]`.
75
+ */
76
+ export type AudioChunk = {
77
+ readonly bytes: Uint8Array
78
+ }
79
+
80
+ /**
81
+ * Full audio result for sync TTS. Format mirrors the request; provider
82
+ * layers normalize.
83
+ */
84
+ export type AudioBlob = {
85
+ readonly format: AudioFormat
86
+ readonly bytes: Uint8Array
87
+ readonly durationSeconds?: number
88
+ }
@@ -0,0 +1,75 @@
1
+ import { Schema } from "effect"
2
+ import type { MediaBase64, MediaBytes, MediaSource, MediaUrl } from "./Media.js"
3
+
4
+ /**
5
+ * Image MIME types AI providers typically accept. The first four are the
6
+ * universal subset (Cohere v4, Voyage multimodal, Jina v4, Google
7
+ * `gemini-embedding-2`); HEIC / HEIF are Google-specific. The
8
+ * `(string & {})` tail keeps autocomplete on the literals while still
9
+ * accepting any string, so a newly-supported format works without an
10
+ * SDK update.
11
+ */
12
+ export type ImageMimeType =
13
+ | "image/png"
14
+ | "image/jpeg"
15
+ | "image/webp"
16
+ | "image/gif"
17
+ | "image/heic"
18
+ | "image/heif"
19
+ // eslint-disable-next-line @typescript-eslint/ban-types
20
+ | (string & {})
21
+
22
+ const ImageMimeTypeSchema = Schema.String as unknown as Schema.Schema<ImageMimeType>
23
+
24
+ export type ImageUrlSource = MediaUrl<ImageMimeType>
25
+ export type ImageBase64Source = MediaBase64<ImageMimeType>
26
+ export type ImageBytesSource = MediaBytes<ImageMimeType>
27
+
28
+ /**
29
+ * Where an image lives. Provider layers normalize across these:
30
+ * `bytes` becomes a base64 data URI for OpenAI / Anthropic, an
31
+ * `inlineData` part for Gemini, and a separate field for Cohere /
32
+ * Voyage. URL constraints (must be HTTPS, must be public, …) are
33
+ * provider-specific and validated at the layer, not in the type.
34
+ */
35
+ export type ImageSource = MediaSource<ImageMimeType>
36
+
37
+ export const ImageUrlSource = Schema.TaggedStruct("url", {
38
+ url: Schema.String,
39
+ mimeType: Schema.optional(ImageMimeTypeSchema),
40
+ })
41
+
42
+ export const ImageBase64Source = Schema.TaggedStruct("base64", {
43
+ base64: Schema.String,
44
+ mimeType: ImageMimeTypeSchema,
45
+ })
46
+
47
+ export const ImageBytesSource = Schema.TaggedStruct("bytes", {
48
+ bytes: Schema.Uint8Array,
49
+ mimeType: ImageMimeTypeSchema,
50
+ })
51
+
52
+ export const ImageSource: Schema.Schema<ImageSource> = Schema.Union([
53
+ ImageUrlSource,
54
+ ImageBase64Source,
55
+ ImageBytesSource,
56
+ ]) as unknown as Schema.Schema<ImageSource>
57
+
58
+ export const imageUrl = (url: string, mimeType?: ImageMimeType): ImageUrlSource =>
59
+ mimeType !== undefined ? { _tag: "url", url, mimeType } : { _tag: "url", url }
60
+
61
+ export const imageBase64 = (base64: string, mimeType: ImageMimeType): ImageBase64Source => ({
62
+ _tag: "base64",
63
+ base64,
64
+ mimeType,
65
+ })
66
+
67
+ export const imageBytes = (bytes: Uint8Array, mimeType: ImageMimeType): ImageBytesSource => ({
68
+ _tag: "bytes",
69
+ bytes,
70
+ mimeType,
71
+ })
72
+
73
+ export const isImageUrl = Schema.is(ImageUrlSource)
74
+ export const isImageBase64 = Schema.is(ImageBase64Source)
75
+ export const isImageBytes = Schema.is(ImageBytesSource)
@@ -1,4 +1,5 @@
1
1
  import { Schema } from "effect"
2
+ import { ImageSource } from "./Image.js"
2
3
 
3
4
  // ---------------------------------------------------------------------------
4
5
  // Content blocks (inside Message.content)
@@ -10,39 +11,13 @@ export const InputText = Schema.Struct({
10
11
  })
11
12
  export type InputText = typeof InputText.Type
12
13
 
13
- /**
14
- * Where an image lives. `url` covers HTTP(S) URLs (the model fetches
15
- * them); `base64` covers inline bytes embedded in the request. Provider
16
- * encoders dispatch on `_tag`. File-id / uploaded-asset references are
17
- * provider-specific and stay out of this union for now.
18
- */
19
- export const ImageUrlSource = Schema.Struct({
20
- _tag: Schema.Literal("url"),
21
- url: Schema.String,
22
- })
23
- export type ImageUrlSource = typeof ImageUrlSource.Type
24
-
25
- /**
26
- * Inline image bytes. `data` is **already base64-encoded** (matches what
27
- * the wire formats expect; no double-encoding needed downstream).
28
- * `media_type` is the MIME type, e.g. `"image/png"`.
29
- */
30
- export const ImageBase64Source = Schema.Struct({
31
- _tag: Schema.Literal("base64"),
32
- media_type: Schema.String,
33
- data: Schema.String,
34
- })
35
- export type ImageBase64Source = typeof ImageBase64Source.Type
36
-
37
- export const ImageSource = Schema.Union([ImageUrlSource, ImageBase64Source])
38
- export type ImageSource = typeof ImageSource.Type
39
-
40
- export const isImageUrlSource = (s: ImageSource): s is ImageUrlSource => s._tag === "url"
41
- export const isImageBase64Source = (s: ImageSource): s is ImageBase64Source => s._tag === "base64"
42
-
43
14
  /**
44
15
  * User-provided image content block. Pair with `InputText` inside a
45
16
  * `Message.content` array to ask "what's in this image?" style questions.
17
+ *
18
+ * `source` is the cross-modality `ImageSource` from `domain/Image.ts` -
19
+ * url, base64, or raw bytes. Provider codecs encode bytes to whatever
20
+ * wire format the provider wants.
46
21
  */
47
22
  export const InputImage = Schema.Struct({
48
23
  type: Schema.Literal("input_image"),
@@ -91,11 +66,10 @@ export type FilePath = typeof FilePath.Type
91
66
  export const Annotation = Schema.Union([UrlCitation, FileCitation, ContainerFileCitation, FilePath])
92
67
  export type Annotation = typeof Annotation.Type
93
68
 
94
- export const isUrlCitation = (a: Annotation): a is UrlCitation => a.type === "url_citation"
95
- export const isFileCitation = (a: Annotation): a is FileCitation => a.type === "file_citation"
96
- export const isContainerFileCitation = (a: Annotation): a is ContainerFileCitation =>
97
- a.type === "container_file_citation"
98
- export const isFilePath = (a: Annotation): a is FilePath => a.type === "file_path"
69
+ export const isUrlCitation = Schema.is(UrlCitation)
70
+ export const isFileCitation = Schema.is(FileCitation)
71
+ export const isContainerFileCitation = Schema.is(ContainerFileCitation)
72
+ export const isFilePath = Schema.is(FilePath)
99
73
 
100
74
  export const OutputText = Schema.Struct({
101
75
  type: Schema.Literal("output_text"),
@@ -183,18 +157,15 @@ export type Item = typeof Item.Type
183
157
  // Type guards
184
158
  // ---------------------------------------------------------------------------
185
159
 
186
- export const isInputText = (block: ContentBlock): block is InputText => block.type === "input_text"
187
- export const isInputImage = (block: ContentBlock): block is InputImage =>
188
- block.type === "input_image"
189
- export const isOutputText = (block: ContentBlock): block is OutputText =>
190
- block.type === "output_text"
191
- export const isRefusal = (block: ContentBlock): block is Refusal => block.type === "refusal"
192
-
193
- export const isMessage = (item: Item): item is Message => item.type === "message"
194
- export const isFunctionCall = (item: Item): item is FunctionCall => item.type === "function_call"
195
- export const isFunctionCallOutput = (item: Item): item is FunctionCallOutput =>
196
- item.type === "function_call_output"
197
- export const isReasoning = (item: Item): item is Reasoning => item.type === "reasoning"
160
+ export const isInputText = Schema.is(InputText)
161
+ export const isInputImage = Schema.is(InputImage)
162
+ export const isOutputText = Schema.is(OutputText)
163
+ export const isRefusal = Schema.is(Refusal)
164
+
165
+ export const isMessage = Schema.is(Message)
166
+ export const isFunctionCall = Schema.is(FunctionCall)
167
+ export const isFunctionCallOutput = Schema.is(FunctionCallOutput)
168
+ export const isReasoning = Schema.is(Reasoning)
198
169
 
199
170
  // ---------------------------------------------------------------------------
200
171
  // Usage and stop reason
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Cross-modality media reference shape.
3
+ *
4
+ * Every "media at rest" reference - image, audio, video, document - is one
5
+ * of three variants:
6
+ *
7
+ * - `url` : a remote address (HTTP, GCS, etc.). The model fetches it.
8
+ * `mimeType` is optional - servers usually set Content-Type.
9
+ * Some providers (Gemini `fileData`) want it explicit.
10
+ *
11
+ * - `base64` : an inline base64-encoded payload. Always carries a
12
+ * `mimeType` so the consumer knows how to decode.
13
+ *
14
+ * - `bytes` : raw `Uint8Array`. Provider layers normalize to base64 or
15
+ * multipart upload at the wire boundary - users don't need
16
+ * to encode themselves.
17
+ *
18
+ * Per-modality files (`Image.ts`, future `Audio.ts` / `Video.ts` /
19
+ * `Document.ts`) instantiate this shape with their typed MIME union to
20
+ * get autocomplete on common formats while keeping the structural type
21
+ * uniform across modalities.
22
+ *
23
+ * Streaming media (live mic feed, streaming TTS playback) is *not*
24
+ * modeled here. Streams carry effect parameters (`Stream<A, E, R>`) and
25
+ * lifecycle (Scope, cancellation) that don't apply to media at rest. The
26
+ * complementary type lives alongside this one as `*Stream` in each
27
+ * per-modality file when those modalities land.
28
+ *
29
+ * Provider-uploaded asset references (OpenAI Files `file_id`, Gemini
30
+ * Files API URIs, Anthropic file IDs) are also out of scope here -
31
+ * they're a separate union (`FileRef`) added when needed.
32
+ */
33
+
34
+ export type MediaUrl<M extends string = string> = {
35
+ readonly _tag: "url"
36
+ readonly url: string
37
+ readonly mimeType?: M
38
+ }
39
+
40
+ export type MediaBase64<M extends string = string> = {
41
+ readonly _tag: "base64"
42
+ readonly base64: string
43
+ readonly mimeType: M
44
+ }
45
+
46
+ export type MediaBytes<M extends string = string> = {
47
+ readonly _tag: "bytes"
48
+ readonly bytes: Uint8Array
49
+ readonly mimeType: M
50
+ }
51
+
52
+ export type MediaSource<M extends string = string> = MediaUrl<M> | MediaBase64<M> | MediaBytes<M>
53
+
54
+ export const isMediaUrl = <M extends string>(s: MediaSource<M>): s is MediaUrl<M> =>
55
+ s._tag === "url"
56
+
57
+ export const isMediaBase64 = <M extends string>(s: MediaSource<M>): s is MediaBase64<M> =>
58
+ s._tag === "base64"
59
+
60
+ export const isMediaBytes = <M extends string>(s: MediaSource<M>): s is MediaBytes<M> =>
61
+ s._tag === "bytes"
@@ -0,0 +1,121 @@
1
+ import type { AudioBlob, AudioFormat } from "./Audio.js"
2
+
3
+ /**
4
+ * Prompt fragment with a relative weight. Native to Lyria RealTime
5
+ * (`{ text, weight }` pairs blended in the model). Single-prompt
6
+ * providers (Suno, Mureka, MiniMax) flatten to text at the adapter
7
+ * layer.
8
+ */
9
+ export type WeightedPrompt = {
10
+ readonly text: string
11
+ /** Default `1.0`. Range typically `[0, 1]`; provider-dependent. */
12
+ readonly weight?: number
13
+ }
14
+
15
+ /**
16
+ * Cross-provider music-generation request. Provider-specific extras
17
+ * (Lyria `mode`, ElevenLabs `composition_plan`, Suno custom-mode `title`,
18
+ * MiniMax `lyrics_optimizer`) live on each provider's typed request
19
+ * which extends this and narrows `model`.
20
+ */
21
+ export type CommonGenerateMusicRequest = {
22
+ /** Model identifier. Each provider narrows. */
23
+ readonly model: string
24
+ /** Single prompt string or weighted-prompt list (blended where supported). */
25
+ readonly prompts: string | ReadonlyArray<WeightedPrompt>
26
+ /**
27
+ * Lyrics text, optionally with section tags like `[Verse]` / `[Chorus]` /
28
+ * `[Bridge]` / `[Outro]`. Ignored for instrumental-only providers or
29
+ * when `instrumental: true`.
30
+ */
31
+ readonly lyrics?: string
32
+ /** Target duration in seconds. Provider may treat as a hint or hard limit. */
33
+ readonly durationSeconds?: number
34
+ /** Beats per minute (60–200 typical). */
35
+ readonly bpm?: number
36
+ /**
37
+ * Musical key/mode hint. Provider-specific vocabulary (e.g. Lyria
38
+ * RealTime uses enum values like `"C_MAJOR"`, `"A_MINOR"`).
39
+ */
40
+ readonly scale?: string
41
+ /** Skip vocals / lyrics. */
42
+ readonly instrumental?: boolean
43
+ /** Preferred output format. Provider may override. */
44
+ readonly outputFormat?: AudioFormat
45
+ }
46
+
47
+ /**
48
+ * Streamed-output request. Same shape as the sync request — the
49
+ * streaming variant only differs in how the response is delivered.
50
+ */
51
+ export type CommonStreamGenerateMusicRequest = CommonGenerateMusicRequest
52
+
53
+ /**
54
+ * Bidirectional-session input. The user pushes one of these per
55
+ * change: a new prompt blend, a config delta, or a playback control.
56
+ * Lyria RealTime is the only provider currently surfacing these.
57
+ */
58
+ export type MusicSessionInput =
59
+ | { readonly _tag: "prompts"; readonly prompts: ReadonlyArray<WeightedPrompt> }
60
+ | {
61
+ readonly _tag: "config"
62
+ readonly config: {
63
+ readonly bpm?: number
64
+ readonly scale?: string
65
+ readonly density?: number
66
+ readonly brightness?: number
67
+ readonly guidance?: number
68
+ readonly temperature?: number
69
+ readonly topK?: number
70
+ readonly seed?: number
71
+ readonly muteBass?: boolean
72
+ readonly muteDrums?: boolean
73
+ readonly onlyBassAndDrums?: boolean
74
+ }
75
+ }
76
+ | { readonly _tag: "control"; readonly action: "play" | "pause" | "stop" | "reset_context" }
77
+
78
+ export const promptsInput = (prompts: ReadonlyArray<WeightedPrompt>): MusicSessionInput => ({
79
+ _tag: "prompts",
80
+ prompts,
81
+ })
82
+
83
+ export const configInput = (
84
+ config: (MusicSessionInput & { _tag: "config" })["config"],
85
+ ): MusicSessionInput => ({ _tag: "config", config })
86
+
87
+ export const controlInput = (
88
+ action: (MusicSessionInput & { _tag: "control" })["action"],
89
+ ): MusicSessionInput => ({ _tag: "control", action })
90
+
91
+ /**
92
+ * Sync-generation result. Extends `AudioBlob` with provider-side
93
+ * metadata that's common across music providers:
94
+ *
95
+ * - `songId` — Suno task id, ElevenLabs `song_id`, etc. Used for
96
+ * back-reference (re-download, stem export, follow-up edits).
97
+ * - `lyrics` — generated lyrics when the model returned them (Lyria
98
+ * text part, Mureka, Suno).
99
+ * - `sections` — structured section markers (Lyria optional JSON
100
+ * structure response).
101
+ * - `watermark` — presence marker (Lyria SynthID is always set).
102
+ */
103
+ export type MusicResult = AudioBlob & {
104
+ readonly songId?: string
105
+ readonly lyrics?: string
106
+ readonly sections?: ReadonlyArray<{
107
+ readonly label: string
108
+ readonly startSeconds: number
109
+ readonly endSeconds: number
110
+ }>
111
+ readonly watermark?: { readonly kind: string }
112
+ }
113
+
114
+ export const isPromptsInput = (
115
+ i: MusicSessionInput,
116
+ ): i is MusicSessionInput & { _tag: "prompts" } => i._tag === "prompts"
117
+ export const isConfigInput = (i: MusicSessionInput): i is MusicSessionInput & { _tag: "config" } =>
118
+ i._tag === "config"
119
+ export const isControlInput = (
120
+ i: MusicSessionInput,
121
+ ): i is MusicSessionInput & { _tag: "control" } => i._tag === "control"