@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
@@ -0,0 +1,655 @@
1
+ /**
2
+ * The `Telemetry` module provides OpenTelemetry integration for operations
3
+ * performed against a large language model provider by defining telemetry
4
+ * attributes and utilities that follow the OpenTelemetry GenAI semantic
5
+ * conventions.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { Telemetry } from "@effect/ai"
10
+ * import { Effect } from "effect"
11
+ *
12
+ * // Add telemetry attributes to a span
13
+ * const addTelemetry = Effect.gen(function* () {
14
+ * const span = yield* Effect.currentSpan
15
+ *
16
+ * Telemetry.addGenAIAnnotations(span, {
17
+ * system: "openai",
18
+ * operation: { name: "chat" },
19
+ * request: {
20
+ * model: "gpt-4",
21
+ * temperature: 0.7,
22
+ * maxTokens: 1000
23
+ * },
24
+ * usage: {
25
+ * inputTokens: 100,
26
+ * outputTokens: 50
27
+ * }
28
+ * })
29
+ * })
30
+ * ```
31
+ *
32
+ * @since 1.0.0
33
+ */
34
+ import * as Context from "effect/Context"
35
+ import { dual } from "effect/Function"
36
+ import * as Predicate from "effect/Predicate"
37
+ import * as String from "effect/String"
38
+ import type { Span } from "effect/Tracer"
39
+ import type { Simplify } from "effect/Types"
40
+ import type { ProviderOptions } from "./LanguageModel.js"
41
+ import type * as Response from "./Response.js"
42
+
43
+ /**
44
+ * The attributes used to describe telemetry in the context of Generative
45
+ * Artificial Intelligence (GenAI) Models requests and responses.
46
+ *
47
+ * {@see https://opentelemetry.io/docs/specs/semconv/attributes-registry/gen-ai/}
48
+ *
49
+ * @since 1.0.0
50
+ * @category Models
51
+ */
52
+ export type GenAITelemetryAttributes = Simplify<
53
+ & AttributesWithPrefix<BaseAttributes, "gen_ai">
54
+ & AttributesWithPrefix<OperationAttributes, "gen_ai.operation">
55
+ & AttributesWithPrefix<TokenAttributes, "gen_ai.token">
56
+ & AttributesWithPrefix<UsageAttributes, "gen_ai.usage">
57
+ & AttributesWithPrefix<RequestAttributes, "gen_ai.request">
58
+ & AttributesWithPrefix<ResponseAttributes, "gen_ai.response">
59
+ >
60
+
61
+ /**
62
+ * All telemetry attributes which are part of the GenAI specification.
63
+ *
64
+ * @since 1.0.0
65
+ * @category Models
66
+ */
67
+ export type AllAttributes =
68
+ & BaseAttributes
69
+ & OperationAttributes
70
+ & TokenAttributes
71
+ & UsageAttributes
72
+ & RequestAttributes
73
+ & ResponseAttributes
74
+
75
+ /**
76
+ * Telemetry attributes which are part of the GenAI specification and are
77
+ * namespaced by `gen_ai`.
78
+ *
79
+ * @since 1.0.0
80
+ * @category Models
81
+ */
82
+ export interface BaseAttributes {
83
+ /**
84
+ * The Generative AI product as identified by the client or server
85
+ * instrumentation.
86
+ */
87
+ readonly system?: (string & {}) | WellKnownSystem | null | undefined
88
+ }
89
+
90
+ /**
91
+ * Telemetry attributes which are part of the GenAI specification and are
92
+ * namespaced by `gen_ai.operation`.
93
+ *
94
+ * @since 1.0.0
95
+ * @category Models
96
+ */
97
+ export interface OperationAttributes {
98
+ readonly name?: (string & {}) | WellKnownOperationName | null | undefined
99
+ }
100
+
101
+ /**
102
+ * Telemetry attributes which are part of the GenAI specification and are
103
+ * namespaced by `gen_ai.token`.
104
+ *
105
+ * @since 1.0.0
106
+ * @category Models
107
+ */
108
+ export interface TokenAttributes {
109
+ readonly type?: string | null | undefined
110
+ }
111
+
112
+ /**
113
+ * Telemetry attributes which are part of the GenAI specification and are
114
+ * namespaced by `gen_ai.usage`.
115
+ *
116
+ * @since 1.0.0
117
+ * @category Models
118
+ */
119
+ export interface UsageAttributes {
120
+ readonly inputTokens?: number | null | undefined
121
+ readonly outputTokens?: number | null | undefined
122
+ }
123
+
124
+ /**
125
+ * Telemetry attributes which are part of the GenAI specification and are
126
+ * namespaced by `gen_ai.request`.
127
+ *
128
+ * @since 1.0.0
129
+ * @category Models
130
+ */
131
+ export interface RequestAttributes {
132
+ /**
133
+ * The name of the GenAI model a request is being made to.
134
+ */
135
+ readonly model?: string | null | undefined
136
+ /**
137
+ * The temperature setting for the GenAI request.
138
+ */
139
+ readonly temperature?: number | null | undefined
140
+ /**
141
+ * The temperature setting for the GenAI request.
142
+ */
143
+ readonly topK?: number | null | undefined
144
+ /**
145
+ * The top_k sampling setting for the GenAI request.
146
+ */
147
+ readonly topP?: number | null | undefined
148
+ /**
149
+ * The top_p sampling setting for the GenAI request.
150
+ */
151
+ readonly maxTokens?: number | null | undefined
152
+ /**
153
+ * The encoding formats requested in an embeddings operation, if specified.
154
+ */
155
+ readonly encodingFormats?: ReadonlyArray<string> | null | undefined
156
+ /**
157
+ * List of sequences that the model will use to stop generating further
158
+ * tokens.
159
+ */
160
+ readonly stopSequences?: ReadonlyArray<string> | null | undefined
161
+ /**
162
+ * The frequency penalty setting for the GenAI request.
163
+ */
164
+ readonly frequencyPenalty?: number | null | undefined
165
+ /**
166
+ * The presence penalty setting for the GenAI request.
167
+ */
168
+ readonly presencePenalty?: number | null | undefined
169
+ /**
170
+ * The seed setting for the GenAI request. Requests with same seed value
171
+ * are more likely to return same result.
172
+ */
173
+ readonly seed?: number | null | undefined
174
+ }
175
+
176
+ /**
177
+ * Telemetry attributes which are part of the GenAI specification and are
178
+ * namespaced by `gen_ai.response`.
179
+ *
180
+ * @since 1.0.0
181
+ * @category Models
182
+ */
183
+ export interface ResponseAttributes {
184
+ /**
185
+ * The unique identifier for the completion.
186
+ */
187
+ readonly id?: string | null | undefined
188
+ /**
189
+ * The name of the model that generated the response.
190
+ */
191
+ readonly model?: string | null | undefined
192
+ /**
193
+ * Array of reasons the model stopped generating tokens, corresponding to
194
+ * each generation received.
195
+ */
196
+ readonly finishReasons?: ReadonlyArray<string> | null | undefined
197
+ }
198
+
199
+ /**
200
+ * The `gen_ai.operation.name` attribute has the following list of well-known
201
+ * values.
202
+ *
203
+ * If one of them applies, then the respective value **MUST** be used;
204
+ * otherwise, a custom value **MAY** be used.
205
+ *
206
+ * @since 1.0.0
207
+ * @category Models
208
+ */
209
+ export type WellKnownOperationName = "chat" | "embeddings" | "text_completion"
210
+
211
+ /**
212
+ * The `gen_ai.system` attribute has the following list of well-known values.
213
+ *
214
+ * If one of them applies, then the respective value **MUST** be used;
215
+ * otherwise, a custom value **MAY** be used.
216
+ *
217
+ * @since 1.0.0
218
+ * @category Models
219
+ */
220
+ export type WellKnownSystem =
221
+ | "anthropic"
222
+ | "aws.bedrock"
223
+ | "az.ai.inference"
224
+ | "az.ai.openai"
225
+ | "cohere"
226
+ | "deepseek"
227
+ | "gemini"
228
+ | "groq"
229
+ | "ibm.watsonx.ai"
230
+ | "mistral_ai"
231
+ | "openai"
232
+ | "perplexity"
233
+ | "vertex_ai"
234
+ | "xai"
235
+
236
+ /**
237
+ * Utility type for prefixing attribute names with a namespace.
238
+ *
239
+ * Transforms attribute keys by adding a prefix and formatting them according to
240
+ * OpenTelemetry conventions (camelCase to snake_case).
241
+ *
242
+ * @template Attributes - Record type containing the attributes to prefix
243
+ * @template Prefix - String literal type for the prefix to add
244
+ *
245
+ * @example
246
+ * ```ts
247
+ * import { Telemetry } from "@effect/ai"
248
+ *
249
+ * type RequestAttrs = {
250
+ * modelName: string
251
+ * maxTokens: number
252
+ * }
253
+ *
254
+ * type PrefixedAttrs = Telemetry.AttributesWithPrefix<RequestAttrs, "gen_ai.request">
255
+ * // Results in: {
256
+ * // "gen_ai.request.model_name": string
257
+ * // "gen_ai.request.max_tokens": number
258
+ * // }
259
+ * ```
260
+ *
261
+ * @since 1.0.0
262
+ * @category Utility Types
263
+ */
264
+ export type AttributesWithPrefix<Attributes extends Record<string, any>, Prefix extends string> = {
265
+ [Name in keyof Attributes as `${Prefix}.${FormatAttributeName<Name>}`]: Attributes[Name]
266
+ }
267
+
268
+ /**
269
+ * Utility type for converting camelCase names to snake_case format.
270
+ *
271
+ * This type recursively transforms string literal types from camelCase to
272
+ * snake_case, which is the standard format for OpenTelemetry attributes.
273
+ *
274
+ * @template T - String literal type to format
275
+ *
276
+ * @example
277
+ * ```ts
278
+ * import { Telemetry } from "@effect/ai"
279
+ *
280
+ * type Formatted1 = Telemetry.FormatAttributeName<"modelName"> // "model_name"
281
+ * type Formatted2 = Telemetry.FormatAttributeName<"maxTokens"> // "max_tokens"
282
+ * type Formatted3 = Telemetry.FormatAttributeName<"temperature"> // "temperature"
283
+ * ```
284
+ *
285
+ * @since 1.0.0
286
+ * @category Utility Types
287
+ */
288
+ export type FormatAttributeName<T extends string | number | symbol> = T extends string ?
289
+ T extends `${infer First}${infer Rest}`
290
+ ? `${First extends Uppercase<First> ? "_" : ""}${Lowercase<First>}${FormatAttributeName<Rest>}`
291
+ : T :
292
+ never
293
+
294
+ /**
295
+ * Creates a function to add attributes to a span with a given prefix and key transformation.
296
+ *
297
+ * This utility function is used internally to create specialized functions for adding
298
+ * different types of telemetry attributes to OpenTelemetry spans.
299
+ *
300
+ * @example
301
+ * ```ts
302
+ * import { Telemetry } from "@effect/ai"
303
+ * import { String, Tracer } from "effect"
304
+ *
305
+ * const addCustomAttributes = Telemetry.addSpanAttributes(
306
+ * "custom.ai",
307
+ * String.camelToSnake
308
+ * )
309
+ *
310
+ * // Usage with a span
311
+ * declare const span: Tracer.Span
312
+ * addCustomAttributes(span, {
313
+ * modelName: "gpt-4",
314
+ * maxTokens: 1000
315
+ * })
316
+ * // Results in attributes: "custom.ai.model_name" and "custom.ai.max_tokens"
317
+ * ```
318
+ *
319
+ * @since 1.0.0
320
+ * @category Utilities
321
+ */
322
+ export const addSpanAttributes = (
323
+ /**
324
+ * The prefix to add to all attribute keys.
325
+ */
326
+ keyPrefix: string,
327
+ /**
328
+ * Function to transform attribute keys (e.g., camelCase to snake_case).
329
+ */
330
+ transformKey: (key: string) => string
331
+ ) =>
332
+ <Attributes extends Record<string, any>>(
333
+ /**
334
+ * The OpenTelemetry span to add attributes to.
335
+ */
336
+ span: Span,
337
+ /**
338
+ * The attributes to add to the span.
339
+ */
340
+ attributes: Attributes
341
+ ): void => {
342
+ for (const [key, value] of Object.entries(attributes)) {
343
+ if (Predicate.isNotNullable(value)) {
344
+ span.attribute(`${keyPrefix}.${transformKey(key)}`, value)
345
+ }
346
+ }
347
+ }
348
+
349
+ const addSpanBaseAttributes = addSpanAttributes("gen_ai", String.camelToSnake)<BaseAttributes>
350
+ const addSpanOperationAttributes = addSpanAttributes("gen_ai.operation", String.camelToSnake)<OperationAttributes>
351
+ const addSpanRequestAttributes = addSpanAttributes("gen_ai.request", String.camelToSnake)<RequestAttributes>
352
+ const addSpanResponseAttributes = addSpanAttributes("gen_ai.response", String.camelToSnake)<ResponseAttributes>
353
+ const addSpanTokenAttributes = addSpanAttributes("gen_ai.token", String.camelToSnake)<TokenAttributes>
354
+ const addSpanUsageAttributes = addSpanAttributes("gen_ai.usage", String.camelToSnake)<UsageAttributes>
355
+
356
+ /**
357
+ * Configuration options for GenAI telemetry attributes.
358
+ *
359
+ * Combines base attributes with optional grouped attributes for comprehensive
360
+ * telemetry coverage of AI operations.
361
+ *
362
+ * @example
363
+ * ```ts
364
+ * import { Telemetry } from "@effect/ai"
365
+ *
366
+ * const telemetryOptions: Telemetry.GenAITelemetryAttributeOptions = {
367
+ * system: "openai",
368
+ * operation: {
369
+ * name: "chat"
370
+ * },
371
+ * request: {
372
+ * model: "gpt-4-turbo",
373
+ * temperature: 0.7,
374
+ * maxTokens: 2000
375
+ * },
376
+ * response: {
377
+ * id: "chatcmpl-123",
378
+ * model: "gpt-4-turbo-2024-04-09",
379
+ * finishReasons: ["stop"]
380
+ * },
381
+ * usage: {
382
+ * inputTokens: 50,
383
+ * outputTokens: 25
384
+ * }
385
+ * }
386
+ * ```
387
+ *
388
+ * @since 1.0.0
389
+ * @category Models
390
+ */
391
+ export type GenAITelemetryAttributeOptions = BaseAttributes & {
392
+ /**
393
+ * Operation-specific attributes (e.g., operation name).
394
+ */
395
+ readonly operation?: OperationAttributes | undefined
396
+ /**
397
+ * Request-specific attributes (e.g., model parameters).
398
+ */
399
+ readonly request?: RequestAttributes | undefined
400
+ /**
401
+ * Response-specific attributes (e.g., response metadata).
402
+ */
403
+ readonly response?: ResponseAttributes | undefined
404
+ /**
405
+ * Token-specific attributes.
406
+ */
407
+ readonly token?: TokenAttributes | undefined
408
+ /**
409
+ * Usage statistics attributes (e.g., token counts).
410
+ */
411
+ readonly usage?: UsageAttributes | undefined
412
+ }
413
+
414
+ /**
415
+ * Applies GenAI telemetry attributes to an OpenTelemetry span.
416
+ *
417
+ * This function adds standardized GenAI attributes to a span following OpenTelemetry
418
+ * semantic conventions. It supports both curried and direct application patterns.
419
+ *
420
+ * **Note**: This function mutates the provided span in-place.
421
+ *
422
+ * @example
423
+ * ```ts
424
+ * import { Telemetry } from "@effect/ai"
425
+ * import { Effect } from "effect"
426
+ *
427
+ * const directUsage = Effect.gen(function* () {
428
+ * const span = yield* Effect.currentSpan
429
+ *
430
+ * Telemetry.addGenAIAnnotations(span, {
431
+ * system: "openai",
432
+ * request: { model: "gpt-4", temperature: 0.7 },
433
+ * usage: { inputTokens: 100, outputTokens: 50 }
434
+ * })
435
+ * })
436
+ * ```
437
+ *
438
+ * @since 1.0.0
439
+ * @category Utilities
440
+ */
441
+ export const addGenAIAnnotations: {
442
+ /**
443
+ * Applies GenAI telemetry attributes to an OpenTelemetry span.
444
+ *
445
+ * This function adds standardized GenAI attributes to a span following OpenTelemetry
446
+ * semantic conventions. It supports both curried and direct application patterns.
447
+ *
448
+ * **Note**: This function mutates the provided span in-place.
449
+ *
450
+ * @example
451
+ * ```ts
452
+ * import { Telemetry } from "@effect/ai"
453
+ * import { Effect } from "effect"
454
+ *
455
+ * const directUsage = Effect.gen(function* () {
456
+ * const span = yield* Effect.currentSpan
457
+ *
458
+ * Telemetry.addGenAIAnnotations(span, {
459
+ * system: "openai",
460
+ * request: { model: "gpt-4", temperature: 0.7 },
461
+ * usage: { inputTokens: 100, outputTokens: 50 }
462
+ * })
463
+ * })
464
+ * ```
465
+ *
466
+ * @since 1.0.0
467
+ * @category Utilities
468
+ */
469
+ (
470
+ /**
471
+ * Telemetry attribute options to apply to the span.
472
+ */
473
+ options: GenAITelemetryAttributeOptions
474
+ ): (
475
+ /**
476
+ * OpenTelemetry span to add attributes to.
477
+ */
478
+ span: Span
479
+ ) => void
480
+ /**
481
+ * Applies GenAI telemetry attributes to an OpenTelemetry span.
482
+ *
483
+ * This function adds standardized GenAI attributes to a span following OpenTelemetry
484
+ * semantic conventions. It supports both curried and direct application patterns.
485
+ *
486
+ * **Note**: This function mutates the provided span in-place.
487
+ *
488
+ * @example
489
+ * ```ts
490
+ * import { Telemetry } from "@effect/ai"
491
+ * import { Effect } from "effect"
492
+ *
493
+ * const directUsage = Effect.gen(function* () {
494
+ * const span = yield* Effect.currentSpan
495
+ *
496
+ * Telemetry.addGenAIAnnotations(span, {
497
+ * system: "openai",
498
+ * request: { model: "gpt-4", temperature: 0.7 },
499
+ * usage: { inputTokens: 100, outputTokens: 50 }
500
+ * })
501
+ * })
502
+ * ```
503
+ *
504
+ * @since 1.0.0
505
+ * @category Utilities
506
+ */
507
+ (
508
+ /**
509
+ * OpenTelemetry span to add attributes to.
510
+ */
511
+ span: Span,
512
+ /**
513
+ * Telemetry attribute options to apply to the span.
514
+ */
515
+ options: GenAITelemetryAttributeOptions
516
+ ): void
517
+ } = dual<
518
+ /**
519
+ * Applies GenAI telemetry attributes to an OpenTelemetry span.
520
+ *
521
+ * This function adds standardized GenAI attributes to a span following OpenTelemetry
522
+ * semantic conventions. It supports both curried and direct application patterns.
523
+ *
524
+ * **Note**: This function mutates the provided span in-place.
525
+ *
526
+ * @example
527
+ * ```ts
528
+ * import { Telemetry } from "@effect/ai"
529
+ * import { Effect } from "effect"
530
+ *
531
+ * const directUsage = Effect.gen(function* () {
532
+ * const span = yield* Effect.currentSpan
533
+ *
534
+ * Telemetry.addGenAIAnnotations(span, {
535
+ * system: "openai",
536
+ * request: { model: "gpt-4", temperature: 0.7 },
537
+ * usage: { inputTokens: 100, outputTokens: 50 }
538
+ * })
539
+ * })
540
+ * ```
541
+ *
542
+ * @since 1.0.0
543
+ * @category Utilities
544
+ */
545
+ (options: GenAITelemetryAttributeOptions) => (span: Span) => void,
546
+ /**
547
+ * Applies GenAI telemetry attributes to an OpenTelemetry span.
548
+ *
549
+ * This function adds standardized GenAI attributes to a span following OpenTelemetry
550
+ * semantic conventions. It supports both curried and direct application patterns.
551
+ *
552
+ * **Note**: This function mutates the provided span in-place.
553
+ *
554
+ * @example
555
+ * ```ts
556
+ * import { Telemetry } from "@effect/ai"
557
+ * import { Effect } from "effect"
558
+ *
559
+ * const directUsage = Effect.gen(function* () {
560
+ * const span = yield* Effect.currentSpan
561
+ *
562
+ * Telemetry.addGenAIAnnotations(span, {
563
+ * system: "openai",
564
+ * request: { model: "gpt-4", temperature: 0.7 },
565
+ * usage: { inputTokens: 100, outputTokens: 50 }
566
+ * })
567
+ * })
568
+ * ```
569
+ *
570
+ * @since 1.0.0
571
+ * @category Utilities
572
+ */
573
+ (span: Span, options: GenAITelemetryAttributeOptions) => void
574
+ >(2, (span, options) => {
575
+ addSpanBaseAttributes(span, { system: options.system })
576
+ if (Predicate.isNotNullable(options.operation)) addSpanOperationAttributes(span, options.operation)
577
+ if (Predicate.isNotNullable(options.request)) addSpanRequestAttributes(span, options.request)
578
+ if (Predicate.isNotNullable(options.response)) addSpanResponseAttributes(span, options.response)
579
+ if (Predicate.isNotNullable(options.token)) addSpanTokenAttributes(span, options.token)
580
+ if (Predicate.isNotNullable(options.usage)) addSpanUsageAttributes(span, options.usage)
581
+ })
582
+
583
+ /**
584
+ * A function that can transform OpenTelemetry spans based on AI operation data.
585
+ *
586
+ * Span transformers receive the complete request/response context from AI operations
587
+ * and can add custom telemetry attributes, metrics, or other observability data.
588
+ *
589
+ * @example
590
+ * ```ts
591
+ * import { Telemetry } from "@effect/ai"
592
+ *
593
+ * const customTransformer: Telemetry.SpanTransformer = (options) => {
594
+ * // Add custom attributes based on the response
595
+ * const textParts = options.response.filter(part => part.type === "text")
596
+ * const totalTextLength = textParts.reduce((sum, part) =>
597
+ * sum + (part.type === "text" ? part.text.length : 0), 0
598
+ * )
599
+ *
600
+ * // Add custom metrics
601
+ * console.log(`Generated ${totalTextLength} characters of text`)
602
+ * }
603
+ * ```
604
+ *
605
+ * @since 1.0.0
606
+ * @category Models
607
+ */
608
+ export interface SpanTransformer {
609
+ (
610
+ options: ProviderOptions & {
611
+ /**
612
+ * Array of response parts generated by the AI model.
613
+ */
614
+ readonly response: ReadonlyArray<Response.AllParts<any>>
615
+ }
616
+ ): void
617
+ }
618
+
619
+ /**
620
+ * Context tag for providing a span transformer to large langauge model
621
+ * operations.
622
+ *
623
+ * The CurrentSpanTransformer allows you to inject custom span transformation
624
+ * logic into AI operations, enabling application-specific telemetry and
625
+ * observability patterns.
626
+ *
627
+ * @example
628
+ * ```ts
629
+ * import { Telemetry } from "@effect/ai"
630
+ * import { Context, Effect } from "effect"
631
+ *
632
+ * // Create a custom span transformer
633
+ * const loggingTransformer: Telemetry.SpanTransformer = (options) => {
634
+ * console.log(`AI request completed: ${options.model}`)
635
+ * options.response.forEach((part, index) => {
636
+ * console.log(`Part ${index}: ${part.type}`)
637
+ * })
638
+ * }
639
+ *
640
+ * // Provide the transformer to your AI operations
641
+ * const program = myAIOperation.pipe(
642
+ * Effect.provideService(
643
+ * Telemetry.CurrentSpanTransformer,
644
+ * Telemetry.CurrentSpanTransformer.of(loggingTransformer)
645
+ * )
646
+ * )
647
+ * ```
648
+ *
649
+ * @since 1.0.0
650
+ * @category Context
651
+ */
652
+ export class CurrentSpanTransformer extends Context.Tag("@effect/ai/Telemetry/CurrentSpanTransformer")<
653
+ CurrentSpanTransformer,
654
+ SpanTransformer
655
+ >() {}