@effect/ai 0.26.0 → 0.27.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 (188) hide show
  1. package/Chat/package.json +6 -0
  2. package/EmbeddingModel/package.json +6 -0
  3. package/IdGenerator/package.json +6 -0
  4. package/LanguageModel/package.json +6 -0
  5. package/Model/package.json +6 -0
  6. package/Prompt/package.json +6 -0
  7. package/Response/package.json +6 -0
  8. package/Telemetry/package.json +6 -0
  9. package/Tool/package.json +6 -0
  10. package/Toolkit/package.json +6 -0
  11. package/dist/cjs/AiError.js +575 -11
  12. package/dist/cjs/AiError.js.map +1 -1
  13. package/dist/cjs/Chat.js +302 -0
  14. package/dist/cjs/Chat.js.map +1 -0
  15. package/dist/cjs/EmbeddingModel.js +184 -0
  16. package/dist/cjs/EmbeddingModel.js.map +1 -0
  17. package/dist/cjs/IdGenerator.js +255 -0
  18. package/dist/cjs/IdGenerator.js.map +1 -0
  19. package/dist/cjs/LanguageModel.js +584 -0
  20. package/dist/cjs/LanguageModel.js.map +1 -0
  21. package/dist/cjs/McpServer.js +12 -4
  22. package/dist/cjs/McpServer.js.map +1 -1
  23. package/dist/cjs/Model.js +118 -0
  24. package/dist/cjs/Model.js.map +1 -0
  25. package/dist/cjs/Prompt.js +649 -0
  26. package/dist/cjs/Prompt.js.map +1 -0
  27. package/dist/cjs/Response.js +635 -0
  28. package/dist/cjs/Response.js.map +1 -0
  29. package/dist/cjs/Telemetry.js +176 -0
  30. package/dist/cjs/Telemetry.js.map +1 -0
  31. package/dist/cjs/Tokenizer.js +87 -8
  32. package/dist/cjs/Tokenizer.js.map +1 -1
  33. package/dist/cjs/Tool.js +556 -0
  34. package/dist/cjs/Tool.js.map +1 -0
  35. package/dist/cjs/Toolkit.js +279 -0
  36. package/dist/cjs/Toolkit.js.map +1 -0
  37. package/dist/cjs/index.js +21 -19
  38. package/dist/dts/AiError.d.ts +577 -9
  39. package/dist/dts/AiError.d.ts.map +1 -1
  40. package/dist/dts/Chat.d.ts +356 -0
  41. package/dist/dts/Chat.d.ts.map +1 -0
  42. package/dist/dts/EmbeddingModel.d.ts +153 -0
  43. package/dist/dts/EmbeddingModel.d.ts.map +1 -0
  44. package/dist/dts/IdGenerator.d.ts +272 -0
  45. package/dist/dts/IdGenerator.d.ts.map +1 -0
  46. package/dist/dts/LanguageModel.d.ts +458 -0
  47. package/dist/dts/LanguageModel.d.ts.map +1 -0
  48. package/dist/dts/McpSchema.d.ts +25 -25
  49. package/dist/dts/McpServer.d.ts +6 -4
  50. package/dist/dts/McpServer.d.ts.map +1 -1
  51. package/dist/dts/Model.d.ts +124 -0
  52. package/dist/dts/Model.d.ts.map +1 -0
  53. package/dist/dts/Prompt.d.ts +1119 -0
  54. package/dist/dts/Prompt.d.ts.map +1 -0
  55. package/dist/dts/Response.d.ts +1519 -0
  56. package/dist/dts/Response.d.ts.map +1 -0
  57. package/dist/dts/Telemetry.d.ts +520 -0
  58. package/dist/dts/Telemetry.d.ts.map +1 -0
  59. package/dist/dts/Tokenizer.d.ts +131 -13
  60. package/dist/dts/Tokenizer.d.ts.map +1 -1
  61. package/dist/dts/Tool.d.ts +876 -0
  62. package/dist/dts/Tool.d.ts.map +1 -0
  63. package/dist/dts/Toolkit.d.ts +310 -0
  64. package/dist/dts/Toolkit.d.ts.map +1 -0
  65. package/dist/dts/index.d.ts +498 -13
  66. package/dist/dts/index.d.ts.map +1 -1
  67. package/dist/esm/AiError.js +570 -10
  68. package/dist/esm/AiError.js.map +1 -1
  69. package/dist/esm/Chat.js +291 -0
  70. package/dist/esm/Chat.js.map +1 -0
  71. package/dist/esm/EmbeddingModel.js +173 -0
  72. package/dist/esm/EmbeddingModel.js.map +1 -0
  73. package/dist/esm/IdGenerator.js +245 -0
  74. package/dist/esm/IdGenerator.js.map +1 -0
  75. package/dist/esm/LanguageModel.js +572 -0
  76. package/dist/esm/LanguageModel.js.map +1 -0
  77. package/dist/esm/McpServer.js +12 -4
  78. package/dist/esm/McpServer.js.map +1 -1
  79. package/dist/esm/Model.js +108 -0
  80. package/dist/esm/Model.js.map +1 -0
  81. package/dist/esm/Prompt.js +633 -0
  82. package/dist/esm/Prompt.js.map +1 -0
  83. package/dist/esm/Response.js +619 -0
  84. package/dist/esm/Response.js.map +1 -0
  85. package/dist/esm/Telemetry.js +166 -0
  86. package/dist/esm/Telemetry.js.map +1 -0
  87. package/dist/esm/Tokenizer.js +87 -8
  88. package/dist/esm/Tokenizer.js.map +1 -1
  89. package/dist/esm/Tool.js +534 -0
  90. package/dist/esm/Tool.js.map +1 -0
  91. package/dist/esm/Toolkit.js +269 -0
  92. package/dist/esm/Toolkit.js.map +1 -0
  93. package/dist/esm/index.js +498 -13
  94. package/dist/esm/index.js.map +1 -1
  95. package/package.json +76 -68
  96. package/src/AiError.ts +739 -9
  97. package/src/Chat.ts +546 -0
  98. package/src/EmbeddingModel.ts +311 -0
  99. package/src/IdGenerator.ts +320 -0
  100. package/src/LanguageModel.ts +1074 -0
  101. package/src/McpServer.ts +337 -194
  102. package/src/Model.ts +155 -0
  103. package/src/Prompt.ts +1616 -0
  104. package/src/Response.ts +2131 -0
  105. package/src/Telemetry.ts +655 -0
  106. package/src/Tokenizer.ts +145 -24
  107. package/src/Tool.ts +1267 -0
  108. package/src/Toolkit.ts +516 -0
  109. package/src/index.ts +499 -13
  110. package/AiChat/package.json +0 -6
  111. package/AiEmbeddingModel/package.json +0 -6
  112. package/AiInput/package.json +0 -6
  113. package/AiLanguageModel/package.json +0 -6
  114. package/AiModel/package.json +0 -6
  115. package/AiResponse/package.json +0 -6
  116. package/AiTelemetry/package.json +0 -6
  117. package/AiTool/package.json +0 -6
  118. package/AiToolkit/package.json +0 -6
  119. package/dist/cjs/AiChat.js +0 -122
  120. package/dist/cjs/AiChat.js.map +0 -1
  121. package/dist/cjs/AiEmbeddingModel.js +0 -109
  122. package/dist/cjs/AiEmbeddingModel.js.map +0 -1
  123. package/dist/cjs/AiInput.js +0 -458
  124. package/dist/cjs/AiInput.js.map +0 -1
  125. package/dist/cjs/AiLanguageModel.js +0 -351
  126. package/dist/cjs/AiLanguageModel.js.map +0 -1
  127. package/dist/cjs/AiModel.js +0 -37
  128. package/dist/cjs/AiModel.js.map +0 -1
  129. package/dist/cjs/AiResponse.js +0 -681
  130. package/dist/cjs/AiResponse.js.map +0 -1
  131. package/dist/cjs/AiTelemetry.js +0 -58
  132. package/dist/cjs/AiTelemetry.js.map +0 -1
  133. package/dist/cjs/AiTool.js +0 -150
  134. package/dist/cjs/AiTool.js.map +0 -1
  135. package/dist/cjs/AiToolkit.js +0 -157
  136. package/dist/cjs/AiToolkit.js.map +0 -1
  137. package/dist/cjs/internal/common.js +0 -21
  138. package/dist/cjs/internal/common.js.map +0 -1
  139. package/dist/dts/AiChat.d.ts +0 -101
  140. package/dist/dts/AiChat.d.ts.map +0 -1
  141. package/dist/dts/AiEmbeddingModel.d.ts +0 -65
  142. package/dist/dts/AiEmbeddingModel.d.ts.map +0 -1
  143. package/dist/dts/AiInput.d.ts +0 -590
  144. package/dist/dts/AiInput.d.ts.map +0 -1
  145. package/dist/dts/AiLanguageModel.d.ts +0 -302
  146. package/dist/dts/AiLanguageModel.d.ts.map +0 -1
  147. package/dist/dts/AiModel.d.ts +0 -25
  148. package/dist/dts/AiModel.d.ts.map +0 -1
  149. package/dist/dts/AiResponse.d.ts +0 -863
  150. package/dist/dts/AiResponse.d.ts.map +0 -1
  151. package/dist/dts/AiTelemetry.d.ts +0 -242
  152. package/dist/dts/AiTelemetry.d.ts.map +0 -1
  153. package/dist/dts/AiTool.d.ts +0 -334
  154. package/dist/dts/AiTool.d.ts.map +0 -1
  155. package/dist/dts/AiToolkit.d.ts +0 -96
  156. package/dist/dts/AiToolkit.d.ts.map +0 -1
  157. package/dist/dts/internal/common.d.ts +0 -2
  158. package/dist/dts/internal/common.d.ts.map +0 -1
  159. package/dist/esm/AiChat.js +0 -111
  160. package/dist/esm/AiChat.js.map +0 -1
  161. package/dist/esm/AiEmbeddingModel.js +0 -98
  162. package/dist/esm/AiEmbeddingModel.js.map +0 -1
  163. package/dist/esm/AiInput.js +0 -433
  164. package/dist/esm/AiInput.js.map +0 -1
  165. package/dist/esm/AiLanguageModel.js +0 -340
  166. package/dist/esm/AiLanguageModel.js.map +0 -1
  167. package/dist/esm/AiModel.js +0 -29
  168. package/dist/esm/AiModel.js.map +0 -1
  169. package/dist/esm/AiResponse.js +0 -657
  170. package/dist/esm/AiResponse.js.map +0 -1
  171. package/dist/esm/AiTelemetry.js +0 -48
  172. package/dist/esm/AiTelemetry.js.map +0 -1
  173. package/dist/esm/AiTool.js +0 -134
  174. package/dist/esm/AiTool.js.map +0 -1
  175. package/dist/esm/AiToolkit.js +0 -147
  176. package/dist/esm/AiToolkit.js.map +0 -1
  177. package/dist/esm/internal/common.js +0 -14
  178. package/dist/esm/internal/common.js.map +0 -1
  179. package/src/AiChat.ts +0 -251
  180. package/src/AiEmbeddingModel.ts +0 -169
  181. package/src/AiInput.ts +0 -602
  182. package/src/AiLanguageModel.ts +0 -685
  183. package/src/AiModel.ts +0 -53
  184. package/src/AiResponse.ts +0 -986
  185. package/src/AiTelemetry.ts +0 -333
  186. package/src/AiTool.ts +0 -579
  187. package/src/AiToolkit.ts +0 -265
  188. package/src/internal/common.ts +0 -12
package/src/Prompt.ts ADDED
@@ -0,0 +1,1616 @@
1
+ /**
2
+ * The `Prompt` module provides several data structures to simplify creating and
3
+ * combining prompts.
4
+ *
5
+ * This module defines the complete structure of a conversation with a large
6
+ * language model, including messages, content parts, and provider-specific
7
+ * options. It supports rich content types like text, files, tool calls, and
8
+ * reasoning.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { Prompt } from "@effect/ai"
13
+ *
14
+ * // Create a structured conversation
15
+ * const conversation = Prompt.make([
16
+ * {
17
+ * role: "system",
18
+ * content: "You are a helpful assistant specialized in mathematics."
19
+ * },
20
+ * {
21
+ * role: "user",
22
+ * content: [{
23
+ * type: "text",
24
+ * text: "What is the derivative of x²?"
25
+ * }]
26
+ * },
27
+ * {
28
+ * role: "assistant",
29
+ * content: [{
30
+ * type: "text",
31
+ * text: "The derivative of x² is 2x."
32
+ * }]
33
+ * }
34
+ * ])
35
+ * ```
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * import { Prompt } from "@effect/ai"
40
+ *
41
+ * // Merge multiple prompts
42
+ * const systemPrompt = Prompt.make([{
43
+ * role: "system",
44
+ * content: "You are a coding assistant."
45
+ * }])
46
+ *
47
+ * const userPrompt = Prompt.make("Help me write a function")
48
+ *
49
+ * const combined = Prompt.merge(systemPrompt, userPrompt)
50
+ * ```
51
+ *
52
+ * @since 1.0.0
53
+ */
54
+ import { constFalse, dual } from "effect/Function"
55
+ import * as Predicate from "effect/Predicate"
56
+ import * as Schema from "effect/Schema"
57
+ import type * as Response from "./Response.js"
58
+
59
+ const constEmptyObject = () => ({})
60
+
61
+ // =============================================================================
62
+ // Options
63
+ // =============================================================================
64
+
65
+ /**
66
+ * Schema for provider-specific options which can be attached to both content
67
+ * parts and messages, enabling provider-specific behavior.
68
+ *
69
+ * Provider-specific options are namespaced by provider and have the structure:
70
+ *
71
+ * ```
72
+ * {
73
+ * "<provider-specific-key>": {
74
+ * // Provider-specific options
75
+ * }
76
+ * }
77
+ * ```
78
+ *
79
+ * @since 1.0.0
80
+ * @category Models
81
+ */
82
+ export const ProviderOptions = Schema.Record({
83
+ key: Schema.String,
84
+ value: Schema.Record({ key: Schema.String, value: Schema.Unknown })
85
+ })
86
+
87
+ /**
88
+ * @since 1.0.0
89
+ * @category Models
90
+ */
91
+ export type ProviderOptions = typeof ProviderOptions.Type
92
+
93
+ // =============================================================================
94
+ // Base Part
95
+ // =============================================================================
96
+
97
+ /**
98
+ * Unique identifier for Part instances.
99
+ *
100
+ * @since 1.0.0
101
+ * @category Type Ids
102
+ */
103
+ export const PartTypeId = "~effect/ai/Prompt/Part"
104
+
105
+ /**
106
+ * Type-level representation of the Part identifier.
107
+ *
108
+ * @since 1.0.0
109
+ * @category Type Ids
110
+ */
111
+ export type PartTypeId = typeof PartTypeId
112
+
113
+ /**
114
+ * Type guard to check if a value is a Part.
115
+ *
116
+ * @since 1.0.0
117
+ * @category Guards
118
+ */
119
+ export const isPart = (u: unknown): u is Part => Predicate.hasProperty(u, PartTypeId)
120
+
121
+ /**
122
+ * Union type representing all possible content parts within messages.
123
+ *
124
+ * Parts are the building blocks of message content, supporting text, files,
125
+ * reasoning, tool calls, and tool results.
126
+ *
127
+ * @since 1.0.0
128
+ * @category Models
129
+ */
130
+ export type Part = TextPart | ReasoningPart | FilePart | ToolCallPart | ToolResultPart
131
+
132
+ /**
133
+ * Encoded representation of a Part.
134
+ *
135
+ * @since 1.0.0
136
+ * @category Models
137
+ */
138
+ export type PartEncoded =
139
+ | TextPartEncoded
140
+ | ReasoningPartEncoded
141
+ | FilePartEncoded
142
+ | ToolCallPartEncoded
143
+ | ToolResultPartEncoded
144
+
145
+ /**
146
+ * Base interface for all content parts.
147
+ *
148
+ * Provides common structure including type and provider options.
149
+ *
150
+ * @since 1.0.0
151
+ * @category Models
152
+ */
153
+ export interface BasePart<Type extends string, Options extends ProviderOptions> {
154
+ readonly [PartTypeId]: PartTypeId
155
+ /**
156
+ * The type of this content part.
157
+ */
158
+ readonly type: Type
159
+ /**
160
+ * Provider-specific options for this part.
161
+ */
162
+ readonly options: Options
163
+ }
164
+
165
+ /**
166
+ * Base interface for encoded content parts.
167
+ *
168
+ * @since 1.0.0
169
+ * @category Models
170
+ */
171
+ export interface BasePartEncoded<Type extends string, Options extends ProviderOptions> {
172
+ /**
173
+ * The type of this content part.
174
+ */
175
+ readonly type: Type
176
+ /**
177
+ * Provider-specific options for this part.
178
+ */
179
+ readonly options?: Options | undefined
180
+ }
181
+
182
+ /**
183
+ * Creates a new content part of the specified type.
184
+ *
185
+ * @example
186
+ * ```ts
187
+ * import { Prompt } from "@effect/ai"
188
+ *
189
+ * const textPart = Prompt.makePart("text", {
190
+ * text: "Hello, world!"
191
+ * })
192
+ *
193
+ * const filePart = Prompt.makePart("file", {
194
+ * mediaType: "image/png",
195
+ * fileName: "screenshot.png",
196
+ * data: new Uint8Array([1, 2, 3])
197
+ * })
198
+ * ```
199
+ *
200
+ * @since 1.0.0
201
+ * @category Constructors
202
+ */
203
+ export const makePart = <const Type extends Part["type"]>(
204
+ /**
205
+ * The type of part to create.
206
+ */
207
+ type: Type,
208
+ /**
209
+ * Parameters specific to the part type being created.
210
+ */
211
+ params: Omit<Extract<Part, { type: Type }>, PartTypeId | "type" | "options"> & {
212
+ /**
213
+ * Optional provider-specific options for this part.
214
+ */
215
+ readonly options?: Extract<Part, { type: Type }>["options"] | undefined
216
+ }
217
+ ): Extract<Part, { type: Type }> =>
218
+ (({
219
+ ...params,
220
+ [PartTypeId]: PartTypeId,
221
+ type,
222
+ options: params.options ?? {}
223
+ }) as any)
224
+
225
+ // =============================================================================
226
+ // Text Part
227
+ // =============================================================================
228
+
229
+ /**
230
+ * Content part representing plain text.
231
+ *
232
+ * The most basic content type used for textual information in messages.
233
+ *
234
+ * @example
235
+ * ```ts
236
+ * import { Prompt } from "@effect/ai"
237
+ *
238
+ * const textPart: Prompt.TextPart = Prompt.makePart("text", {
239
+ * text: "Hello, how can I help you today?",
240
+ * })
241
+ * ```
242
+ *
243
+ * @since 1.0.0
244
+ * @category Models
245
+ */
246
+ export interface TextPart extends BasePart<"text", TextPartOptions> {
247
+ /**
248
+ * The text content.
249
+ */
250
+ readonly text: string
251
+ }
252
+
253
+ /**
254
+ * Encoded representation of text parts for serialization.
255
+ *
256
+ * @since 1.0.0
257
+ * @category Models
258
+ */
259
+ export interface TextPartEncoded extends BasePartEncoded<"text", TextPartOptions> {
260
+ /**
261
+ * The text content.
262
+ */
263
+ readonly text: string
264
+ }
265
+
266
+ /**
267
+ * Represents provider-specific options that can be associated with a
268
+ * `TextPart` through module augmentation.
269
+ *
270
+ * @since 1.0.0
271
+ * @category ProviderOptions
272
+ */
273
+ export interface TextPartOptions extends ProviderOptions {}
274
+
275
+ /**
276
+ * Schema for validation and encoding of text parts.
277
+ *
278
+ * @since 1.0.0
279
+ * @category Schemas
280
+ */
281
+ export const TextPart: Schema.Schema<TextPart, TextPartEncoded> = Schema.Struct({
282
+ type: Schema.Literal("text"),
283
+ text: Schema.String,
284
+ options: Schema.optionalWith(ProviderOptions, { default: constEmptyObject })
285
+ }).pipe(
286
+ Schema.attachPropertySignature(PartTypeId, PartTypeId),
287
+ Schema.annotations({ identifier: "TextPart" })
288
+ )
289
+
290
+ // =============================================================================
291
+ // Reasoning Part
292
+ // =============================================================================
293
+
294
+ /**
295
+ * Content part representing reasoning or chain-of-thought.
296
+ *
297
+ * @example
298
+ * ```ts
299
+ * import { Prompt } from "@effect/ai"
300
+ *
301
+ * const reasoningPart: Prompt.ReasoningPart = Prompt.makePart("reasoning", {
302
+ * text: "Let me think step by step: First I need to understand the user's question...",
303
+ * })
304
+ * ```
305
+ *
306
+ * @since 1.0.0
307
+ * @category Models
308
+ */
309
+ export interface ReasoningPart extends BasePart<"reasoning", ReasoningPartOptions> {
310
+ /**
311
+ * The reasoning or thought process text.
312
+ */
313
+ readonly text: string
314
+ }
315
+
316
+ /**
317
+ * Encoded representation of reasoning parts for serialization.
318
+ *
319
+ * @since 1.0.0
320
+ * @category Models
321
+ */
322
+ export interface ReasoningPartEncoded extends BasePartEncoded<"reasoning", ReasoningPartOptions> {
323
+ /**
324
+ * The reasoning or thought process text.
325
+ */
326
+ readonly text: string
327
+ }
328
+
329
+ /**
330
+ * Represents provider-specific options that can be associated with a
331
+ * `ReasoningPart` through module augmentation.
332
+ *
333
+ * @since 1.0.0
334
+ * @category ProviderOptions
335
+ */
336
+ export interface ReasoningPartOptions extends ProviderOptions {}
337
+
338
+ /**
339
+ * Schema for validation and encoding of reasoning parts.
340
+ *
341
+ * @since 1.0.0
342
+ * @category Schemas
343
+ */
344
+ export const ReasoningPart: Schema.Schema<ReasoningPart, ReasoningPartEncoded> = Schema.Struct({
345
+ type: Schema.Literal("reasoning"),
346
+ text: Schema.String,
347
+ options: Schema.optionalWith(ProviderOptions, { default: constEmptyObject })
348
+ }).pipe(
349
+ Schema.attachPropertySignature(PartTypeId, PartTypeId),
350
+ Schema.annotations({ identifier: "ReasoningPart" })
351
+ )
352
+
353
+ // =============================================================================
354
+ // File Part
355
+ // =============================================================================
356
+
357
+ /**
358
+ * Content part representing a file attachment. Files can be provided as base64
359
+ * strings of data, byte arrays, or URLs.
360
+ *
361
+ * Supports various file types including images, documents, and binary data.
362
+ *
363
+ * @example
364
+ * ```ts
365
+ * import { Prompt } from "@effect/ai"
366
+ *
367
+ * const imagePart: Prompt.FilePart = Prompt.makePart("file", {
368
+ * mediaType: "image/jpeg",
369
+ * fileName: "photo.jpg",
370
+ * data: "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ..."
371
+ * })
372
+ *
373
+ * const documentPart: Prompt.FilePart = Prompt.makePart("file", {
374
+ * mediaType: "application/pdf",
375
+ * fileName: "report.pdf",
376
+ * data: new Uint8Array([1, 2, 3])
377
+ * })
378
+ * ```
379
+ *
380
+ * @since 1.0.0
381
+ * @category Models
382
+ */
383
+ export interface FilePart extends BasePart<"file", FilePartOptions> {
384
+ /**
385
+ * MIME type of the file (e.g., "image/jpeg", "application/pdf").
386
+ */
387
+ readonly mediaType: string
388
+ /**
389
+ * Optional filename for the file.
390
+ */
391
+ readonly fileName?: string | undefined
392
+ /**
393
+ * File data as base64 string of data, a byte array, or a URL.
394
+ */
395
+ readonly data: string | Uint8Array | URL
396
+ }
397
+
398
+ /**
399
+ * Encoded representation of file parts for serialization.
400
+ *
401
+ * @since 1.0.0
402
+ * @category Models
403
+ */
404
+ export interface FilePartEncoded extends BasePartEncoded<"file", FilePartOptions> {
405
+ /**
406
+ * MIME type of the file (e.g., "image/jpeg", "application/pdf").
407
+ */
408
+ readonly mediaType: string
409
+ /**
410
+ * Optional filename for the file.
411
+ */
412
+ readonly fileName?: string | undefined
413
+ /**
414
+ * File data as base64 string of data, a byte array, or a URL.
415
+ */
416
+ readonly data: string | Uint8Array | URL
417
+ }
418
+
419
+ /**
420
+ * Represents provider-specific options that can be associated with a
421
+ * `FilePart` through module augmentation.
422
+ *
423
+ * @since 1.0.0
424
+ * @category ProviderOptions
425
+ */
426
+ export interface FilePartOptions extends ProviderOptions {}
427
+
428
+ /**
429
+ * Schema for validation and encoding of file parts.
430
+ *
431
+ * @since 1.0.0
432
+ * @category Schemas
433
+ */
434
+ export const FilePart: Schema.Schema<FilePart, FilePartEncoded> = Schema.Struct({
435
+ type: Schema.Literal("file"),
436
+ mediaType: Schema.String,
437
+ fileName: Schema.optional(Schema.String),
438
+ data: Schema.Union(Schema.String, Schema.Uint8ArrayFromSelf, Schema.URLFromSelf),
439
+ options: Schema.optionalWith(ProviderOptions, { default: constEmptyObject })
440
+ }).pipe(
441
+ Schema.attachPropertySignature(PartTypeId, PartTypeId),
442
+ Schema.annotations({ identifier: "FilePart" })
443
+ )
444
+
445
+ // =============================================================================
446
+ // Tool Call Part
447
+ // =============================================================================
448
+
449
+ /**
450
+ * Content part representing a tool call request.
451
+ *
452
+ * @example
453
+ * ```ts
454
+ * import { Prompt } from "@effect/ai"
455
+ *
456
+ * const toolCallPart: Prompt.ToolCallPart = Prompt.makePart("tool-call", {
457
+ * id: "call_123",
458
+ * name: "get_weather",
459
+ * params: { city: "San Francisco", units: "celsius" },
460
+ * providerExecuted: false,
461
+ * })
462
+ * ```
463
+ *
464
+ * @since 1.0.0
465
+ * @category Models
466
+ */
467
+ export interface ToolCallPart extends BasePart<"tool-call", ToolCallPartOptions> {
468
+ /**
469
+ * Unique identifier for this tool call.
470
+ */
471
+ readonly id: string
472
+ /**
473
+ * Name of the tool to invoke.
474
+ */
475
+ readonly name: string
476
+ /**
477
+ * Parameters to pass to the tool.
478
+ */
479
+ readonly params: unknown
480
+ /**
481
+ * Whether the tool was executed by the provider (true) or framework (false).
482
+ */
483
+ readonly providerExecuted: boolean
484
+ }
485
+
486
+ /**
487
+ * Encoded representation of tool call parts for serialization.
488
+ *
489
+ * @since 1.0.0
490
+ * @category Models
491
+ */
492
+ export interface ToolCallPartEncoded extends BasePartEncoded<"tool-call", ToolCallPartOptions> {
493
+ /**
494
+ * Unique identifier for this tool call.
495
+ */
496
+ readonly id: string
497
+ /**
498
+ * Name of the tool to invoke.
499
+ */
500
+ readonly name: string
501
+ /**
502
+ * Parameters to pass to the tool.
503
+ */
504
+ readonly params: unknown
505
+ /**
506
+ * Whether the tool was executed by the provider (true) or framework (false).
507
+ */
508
+ readonly providerExecuted?: boolean | undefined
509
+ }
510
+
511
+ /**
512
+ * Represents provider-specific options that can be associated with a
513
+ * `ToolCallPart` through module augmentation.
514
+ *
515
+ * @since 1.0.0
516
+ * @category ProviderOptions
517
+ */
518
+ export interface ToolCallPartOptions extends ProviderOptions {}
519
+
520
+ /**
521
+ * Schema for validation and encoding of tool call parts.
522
+ *
523
+ * @since 1.0.0
524
+ * @category Schemas
525
+ */
526
+ export const ToolCallPart: Schema.Schema<ToolCallPart, ToolCallPartEncoded> = Schema.Struct({
527
+ type: Schema.Literal("tool-call"),
528
+ id: Schema.String,
529
+ name: Schema.String,
530
+ params: Schema.Unknown,
531
+ providerExecuted: Schema.optionalWith(Schema.Boolean, { default: constFalse }),
532
+ options: Schema.optionalWith(ProviderOptions, { default: constEmptyObject })
533
+ }).pipe(
534
+ Schema.attachPropertySignature(PartTypeId, PartTypeId),
535
+ Schema.annotations({ identifier: "ToolCallPart" })
536
+ )
537
+
538
+ // =============================================================================
539
+ // Tool Result Part
540
+ // =============================================================================
541
+
542
+ /**
543
+ * Content part representing the result of a tool call.
544
+ *
545
+ * @example
546
+ * ```ts
547
+ * import { Prompt } from "@effect/ai"
548
+ *
549
+ * const toolResultPart: Prompt.ToolResultPart = Prompt.makePart("tool-result", {
550
+ * id: "call_123",
551
+ * name: "get_weather",
552
+ * result: {
553
+ * temperature: 22,
554
+ * condition: "sunny",
555
+ * humidity: 65
556
+ * }
557
+ * })
558
+ * ```
559
+ *
560
+ * @since 1.0.0
561
+ * @category Models
562
+ */
563
+ export interface ToolResultPart extends BasePart<"tool-result", ToolResultPartOptions> {
564
+ /**
565
+ * Unique identifier matching the original tool call.
566
+ */
567
+ readonly id: string
568
+ /**
569
+ * Name of the tool that was executed.
570
+ */
571
+ readonly name: string
572
+ /**
573
+ * The result returned by the tool execution.
574
+ */
575
+ readonly result: unknown
576
+ }
577
+
578
+ /**
579
+ * Encoded representation of tool result parts for serialization.
580
+ *
581
+ * @since 1.0.0
582
+ * @category Models
583
+ */
584
+ export interface ToolResultPartEncoded extends BasePartEncoded<"tool-result", ToolResultPartOptions> {
585
+ /**
586
+ * Unique identifier matching the original tool call.
587
+ */
588
+ readonly id: string
589
+ /**
590
+ * Name of the tool that was executed.
591
+ */
592
+ readonly name: string
593
+ /**
594
+ * The result returned by the tool execution.
595
+ */
596
+ readonly result: unknown
597
+ }
598
+
599
+ /**
600
+ * Represents provider-specific options that can be associated with a
601
+ * `ToolResultPart` through module augmentation.
602
+ *
603
+ * @since 1.0.0
604
+ * @category ProviderOptions
605
+ */
606
+ export interface ToolResultPartOptions extends ProviderOptions {}
607
+
608
+ /**
609
+ * Schema for validation and encoding of tool result parts.
610
+ *
611
+ * @since 1.0.0
612
+ * @category Schemas
613
+ */
614
+ export const ToolResultPart: Schema.Schema<ToolResultPart, ToolResultPartEncoded> = Schema.Struct({
615
+ type: Schema.Literal("tool-result"),
616
+ id: Schema.String,
617
+ name: Schema.String,
618
+ result: Schema.Unknown,
619
+ options: Schema.optionalWith(ProviderOptions, { default: constEmptyObject })
620
+ }).pipe(
621
+ Schema.attachPropertySignature(PartTypeId, PartTypeId),
622
+ Schema.annotations({ identifier: "ToolResultPart" })
623
+ )
624
+
625
+ // =============================================================================
626
+ // Base Message
627
+ // =============================================================================
628
+
629
+ /**
630
+ * Unique identifier for Message instances.
631
+ *
632
+ * @since 1.0.0
633
+ * @category Type Ids
634
+ */
635
+ export const MessageTypeId = "~effect/ai/Prompt/Message"
636
+
637
+ /**
638
+ * Type-level representation of the Message identifier.
639
+ *
640
+ * @since 1.0.0
641
+ * @category Type Ids
642
+ */
643
+ export type MessageTypeId = typeof MessageTypeId
644
+
645
+ /**
646
+ * Type guard to check if a value is a Message.
647
+ *
648
+ * @since 1.0.0
649
+ * @category Guards
650
+ */
651
+ export const isMessage = (u: unknown): u is Message => Predicate.hasProperty(u, MessageTypeId)
652
+
653
+ /**
654
+ * Base interface for all message types.
655
+ *
656
+ * Provides common structure including role and provider options.
657
+ *
658
+ * @since 1.0.0
659
+ * @category Models
660
+ */
661
+ export interface BaseMessage<Role extends string, Options extends ProviderOptions> {
662
+ readonly [MessageTypeId]: MessageTypeId
663
+ /**
664
+ * The role of the message participant.
665
+ */
666
+ readonly role: Role
667
+ /**
668
+ * Provider-specific options for this message.
669
+ */
670
+ readonly options: Options
671
+ }
672
+
673
+ /**
674
+ * Base interface for encoded message types.
675
+ *
676
+ * @template Role - String literal type for the message role
677
+ *
678
+ * @since 1.0.0
679
+ * @category Models
680
+ */
681
+ export interface BaseMessageEncoded<Role extends string, Options extends ProviderOptions> {
682
+ /**
683
+ * The role of the message participant.
684
+ */
685
+ readonly role: Role
686
+ /**
687
+ * Provider-specific options for this message.
688
+ */
689
+ readonly options?: Options | undefined
690
+ }
691
+
692
+ /**
693
+ * Creates a new message with the specified role.
694
+ *
695
+ * @example
696
+ * ```ts
697
+ * import { Prompt } from "@effect/ai"
698
+ *
699
+ * const textPart = Prompt.makePart("text", {
700
+ * text: "Hello, world!"
701
+ * })
702
+ *
703
+ * const filePart = Prompt.makeMessage("user", {
704
+ * content: [textPart]
705
+ * })
706
+ * ```
707
+ *
708
+ * @since 1.0.0
709
+ * @category Constructors
710
+ */
711
+ export const makeMessage = <const Role extends Message["role"]>(
712
+ role: Role,
713
+ params: Omit<Extract<Message, { role: Role }>, MessageTypeId | "role" | "options"> & {
714
+ readonly options?: Extract<Message, { role: Role }>["options"]
715
+ }
716
+ ): Extract<Message, { role: Role }> =>
717
+ (({
718
+ ...params,
719
+ [MessageTypeId]: MessageTypeId,
720
+ role,
721
+ options: params.options ?? {}
722
+ }) as any)
723
+
724
+ // =============================================================================
725
+ // System Message
726
+ // =============================================================================
727
+
728
+ /**
729
+ * Message representing system instructions or context.
730
+ *
731
+ * @example
732
+ * ```ts
733
+ * import { Prompt } from "@effect/ai"
734
+ *
735
+ * const systemMessage: Prompt.SystemMessage = Prompt.makeMessage("system", {
736
+ * content: "You are a helpful assistant specialized in mathematics. " +
737
+ * "Always show your work step by step."
738
+ * })
739
+ * ```
740
+ *
741
+ * @since 1.0.0
742
+ * @category Models
743
+ */
744
+ export interface SystemMessage extends BaseMessage<"system", SystemMessageOptions> {
745
+ /**
746
+ * The system instruction or context as plain text.
747
+ */
748
+ readonly content: string
749
+ }
750
+
751
+ /**
752
+ * Encoded representation of system messages for serialization.
753
+ *
754
+ * @since 1.0.0
755
+ * @category Models
756
+ */
757
+ export interface SystemMessageEncoded extends BaseMessageEncoded<"system", SystemMessageOptions> {
758
+ /**
759
+ * The system instruction or context as plain text.
760
+ */
761
+ readonly content: string
762
+ }
763
+
764
+ /**
765
+ * Represents provider-specific options that can be associated with a
766
+ * `SystemMessage` through module augmentation.
767
+ *
768
+ * @since 1.0.0
769
+ * @category ProviderOptions
770
+ */
771
+ export interface SystemMessageOptions extends ProviderOptions {}
772
+
773
+ /**
774
+ * Schema for validation and encoding of system messages.
775
+ *
776
+ * @since 1.0.0
777
+ * @category Schemas
778
+ */
779
+ export const SystemMessage: Schema.Schema<SystemMessage, SystemMessageEncoded> = Schema.Struct({
780
+ role: Schema.Literal("system"),
781
+ content: Schema.String,
782
+ options: Schema.optionalWith(ProviderOptions, { default: constEmptyObject })
783
+ }).pipe(
784
+ Schema.attachPropertySignature(MessageTypeId, MessageTypeId),
785
+ Schema.annotations({ identifier: "SystemMessage" })
786
+ )
787
+
788
+ // =============================================================================
789
+ // User Message
790
+ // =============================================================================
791
+
792
+ /**
793
+ * Message representing user input or questions.
794
+ *
795
+ * @example
796
+ * ```ts
797
+ * import { Prompt } from "@effect/ai"
798
+ *
799
+ * const textUserMessage: Prompt.UserMessage = Prompt.makeMessage("user", {
800
+ * content: [
801
+ * Prompt.makePart("text", {
802
+ * text: "Can you analyze this image for me?"
803
+ * })
804
+ * ]
805
+ * })
806
+ *
807
+ * const multimodalUserMessage: Prompt.UserMessage = Prompt.makeMessage("user", {
808
+ * content: [
809
+ * Prompt.makePart("text", {
810
+ * text: "What do you see in this image?"
811
+ * }),
812
+ * Prompt.makePart("file", {
813
+ * mediaType: "image/jpeg",
814
+ * fileName: "vacation.jpg",
815
+ * data: "data:image/jpeg;base64,..."
816
+ * })
817
+ * ]
818
+ * })
819
+ * ```
820
+ *
821
+ * @since 1.0.0
822
+ * @category Models
823
+ */
824
+ export interface UserMessage extends BaseMessage<"user", UserMessageOptions> {
825
+ /**
826
+ * Array of content parts that make up the user's message.
827
+ */
828
+ readonly content: ReadonlyArray<UserMessagePart>
829
+ }
830
+
831
+ /**
832
+ * Union type of content parts allowed in user messages.
833
+ *
834
+ * @since 1.0.0
835
+ * @category Models
836
+ */
837
+ export type UserMessagePart = TextPart | FilePart
838
+
839
+ /**
840
+ * Encoded representation of user messages for serialization.
841
+ *
842
+ * @since 1.0.0
843
+ * @category Models
844
+ */
845
+ export interface UserMessageEncoded extends BaseMessageEncoded<"user", UserMessageOptions> {
846
+ /**
847
+ * Array of content parts that make up the user's message.
848
+ */
849
+ readonly content: ReadonlyArray<UserMessagePartEncoded>
850
+ }
851
+
852
+ /**
853
+ * Union type of encoded content parts for user messages.
854
+ *
855
+ * @since 1.0.0
856
+ * @category Models
857
+ */
858
+ export type UserMessagePartEncoded = TextPartEncoded | FilePartEncoded
859
+
860
+ /**
861
+ * Represents provider-specific options that can be associated with a
862
+ * `UserMessage` through module augmentation.
863
+ *
864
+ * @since 1.0.0
865
+ * @category ProviderOptions
866
+ */
867
+ export interface UserMessageOptions extends ProviderOptions {}
868
+
869
+ /**
870
+ * Schema for validation and encoding of user messages.
871
+ *
872
+ * @since 1.0.0
873
+ * @category Schemas
874
+ */
875
+ export const UserMessage: Schema.Schema<UserMessage, UserMessageEncoded> = Schema.Struct({
876
+ role: Schema.Literal("user"),
877
+ content: Schema.Array(Schema.Union(TextPart, FilePart)),
878
+ options: Schema.optionalWith(ProviderOptions, { default: constEmptyObject })
879
+ }).pipe(
880
+ Schema.attachPropertySignature(MessageTypeId, MessageTypeId),
881
+ Schema.annotations({ identifier: "UserMessage" })
882
+ )
883
+
884
+ // =============================================================================
885
+ // Assistant Message
886
+ // =============================================================================
887
+
888
+ /**
889
+ * Message representing large language model assistant responses.
890
+ *
891
+ * @example
892
+ * ```ts
893
+ * import { Prompt } from "@effect/ai"
894
+ *
895
+ * const assistantMessage: Prompt.AssistantMessage = Prompt.makeMessage("assistant", {
896
+ * content: [
897
+ * Prompt.makePart("text", {
898
+ * text: "The user is asking about the weather. I should use the weather tool."
899
+ * }),
900
+ * Prompt.makePart("tool-call", {
901
+ * id: "call_123",
902
+ * name: "get_weather",
903
+ * params: { city: "San Francisco" },
904
+ * providerExecuted: false
905
+ * }),
906
+ * Prompt.makePart("tool-result", {
907
+ * id: "call_123",
908
+ * name: "get_weather",
909
+ * result: { temperature: 72, condition: "sunny" }
910
+ * }),
911
+ * Prompt.makePart("text", {
912
+ * text: "The weather in San Francisco is currently 72°F and sunny."
913
+ * })
914
+ * ]
915
+ * })
916
+ * ```
917
+ *
918
+ * @since 1.0.0
919
+ * @category Models
920
+ */
921
+ export interface AssistantMessage extends BaseMessage<"assistant", AssistantMessageOptions> {
922
+ /**
923
+ * Array of content parts that make up the assistant's response.
924
+ */
925
+ readonly content: ReadonlyArray<AssistantMessagePart>
926
+ }
927
+
928
+ /**
929
+ * Union type of content parts allowed in assistant messages.
930
+ *
931
+ * @since 1.0.0
932
+ * @category Models
933
+ */
934
+ export type AssistantMessagePart =
935
+ | TextPart
936
+ | FilePart
937
+ | ReasoningPart
938
+ | ToolCallPart
939
+ | ToolResultPart
940
+
941
+ /**
942
+ * Encoded representation of assistant messages for serialization.
943
+ *
944
+ * @since 1.0.0
945
+ * @category Models
946
+ */
947
+ export interface AssistantMessageEncoded extends BaseMessageEncoded<"assistant", AssistantMessageOptions> {
948
+ readonly content: ReadonlyArray<AssistantMessagePartEncoded>
949
+ }
950
+
951
+ /**
952
+ * Union type of encoded content parts for assistant messages.
953
+ *
954
+ * @since 1.0.0
955
+ * @category Models
956
+ */
957
+ export type AssistantMessagePartEncoded =
958
+ | TextPartEncoded
959
+ | FilePartEncoded
960
+ | ReasoningPartEncoded
961
+ | ToolCallPartEncoded
962
+ | ToolResultPartEncoded
963
+
964
+ /**
965
+ * Represents provider-specific options that can be associated with a
966
+ * `AssistantMessage` through module augmentation.
967
+ *
968
+ * @since 1.0.0
969
+ * @category ProviderOptions
970
+ */
971
+ export interface AssistantMessageOptions extends ProviderOptions {}
972
+
973
+ /**
974
+ * Schema for validation and encoding of assistant messages.
975
+ *
976
+ * @since 1.0.0
977
+ * @category Schemas
978
+ */
979
+ export const AssistantMessage: Schema.Schema<AssistantMessage, AssistantMessageEncoded> = Schema.Struct({
980
+ role: Schema.Literal("assistant"),
981
+ content: Schema.Array(Schema.Union(TextPart, FilePart, ReasoningPart, ToolCallPart, ToolResultPart)),
982
+ options: Schema.optionalWith(ProviderOptions, { default: constEmptyObject })
983
+ }).pipe(
984
+ Schema.attachPropertySignature(MessageTypeId, MessageTypeId),
985
+ Schema.annotations({ identifier: "AssistantMessage" })
986
+ )
987
+
988
+ // =============================================================================
989
+ // Tool Message
990
+ // =============================================================================
991
+
992
+ /**
993
+ * Message representing tool execution results.
994
+ *
995
+ * @example
996
+ * ```ts
997
+ * import { Prompt } from "@effect/ai"
998
+ *
999
+ * const toolMessage: Prompt.ToolMessage = Prompt.makeMessage("tool", {
1000
+ * content: [
1001
+ * Prompt.makePart("tool-result", {
1002
+ * id: "call_123",
1003
+ * name: "search_web",
1004
+ * result: {
1005
+ * query: "TypeScript best practices",
1006
+ * results: [
1007
+ * { title: "TypeScript Handbook", url: "https://..." },
1008
+ * { title: "Effective TypeScript", url: "https://..." }
1009
+ * ]
1010
+ * }
1011
+ * })
1012
+ * ]
1013
+ * })
1014
+ * ```
1015
+ *
1016
+ * @since 1.0.0
1017
+ * @category Models
1018
+ */
1019
+ export interface ToolMessage extends BaseMessage<"tool", ToolMessageOptions> {
1020
+ /**
1021
+ * Array of tool result parts.
1022
+ */
1023
+ readonly content: ReadonlyArray<ToolMessagePart>
1024
+ }
1025
+
1026
+ /**
1027
+ * Union type of content parts allowed in tool messages.
1028
+ *
1029
+ * @since 1.0.0
1030
+ * @category Models
1031
+ */
1032
+ export type ToolMessagePart = ToolResultPart
1033
+
1034
+ /**
1035
+ * Encoded representation of tool messages for serialization.
1036
+ *
1037
+ * @since 1.0.0
1038
+ * @category Models
1039
+ */
1040
+ export interface ToolMessageEncoded extends BaseMessageEncoded<"tool", ToolMessageOptions> {
1041
+ /**
1042
+ * Array of tool result parts.
1043
+ */
1044
+ readonly content: ReadonlyArray<ToolMessagePartEncoded>
1045
+ }
1046
+
1047
+ /**
1048
+ * Union type of encoded content parts for tool messages.
1049
+ *
1050
+ * @since 1.0.0
1051
+ * @category Models
1052
+ */
1053
+ export type ToolMessagePartEncoded = ToolResultPartEncoded
1054
+
1055
+ /**
1056
+ * Represents provider-specific options that can be associated with a
1057
+ * `ToolMessage` through module augmentation.
1058
+ *
1059
+ * @since 1.0.0
1060
+ * @category ProviderOptions
1061
+ */
1062
+ export interface ToolMessageOptions extends ProviderOptions {}
1063
+
1064
+ /**
1065
+ * Schema for validation and encoding of tool messages.
1066
+ *
1067
+ * @since 1.0.0
1068
+ * @category Schemas
1069
+ */
1070
+ export const ToolMessage: Schema.Schema<ToolMessage, ToolMessageEncoded> = Schema.Struct({
1071
+ role: Schema.Literal("tool"),
1072
+ content: Schema.Array(ToolResultPart),
1073
+ options: Schema.optionalWith(ProviderOptions, { default: constEmptyObject })
1074
+ }).pipe(
1075
+ Schema.attachPropertySignature(MessageTypeId, MessageTypeId),
1076
+ Schema.annotations({ identifier: "ToolMessage" })
1077
+ )
1078
+
1079
+ // =============================================================================
1080
+ // Message
1081
+ // =============================================================================
1082
+
1083
+ /**
1084
+ * A type representing all possible message types in a conversation.
1085
+ *
1086
+ * @since 1.0.0
1087
+ * @category Models
1088
+ */
1089
+ export type Message =
1090
+ | SystemMessage
1091
+ | UserMessage
1092
+ | AssistantMessage
1093
+ | ToolMessage
1094
+
1095
+ /**
1096
+ * A type representing all possible encoded message types for serialization.
1097
+ *
1098
+ * @since 1.0.0
1099
+ * @category Models
1100
+ */
1101
+ export type MessageEncoded =
1102
+ | SystemMessageEncoded
1103
+ | UserMessageEncoded
1104
+ | AssistantMessageEncoded
1105
+ | ToolMessageEncoded
1106
+
1107
+ /**
1108
+ * Schema for validation and encoding of messages.
1109
+ *
1110
+ * @since 1.0.0
1111
+ * @category Schemas
1112
+ */
1113
+ export const Message: Schema.Schema<Message, MessageEncoded> = Schema.Union(
1114
+ SystemMessage,
1115
+ UserMessage,
1116
+ AssistantMessage,
1117
+ ToolMessage
1118
+ )
1119
+
1120
+ // =============================================================================
1121
+ // Prompt
1122
+ // =============================================================================
1123
+
1124
+ /**
1125
+ * Unique identifier for Prompt instances.
1126
+ *
1127
+ * @since 1.0.0
1128
+ * @category Type Ids
1129
+ */
1130
+ export const TypeId = "~@effect/ai/Prompt"
1131
+
1132
+ /**
1133
+ * Type-level representation of the Prompt identifier.
1134
+ *
1135
+ * @since 1.0.0
1136
+ * @category Type Ids
1137
+ */
1138
+ export type TypeId = typeof TypeId
1139
+
1140
+ /**
1141
+ * Type guard to check if a value is a Prompt.
1142
+ *
1143
+ * @since 1.0.0
1144
+ * @category Guards
1145
+ */
1146
+ export const isPrompt = (u: unknown): u is Prompt => Predicate.hasProperty(u, TypeId)
1147
+
1148
+ /**
1149
+ * A Prompt contains a sequence of messages that form the context of a
1150
+ * conversation with a large language model.
1151
+ *
1152
+ * @since 1.0.0
1153
+ * @category Models
1154
+ */
1155
+ export interface Prompt {
1156
+ readonly [TypeId]: TypeId
1157
+ /**
1158
+ * Array of messages that make up the conversation.
1159
+ */
1160
+ readonly content: ReadonlyArray<Message>
1161
+ }
1162
+
1163
+ /**
1164
+ * Encoded representation of prompts for serialization.
1165
+ *
1166
+ * @since 1.0.0
1167
+ * @category Models
1168
+ */
1169
+ export interface PromptEncoded {
1170
+ /**
1171
+ * Array of messages that make up the conversation.
1172
+ */
1173
+ readonly content: ReadonlyArray<MessageEncoded>
1174
+ }
1175
+
1176
+ /**
1177
+ * Schema for validation and encoding of prompts.
1178
+ *
1179
+ * @since 1.0.0
1180
+ * @category Schemas
1181
+ */
1182
+ export const Prompt: Schema.Schema<Prompt, PromptEncoded> = Schema.Struct({
1183
+ content: Schema.Array(Message)
1184
+ }).pipe(
1185
+ Schema.attachPropertySignature(TypeId, TypeId),
1186
+ Schema.annotations({ identifier: "Prompt" })
1187
+ )
1188
+
1189
+ /**
1190
+ * Schema for parsing a Prompt from JSON strings.
1191
+ *
1192
+ * @since 1.0.0
1193
+ * @category Schemas
1194
+ */
1195
+ export const FromJson = Schema.parseJson(Prompt)
1196
+
1197
+ /**
1198
+ * Raw input types that can be converted into a Prompt.
1199
+ *
1200
+ * Supports various input formats for convenience, including simple strings,
1201
+ * message arrays, response parts, and existing prompts.
1202
+ *
1203
+ * @example
1204
+ * ```ts
1205
+ * import { Prompt } from "@effect/ai"
1206
+ *
1207
+ * // String input - creates a user message
1208
+ * const stringInput: Prompt.RawInput = "Hello, world!"
1209
+ *
1210
+ * // Message array input
1211
+ * const messagesInput: Prompt.RawInput = [
1212
+ * { role: "system", content: "You are helpful." },
1213
+ * { role: "user", content: [{ type: "text", text: "Hi!" }] }
1214
+ * ]
1215
+ *
1216
+ * // Existing prompt
1217
+ * declare const existingPrompt: Prompt.Prompt
1218
+ * const promptInput: Prompt.RawInput = existingPrompt
1219
+ * ```
1220
+ *
1221
+ * @since 1.0.0
1222
+ * @category Models
1223
+ */
1224
+ export type RawInput =
1225
+ | string
1226
+ | Iterable<MessageEncoded>
1227
+ | Prompt
1228
+
1229
+ const makePrompt = (content: ReadonlyArray<Message>): Prompt => ({
1230
+ [TypeId]: TypeId,
1231
+ content
1232
+ })
1233
+
1234
+ const decodeMessagesSync = Schema.decodeSync(Schema.Array(Message))
1235
+
1236
+ /**
1237
+ * An empty prompt with no messages.
1238
+ *
1239
+ * @example
1240
+ * ```ts
1241
+ * import { Prompt } from "@effect/ai"
1242
+ *
1243
+ * const emptyPrompt = Prompt.empty
1244
+ * console.log(emptyPrompt.content) // []
1245
+ * ```
1246
+ *
1247
+ * @since 1.0.0
1248
+ * @category Constructors
1249
+ */
1250
+ export const empty: Prompt = makePrompt([])
1251
+
1252
+ /**
1253
+ * Creates a Prompt from an input.
1254
+ *
1255
+ * This is the primary constructor for creating prompts, supporting multiple
1256
+ * input formats for convenience and flexibility.
1257
+ *
1258
+ * @example
1259
+ * ```ts
1260
+ * import { Prompt } from "@effect/ai"
1261
+ *
1262
+ * // From string - creates a user message
1263
+ * const textPrompt = Prompt.make("Hello, how are you?")
1264
+ *
1265
+ * // From messages array
1266
+ * const structuredPrompt = Prompt.make([
1267
+ * { role: "system", content: "You are a helpful assistant." },
1268
+ * { role: "user", content: [{ type: "text", text: "Hi!" }] }
1269
+ * ])
1270
+ *
1271
+ * // From existing prompt
1272
+ * declare const existingPrompt: Prompt.Prompt
1273
+ * const copiedPrompt = Prompt.make(existingPrompt)
1274
+ * ```
1275
+ *
1276
+ * @since 1.0.0
1277
+ * @category Constructors
1278
+ */
1279
+ export const make = (input: RawInput): Prompt => {
1280
+ if (Predicate.isString(input)) {
1281
+ const part = makePart("text", { text: input })
1282
+ const message = makeMessage("user", { content: [part] })
1283
+ return makePrompt([message])
1284
+ }
1285
+
1286
+ if (Predicate.isIterable(input)) {
1287
+ return makePrompt(decodeMessagesSync(Array.from(input), {
1288
+ errors: "all"
1289
+ }))
1290
+ }
1291
+
1292
+ return input
1293
+ }
1294
+
1295
+ /**
1296
+ * Creates a Prompt from an array of messages.
1297
+ *
1298
+ * @example
1299
+ * ```ts
1300
+ * import { Prompt } from "@effect/ai"
1301
+ *
1302
+ * const messages: ReadonlyArray<Prompt.Message> = [
1303
+ * Prompt.makeMessage("system", {
1304
+ * content: "You are a coding assistant."
1305
+ * }),
1306
+ * Prompt.makeMessage("user", {
1307
+ * content: [Prompt.makePart("text", { text: "Help me with TypeScript" })]
1308
+ * })
1309
+ * ]
1310
+ *
1311
+ * const prompt = Prompt.fromMessages(messages)
1312
+ * ```
1313
+ *
1314
+ * @since 1.0.0
1315
+ * @category Constructors
1316
+ */
1317
+ export const fromMessages = (messages: ReadonlyArray<Message>): Prompt => makePrompt(messages)
1318
+
1319
+ const VALID_RESPONSE_PART_MAP = {
1320
+ "response-metadata": false,
1321
+ "text": true,
1322
+ "text-start": false,
1323
+ "text-delta": true,
1324
+ "text-end": false,
1325
+ "reasoning": true,
1326
+ "reasoning-start": false,
1327
+ "reasoning-delta": true,
1328
+ "reasoning-end": false,
1329
+ "file": false,
1330
+ "source": false,
1331
+ "tool-params-start": false,
1332
+ "tool-params-delta": false,
1333
+ "tool-params-end": false,
1334
+ "tool-call": true,
1335
+ "tool-result": true,
1336
+ "finish": false,
1337
+ "error": false
1338
+ } as const satisfies Record<Response.AnyPart["type"], boolean>
1339
+
1340
+ type ValidResponseParts = typeof VALID_RESPONSE_PART_MAP
1341
+
1342
+ type ValidResponsePart = {
1343
+ [Type in keyof ValidResponseParts]: ValidResponseParts[Type] extends true ? Extract<Response.AnyPart, { type: Type }>
1344
+ : never
1345
+ }[keyof typeof VALID_RESPONSE_PART_MAP]
1346
+
1347
+ const isValidPart = (part: Response.AnyPart): part is ValidResponsePart => {
1348
+ return VALID_RESPONSE_PART_MAP[part.type]
1349
+ }
1350
+
1351
+ /**
1352
+ * Creates a Prompt from the response parts of a previous interaction with a
1353
+ * large language model.
1354
+ *
1355
+ * Converts streaming or non-streaming AI response parts into a structured
1356
+ * prompt, typically for use in conversation history or further processing.
1357
+ *
1358
+ * @example
1359
+ * ```ts
1360
+ * import { Prompt, Response } from "@effect/ai"
1361
+ *
1362
+ * const responseParts: ReadonlyArray<Response.AnyPart> = [
1363
+ * Response.makePart("text", {
1364
+ * text: "Hello there!"
1365
+ * }),
1366
+ * Response.makePart("tool-call", {
1367
+ * id: "call_1",
1368
+ * name: "get_time",
1369
+ * params: {},
1370
+ * providerExecuted: false
1371
+ * }),
1372
+ * Response.makePart("tool-result", {
1373
+ * id: "call_1",
1374
+ * name: "get_time",
1375
+ * result: "10:30 AM",
1376
+ * encodedResult: "10:30 AM",
1377
+ * providerExecuted: false
1378
+ * })
1379
+ * ]
1380
+ *
1381
+ * const prompt = Prompt.fromResponseParts(responseParts)
1382
+ * // Creates an assistant message with the response content
1383
+ * ```
1384
+ *
1385
+ * @since 1.0.0
1386
+ * @category Constructors
1387
+ */
1388
+ export const fromResponseParts = (parts: ReadonlyArray<Response.AnyPart>): Prompt => {
1389
+ if (parts.length === 0) {
1390
+ return empty
1391
+ }
1392
+
1393
+ const content: Array<AssistantMessagePart> = []
1394
+
1395
+ const textDeltas: Array<string> = []
1396
+ function flushTextDeltas() {
1397
+ if (textDeltas.length > 0) {
1398
+ const text = textDeltas.join("")
1399
+ if (text.length > 0) {
1400
+ content.push(makePart("text", { text }))
1401
+ }
1402
+ textDeltas.length = 0
1403
+ }
1404
+ }
1405
+
1406
+ const reasoningDeltas: Array<string> = []
1407
+ function flushReasoningDeltas() {
1408
+ if (reasoningDeltas.length > 0) {
1409
+ const text = reasoningDeltas.join("")
1410
+ if (text.length > 0) {
1411
+ content.push(makePart("reasoning", { text }))
1412
+ }
1413
+ reasoningDeltas.length = 0
1414
+ }
1415
+ }
1416
+
1417
+ function flushDeltas() {
1418
+ flushTextDeltas()
1419
+ flushReasoningDeltas()
1420
+ }
1421
+
1422
+ for (const part of parts) {
1423
+ if (isValidPart(part)) {
1424
+ switch (part.type) {
1425
+ case "text": {
1426
+ flushDeltas()
1427
+ content.push(makePart("text", { text: part.text }))
1428
+ break
1429
+ }
1430
+ case "text-delta": {
1431
+ flushReasoningDeltas()
1432
+ textDeltas.push(part.delta)
1433
+ break
1434
+ }
1435
+ case "reasoning": {
1436
+ flushDeltas()
1437
+ content.push(makePart("reasoning", { text: part.text }))
1438
+ break
1439
+ }
1440
+ case "reasoning-delta": {
1441
+ flushTextDeltas()
1442
+ reasoningDeltas.push(part.delta)
1443
+ break
1444
+ }
1445
+ case "tool-call": {
1446
+ flushDeltas()
1447
+ content.push(makePart("tool-call", {
1448
+ id: part.id,
1449
+ name: part.providerName ?? part.name,
1450
+ params: part.params,
1451
+ providerExecuted: part.providerExecuted ?? false
1452
+ }))
1453
+ break
1454
+ }
1455
+ case "tool-result": {
1456
+ flushDeltas()
1457
+ content.push(makePart("tool-result", {
1458
+ id: part.id,
1459
+ name: part.providerName ?? part.name,
1460
+ result: part.encodedResult
1461
+ }))
1462
+ break
1463
+ }
1464
+ }
1465
+ }
1466
+ }
1467
+
1468
+ flushDeltas()
1469
+
1470
+ const message = makeMessage("assistant", { content })
1471
+
1472
+ return makePrompt([message])
1473
+ }
1474
+
1475
+ // =============================================================================
1476
+ // Merging Prompts
1477
+ // =============================================================================
1478
+
1479
+ /**
1480
+ * Merges two prompts by concatenating their messages.
1481
+ *
1482
+ * Creates a new prompt containing all messages from both prompts, maintaining
1483
+ * the order of messages within each prompt.
1484
+ *
1485
+ * @example
1486
+ * ```ts
1487
+ * import { Prompt } from "@effect/ai"
1488
+ *
1489
+ * const systemPrompt = Prompt.make([{
1490
+ * role: "system",
1491
+ * content: "You are a helpful assistant."
1492
+ * }])
1493
+ *
1494
+ * const userPrompt = Prompt.make("Hello, world!")
1495
+ *
1496
+ * const merged = Prompt.merge(systemPrompt, userPrompt)
1497
+ * ```
1498
+ *
1499
+ * @since 1.0.0
1500
+ * @category Combinators
1501
+ */
1502
+ export const merge: {
1503
+ // =============================================================================
1504
+ // Merging Prompts
1505
+ // =============================================================================
1506
+
1507
+ /**
1508
+ * Merges two prompts by concatenating their messages.
1509
+ *
1510
+ * Creates a new prompt containing all messages from both prompts, maintaining
1511
+ * the order of messages within each prompt.
1512
+ *
1513
+ * @example
1514
+ * ```ts
1515
+ * import { Prompt } from "@effect/ai"
1516
+ *
1517
+ * const systemPrompt = Prompt.make([{
1518
+ * role: "system",
1519
+ * content: "You are a helpful assistant."
1520
+ * }])
1521
+ *
1522
+ * const userPrompt = Prompt.make("Hello, world!")
1523
+ *
1524
+ * const merged = Prompt.merge(systemPrompt, userPrompt)
1525
+ * ```
1526
+ *
1527
+ * @since 1.0.0
1528
+ * @category Combinators
1529
+ */
1530
+ (other: Prompt): (self: Prompt) => Prompt
1531
+ // =============================================================================
1532
+ // Merging Prompts
1533
+ // =============================================================================
1534
+
1535
+ /**
1536
+ * Merges two prompts by concatenating their messages.
1537
+ *
1538
+ * Creates a new prompt containing all messages from both prompts, maintaining
1539
+ * the order of messages within each prompt.
1540
+ *
1541
+ * @example
1542
+ * ```ts
1543
+ * import { Prompt } from "@effect/ai"
1544
+ *
1545
+ * const systemPrompt = Prompt.make([{
1546
+ * role: "system",
1547
+ * content: "You are a helpful assistant."
1548
+ * }])
1549
+ *
1550
+ * const userPrompt = Prompt.make("Hello, world!")
1551
+ *
1552
+ * const merged = Prompt.merge(systemPrompt, userPrompt)
1553
+ * ```
1554
+ *
1555
+ * @since 1.0.0
1556
+ * @category Combinators
1557
+ */
1558
+ (self: Prompt, other: Prompt): Prompt
1559
+ } = dual<
1560
+ // =============================================================================
1561
+ // Merging Prompts
1562
+ // =============================================================================
1563
+
1564
+ /**
1565
+ * Merges two prompts by concatenating their messages.
1566
+ *
1567
+ * Creates a new prompt containing all messages from both prompts, maintaining
1568
+ * the order of messages within each prompt.
1569
+ *
1570
+ * @example
1571
+ * ```ts
1572
+ * import { Prompt } from "@effect/ai"
1573
+ *
1574
+ * const systemPrompt = Prompt.make([{
1575
+ * role: "system",
1576
+ * content: "You are a helpful assistant."
1577
+ * }])
1578
+ *
1579
+ * const userPrompt = Prompt.make("Hello, world!")
1580
+ *
1581
+ * const merged = Prompt.merge(systemPrompt, userPrompt)
1582
+ * ```
1583
+ *
1584
+ * @since 1.0.0
1585
+ * @category Combinators
1586
+ */
1587
+ (other: Prompt) => (self: Prompt) => Prompt,
1588
+ // =============================================================================
1589
+ // Merging Prompts
1590
+ // =============================================================================
1591
+
1592
+ /**
1593
+ * Merges two prompts by concatenating their messages.
1594
+ *
1595
+ * Creates a new prompt containing all messages from both prompts, maintaining
1596
+ * the order of messages within each prompt.
1597
+ *
1598
+ * @example
1599
+ * ```ts
1600
+ * import { Prompt } from "@effect/ai"
1601
+ *
1602
+ * const systemPrompt = Prompt.make([{
1603
+ * role: "system",
1604
+ * content: "You are a helpful assistant."
1605
+ * }])
1606
+ *
1607
+ * const userPrompt = Prompt.make("Hello, world!")
1608
+ *
1609
+ * const merged = Prompt.merge(systemPrompt, userPrompt)
1610
+ * ```
1611
+ *
1612
+ * @since 1.0.0
1613
+ * @category Combinators
1614
+ */
1615
+ (self: Prompt, other: Prompt) => Prompt
1616
+ >(2, (self, other) => fromMessages([...self.content, ...other.content]))