@effect/ai-openai 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/OpenAiEmbeddingModel/package.json +6 -0
- package/OpenAiLanguageModel/package.json +6 -0
- package/dist/cjs/OpenAiClient.js +111 -109
- package/dist/cjs/OpenAiClient.js.map +1 -1
- package/dist/cjs/OpenAiConfig.js +2 -2
- package/dist/cjs/OpenAiConfig.js.map +1 -1
- package/dist/cjs/{OpenAiEmbeddings.js → OpenAiEmbeddingModel.js} +22 -51
- package/dist/cjs/OpenAiEmbeddingModel.js.map +1 -0
- package/dist/cjs/OpenAiLanguageModel.js +490 -0
- package/dist/cjs/OpenAiLanguageModel.js.map +1 -0
- package/dist/cjs/OpenAiTelemetry.js +1 -1
- package/dist/cjs/OpenAiTelemetry.js.map +1 -1
- package/dist/cjs/OpenAiTokenizer.js +11 -13
- package/dist/cjs/OpenAiTokenizer.js.map +1 -1
- package/dist/cjs/index.js +5 -5
- package/dist/cjs/internal/utilities.js +25 -0
- package/dist/cjs/internal/utilities.js.map +1 -0
- package/dist/dts/OpenAiClient.d.ts +32 -75
- package/dist/dts/OpenAiClient.d.ts.map +1 -1
- package/dist/dts/OpenAiConfig.d.ts +5 -6
- package/dist/dts/OpenAiConfig.d.ts.map +1 -1
- package/dist/dts/{OpenAiEmbeddings.d.ts → OpenAiEmbeddingModel.d.ts} +16 -37
- package/dist/dts/OpenAiEmbeddingModel.d.ts.map +1 -0
- package/dist/dts/OpenAiLanguageModel.d.ts +108 -0
- package/dist/dts/OpenAiLanguageModel.d.ts.map +1 -0
- package/dist/dts/OpenAiTelemetry.d.ts +59 -64
- package/dist/dts/OpenAiTelemetry.d.ts.map +1 -1
- package/dist/dts/OpenAiTokenizer.d.ts +2 -2
- package/dist/dts/OpenAiTokenizer.d.ts.map +1 -1
- package/dist/dts/index.d.ts +3 -3
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/internal/utilities.d.ts +2 -0
- package/dist/dts/internal/utilities.d.ts.map +1 -0
- package/dist/esm/OpenAiClient.js +110 -106
- package/dist/esm/OpenAiClient.js.map +1 -1
- package/dist/esm/OpenAiConfig.js +2 -2
- package/dist/esm/OpenAiConfig.js.map +1 -1
- package/dist/esm/{OpenAiEmbeddings.js → OpenAiEmbeddingModel.js} +21 -48
- package/dist/esm/OpenAiEmbeddingModel.js.map +1 -0
- package/dist/esm/OpenAiLanguageModel.js +478 -0
- package/dist/esm/OpenAiLanguageModel.js.map +1 -0
- package/dist/esm/OpenAiTelemetry.js +1 -1
- package/dist/esm/OpenAiTelemetry.js.map +1 -1
- package/dist/esm/OpenAiTokenizer.js +11 -13
- package/dist/esm/OpenAiTokenizer.js.map +1 -1
- package/dist/esm/index.js +3 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/utilities.js +16 -0
- package/dist/esm/internal/utilities.js.map +1 -0
- package/package.json +19 -19
- package/src/OpenAiClient.ts +184 -191
- package/src/OpenAiConfig.ts +7 -8
- package/src/{OpenAiEmbeddings.ts → OpenAiEmbeddingModel.ts} +39 -85
- package/src/OpenAiLanguageModel.ts +601 -0
- package/src/OpenAiTelemetry.ts +66 -71
- package/src/OpenAiTokenizer.ts +35 -26
- package/src/index.ts +3 -3
- package/src/internal/utilities.ts +19 -0
- package/OpenAiCompletions/package.json +0 -6
- package/OpenAiEmbeddings/package.json +0 -6
- package/dist/cjs/OpenAiCompletions.js +0 -358
- package/dist/cjs/OpenAiCompletions.js.map +0 -1
- package/dist/cjs/OpenAiEmbeddings.js.map +0 -1
- package/dist/dts/OpenAiCompletions.d.ts +0 -75
- package/dist/dts/OpenAiCompletions.d.ts.map +0 -1
- package/dist/dts/OpenAiEmbeddings.d.ts.map +0 -1
- package/dist/esm/OpenAiCompletions.js +0 -345
- package/dist/esm/OpenAiCompletions.js.map +0 -1
- package/dist/esm/OpenAiEmbeddings.js.map +0 -1
- package/src/OpenAiCompletions.ts +0 -500
package/src/OpenAiCompletions.ts
DELETED
|
@@ -1,500 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @since 1.0.0
|
|
3
|
-
*/
|
|
4
|
-
import { AiError } from "@effect/ai/AiError"
|
|
5
|
-
import type * as AiInput from "@effect/ai/AiInput"
|
|
6
|
-
import * as AiModel from "@effect/ai/AiModel"
|
|
7
|
-
import * as AiResponse from "@effect/ai/AiResponse"
|
|
8
|
-
import * as AiRole from "@effect/ai/AiRole"
|
|
9
|
-
import * as Completions from "@effect/ai/Completions"
|
|
10
|
-
import * as Tokenizer from "@effect/ai/Tokenizer"
|
|
11
|
-
import * as Arr from "effect/Array"
|
|
12
|
-
import * as Context from "effect/Context"
|
|
13
|
-
import * as Effect from "effect/Effect"
|
|
14
|
-
import { dual } from "effect/Function"
|
|
15
|
-
import * as Layer from "effect/Layer"
|
|
16
|
-
import type * as Option from "effect/Option"
|
|
17
|
-
import * as Predicate from "effect/Predicate"
|
|
18
|
-
import * as Stream from "effect/Stream"
|
|
19
|
-
import type { Span } from "effect/Tracer"
|
|
20
|
-
import type { Simplify } from "effect/Types"
|
|
21
|
-
import type * as Generated from "./Generated.js"
|
|
22
|
-
import type { StreamChunk } from "./OpenAiClient.js"
|
|
23
|
-
import { OpenAiClient } from "./OpenAiClient.js"
|
|
24
|
-
import { addGenAIAnnotations } from "./OpenAiTelemetry.js"
|
|
25
|
-
import * as OpenAiTokenizer from "./OpenAiTokenizer.js"
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* @since 1.0.0
|
|
29
|
-
* @category models
|
|
30
|
-
*/
|
|
31
|
-
export type Model = typeof Generated.ModelIdsSharedEnum.Encoded
|
|
32
|
-
|
|
33
|
-
// =============================================================================
|
|
34
|
-
// Configuration
|
|
35
|
-
// =============================================================================
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* @since 1.0.0
|
|
39
|
-
* @category tags
|
|
40
|
-
*/
|
|
41
|
-
export class Config extends Context.Tag("@effect/ai-openai/OpenAiCompletions/Config")<
|
|
42
|
-
Config,
|
|
43
|
-
Config.Service
|
|
44
|
-
>() {
|
|
45
|
-
/**
|
|
46
|
-
* @since 1.0.0
|
|
47
|
-
*/
|
|
48
|
-
static readonly getOrUndefined: Effect.Effect<Config.Service | undefined> = Effect.map(
|
|
49
|
-
Effect.context<never>(),
|
|
50
|
-
(context) => context.unsafeMap.get(Config.key)
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* @since 1.0.0
|
|
56
|
-
*/
|
|
57
|
-
export declare namespace Config {
|
|
58
|
-
/**
|
|
59
|
-
* @since 1.0.0
|
|
60
|
-
* @category configuration
|
|
61
|
-
*/
|
|
62
|
-
export interface Service extends
|
|
63
|
-
Simplify<
|
|
64
|
-
Partial<
|
|
65
|
-
Omit<
|
|
66
|
-
typeof Generated.CreateChatCompletionRequest.Encoded,
|
|
67
|
-
"messages" | "tools" | "tool_choice" | "stream" | "stream_options" | "functions"
|
|
68
|
-
>
|
|
69
|
-
>
|
|
70
|
-
>
|
|
71
|
-
{}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// =============================================================================
|
|
75
|
-
// OpenAi Completions
|
|
76
|
-
// =============================================================================
|
|
77
|
-
|
|
78
|
-
const modelCacheKey = Symbol.for("@effect/ai-openai/OpenAiCompletions/AiModel")
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* @since 1.0.0
|
|
82
|
-
* @category ai models
|
|
83
|
-
*/
|
|
84
|
-
export const model = (
|
|
85
|
-
model: (string & {}) | Model,
|
|
86
|
-
config?: Omit<Config.Service, "model">
|
|
87
|
-
): AiModel.AiModel<Completions.Completions | Tokenizer.Tokenizer, OpenAiClient> =>
|
|
88
|
-
AiModel.make({
|
|
89
|
-
model,
|
|
90
|
-
cacheKey: modelCacheKey,
|
|
91
|
-
requires: OpenAiClient,
|
|
92
|
-
provides: Effect.map(
|
|
93
|
-
make({ model, config }),
|
|
94
|
-
(completions) => Context.make(Completions.Completions, completions)
|
|
95
|
-
) as Effect.Effect<Context.Context<Completions.Completions | Tokenizer.Tokenizer>>,
|
|
96
|
-
updateContext: (context) => {
|
|
97
|
-
const innerConfig = context.unsafeMap.get(Config.key) as Config.Service | undefined
|
|
98
|
-
return Context.mergeAll(
|
|
99
|
-
context,
|
|
100
|
-
Context.make(Config, { model, ...config, ...innerConfig }),
|
|
101
|
-
Context.make(Tokenizer.Tokenizer, OpenAiTokenizer.make({ model: innerConfig?.model ?? model }))
|
|
102
|
-
)
|
|
103
|
-
}
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
const make = Effect.fnUntraced(function*(options: {
|
|
107
|
-
readonly model: (string & {}) | Model
|
|
108
|
-
readonly config?: Omit<Config.Service, "model">
|
|
109
|
-
}) {
|
|
110
|
-
const client = yield* OpenAiClient
|
|
111
|
-
|
|
112
|
-
const makeRequest = ({ input, required, system, tools }: Completions.CompletionOptions) => {
|
|
113
|
-
const useStructured = tools.length === 1 && tools[0].structured
|
|
114
|
-
return Effect.map(
|
|
115
|
-
Effect.context<never>(),
|
|
116
|
-
(context): typeof Generated.CreateChatCompletionRequest.Encoded => ({
|
|
117
|
-
model: options.model,
|
|
118
|
-
...options.config,
|
|
119
|
-
...context.unsafeMap.get(Config.key),
|
|
120
|
-
messages: makeMessages(input, system),
|
|
121
|
-
response_format: useStructured ?
|
|
122
|
-
{
|
|
123
|
-
type: "json_schema",
|
|
124
|
-
json_schema: {
|
|
125
|
-
strict: true,
|
|
126
|
-
name: tools[0].name,
|
|
127
|
-
description: tools[0].description,
|
|
128
|
-
schema: tools[0].parameters as any
|
|
129
|
-
}
|
|
130
|
-
} :
|
|
131
|
-
undefined,
|
|
132
|
-
tools: !useStructured && tools.length > 0 ?
|
|
133
|
-
tools.map((tool) => ({
|
|
134
|
-
type: "function",
|
|
135
|
-
function: {
|
|
136
|
-
name: tool.name,
|
|
137
|
-
description: tool.description,
|
|
138
|
-
parameters: tool.parameters as any,
|
|
139
|
-
strict: true
|
|
140
|
-
}
|
|
141
|
-
})) :
|
|
142
|
-
undefined,
|
|
143
|
-
tool_choice: !useStructured && tools.length > 0 ?
|
|
144
|
-
typeof required === "boolean" ? (required ? "required" : "auto") : {
|
|
145
|
-
type: "function",
|
|
146
|
-
function: { name: required }
|
|
147
|
-
} :
|
|
148
|
-
undefined
|
|
149
|
-
})
|
|
150
|
-
)
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return yield* Completions.make({
|
|
154
|
-
create({ span, ...options }) {
|
|
155
|
-
return makeRequest(options).pipe(
|
|
156
|
-
Effect.tap((request) => annotateRequest(span, request)),
|
|
157
|
-
Effect.flatMap(client.client.createChatCompletion),
|
|
158
|
-
Effect.tap((response) => annotateChatResponse(span, response)),
|
|
159
|
-
Effect.flatMap((response) =>
|
|
160
|
-
makeResponse(
|
|
161
|
-
response,
|
|
162
|
-
"create",
|
|
163
|
-
options.tools.length === 1 && options.tools[0].structured
|
|
164
|
-
? options.tools[0]
|
|
165
|
-
: undefined
|
|
166
|
-
)
|
|
167
|
-
),
|
|
168
|
-
Effect.catchAll((cause) =>
|
|
169
|
-
Effect.fail(
|
|
170
|
-
new AiError({
|
|
171
|
-
module: "OpenAiCompletions",
|
|
172
|
-
method: "create",
|
|
173
|
-
description: "An error occurred",
|
|
174
|
-
cause
|
|
175
|
-
})
|
|
176
|
-
)
|
|
177
|
-
)
|
|
178
|
-
)
|
|
179
|
-
},
|
|
180
|
-
stream({ span, ...options }) {
|
|
181
|
-
return makeRequest(options).pipe(
|
|
182
|
-
Effect.tap((request) => annotateRequest(span, request)),
|
|
183
|
-
Effect.map(client.stream),
|
|
184
|
-
Stream.unwrap,
|
|
185
|
-
Stream.tap((response) => {
|
|
186
|
-
annotateStreamResponse(span, response)
|
|
187
|
-
return Effect.void
|
|
188
|
-
}),
|
|
189
|
-
Stream.map((response) => response.asAiResponse),
|
|
190
|
-
Stream.catchAll((cause) =>
|
|
191
|
-
Effect.fail(
|
|
192
|
-
new AiError({
|
|
193
|
-
module: "OpenAiCompletions",
|
|
194
|
-
method: "stream",
|
|
195
|
-
description: "An error occurred",
|
|
196
|
-
cause
|
|
197
|
-
})
|
|
198
|
-
)
|
|
199
|
-
)
|
|
200
|
-
)
|
|
201
|
-
}
|
|
202
|
-
})
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* @since 1.0.0
|
|
207
|
-
* @category layers
|
|
208
|
-
*/
|
|
209
|
-
export const layerCompletions = (options: {
|
|
210
|
-
readonly model: (string & {}) | Model
|
|
211
|
-
readonly config?: Omit<Config.Service, "model">
|
|
212
|
-
}): Layer.Layer<Completions.Completions, never, OpenAiClient> =>
|
|
213
|
-
Layer.effect(
|
|
214
|
-
Completions.Completions,
|
|
215
|
-
make({ model: options.model, config: options.config })
|
|
216
|
-
)
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* @since 1.0.0
|
|
220
|
-
* @category layers
|
|
221
|
-
*/
|
|
222
|
-
export const layer = (options: {
|
|
223
|
-
readonly model: (string & {}) | Model
|
|
224
|
-
readonly config?: Omit<Config.Service, "model">
|
|
225
|
-
}): Layer.Layer<Completions.Completions | Tokenizer.Tokenizer, never, OpenAiClient> =>
|
|
226
|
-
Layer.merge(layerCompletions(options), OpenAiTokenizer.layer(options))
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* @since 1.0.0
|
|
230
|
-
* @category configuration
|
|
231
|
-
*/
|
|
232
|
-
export const withConfigOverride: {
|
|
233
|
-
/**
|
|
234
|
-
* @since 1.0.0
|
|
235
|
-
* @category configuration
|
|
236
|
-
*/
|
|
237
|
-
(overrides: Config.Service): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
|
|
238
|
-
/**
|
|
239
|
-
* @since 1.0.0
|
|
240
|
-
* @category configuration
|
|
241
|
-
*/
|
|
242
|
-
<A, E, R>(self: Effect.Effect<A, E, R>, overrides: Config.Service): Effect.Effect<A, E, R>
|
|
243
|
-
} = dual<
|
|
244
|
-
/**
|
|
245
|
-
* @since 1.0.0
|
|
246
|
-
* @category configuration
|
|
247
|
-
*/
|
|
248
|
-
(overrides: Config.Service) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>,
|
|
249
|
-
/**
|
|
250
|
-
* @since 1.0.0
|
|
251
|
-
* @category configuration
|
|
252
|
-
*/
|
|
253
|
-
<A, E, R>(self: Effect.Effect<A, E, R>, overrides: Config.Service) => Effect.Effect<A, E, R>
|
|
254
|
-
>(2, (self, overrides) =>
|
|
255
|
-
Effect.flatMap(
|
|
256
|
-
Config.getOrUndefined,
|
|
257
|
-
(config) => Effect.provideService(self, Config, { ...config, ...overrides })
|
|
258
|
-
))
|
|
259
|
-
|
|
260
|
-
const makeMessages = (
|
|
261
|
-
input: AiInput.AiInput,
|
|
262
|
-
system: Option.Option<string>
|
|
263
|
-
): Arr.NonEmptyReadonlyArray<typeof Generated.ChatCompletionRequestMessage.Encoded> => {
|
|
264
|
-
const messages: Array<typeof Generated.ChatCompletionRequestMessage.Encoded> = system._tag === "Some" ?
|
|
265
|
-
[makeSystemMessage(system.value)] :
|
|
266
|
-
[]
|
|
267
|
-
for (const message of input) {
|
|
268
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
269
|
-
messages.push(...convertMessage(message))
|
|
270
|
-
}
|
|
271
|
-
return messages as any
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const formatRole = (role: AiRole.AiRole) => {
|
|
275
|
-
switch (role._tag) {
|
|
276
|
-
case "UserWithName":
|
|
277
|
-
return {
|
|
278
|
-
role: "user",
|
|
279
|
-
name: safeName(role.name)
|
|
280
|
-
} as const
|
|
281
|
-
case "User":
|
|
282
|
-
return {
|
|
283
|
-
role: "user"
|
|
284
|
-
} as const
|
|
285
|
-
case "Model":
|
|
286
|
-
return {
|
|
287
|
-
role: "assistant"
|
|
288
|
-
} as const
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
const convertMessage = (
|
|
293
|
-
message: AiInput.Message
|
|
294
|
-
): Array<typeof Generated.ChatCompletionRequestMessage.Encoded> => {
|
|
295
|
-
const messages: Array<typeof Generated.ChatCompletionRequestMessage.Encoded> = []
|
|
296
|
-
let parts: Array<typeof Generated.ChatCompletionRequestUserMessageContentPart.Encoded> = []
|
|
297
|
-
let toolCalls: Array<typeof Generated.ChatCompletionMessageToolCall.Encoded> = []
|
|
298
|
-
function flushContent() {
|
|
299
|
-
if (parts.length === 0) return
|
|
300
|
-
messages.push({
|
|
301
|
-
...formatRole(message.role),
|
|
302
|
-
content: parts as any
|
|
303
|
-
})
|
|
304
|
-
parts = []
|
|
305
|
-
}
|
|
306
|
-
function flushToolCalls() {
|
|
307
|
-
if (toolCalls.length === 0) return
|
|
308
|
-
messages.push({
|
|
309
|
-
role: "assistant",
|
|
310
|
-
content: null,
|
|
311
|
-
tool_calls: toolCalls
|
|
312
|
-
})
|
|
313
|
-
toolCalls = []
|
|
314
|
-
}
|
|
315
|
-
for (const part of message.parts) {
|
|
316
|
-
if (part._tag === "ToolCall") {
|
|
317
|
-
flushContent()
|
|
318
|
-
toolCalls.push({
|
|
319
|
-
id: part.id,
|
|
320
|
-
type: "function",
|
|
321
|
-
function: {
|
|
322
|
-
name: part.name,
|
|
323
|
-
arguments: JSON.stringify(part.params)
|
|
324
|
-
}
|
|
325
|
-
})
|
|
326
|
-
} else if (part._tag === "ToolCallResolved") {
|
|
327
|
-
flushContent()
|
|
328
|
-
flushToolCalls()
|
|
329
|
-
messages.push({
|
|
330
|
-
role: "tool",
|
|
331
|
-
tool_call_id: part.toolCallId,
|
|
332
|
-
content: JSON.stringify(part.value)
|
|
333
|
-
})
|
|
334
|
-
} else {
|
|
335
|
-
flushToolCalls()
|
|
336
|
-
parts.push(makeContentPart(part))
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
flushContent()
|
|
340
|
-
flushToolCalls()
|
|
341
|
-
return messages
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
const makeContentPart = (
|
|
345
|
-
part: AiInput.TextPart | AiInput.ImagePart | AiInput.ImageUrlPart
|
|
346
|
-
): typeof Generated.ChatCompletionRequestUserMessageContentPart.Encoded => {
|
|
347
|
-
switch (part._tag) {
|
|
348
|
-
case "Image":
|
|
349
|
-
return {
|
|
350
|
-
type: "image_url",
|
|
351
|
-
image_url: {
|
|
352
|
-
url: part.asDataUri,
|
|
353
|
-
detail: part.quality
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
case "ImageUrl":
|
|
357
|
-
return {
|
|
358
|
-
type: "image_url",
|
|
359
|
-
image_url: {
|
|
360
|
-
url: part.url,
|
|
361
|
-
detail: part.quality
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
case "Text":
|
|
365
|
-
return {
|
|
366
|
-
type: "text",
|
|
367
|
-
text: part.content
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
const makeResponse = (
|
|
373
|
-
response: typeof Generated.CreateChatCompletionResponse.Type,
|
|
374
|
-
method: string,
|
|
375
|
-
structuredTool?: {
|
|
376
|
-
readonly name: string
|
|
377
|
-
readonly description: string
|
|
378
|
-
}
|
|
379
|
-
) =>
|
|
380
|
-
Arr.head(response.choices).pipe(
|
|
381
|
-
Effect.mapError(() =>
|
|
382
|
-
new AiError({
|
|
383
|
-
module: "OpenAiCompletions",
|
|
384
|
-
method,
|
|
385
|
-
description: "Could not get response"
|
|
386
|
-
})
|
|
387
|
-
),
|
|
388
|
-
Effect.flatMap((choice) => {
|
|
389
|
-
if (structuredTool) {
|
|
390
|
-
return AiResponse.AiResponse.empty.withToolCallsJson([
|
|
391
|
-
{
|
|
392
|
-
id: response.id,
|
|
393
|
-
name: structuredTool.name,
|
|
394
|
-
params: choice.message.content!
|
|
395
|
-
}
|
|
396
|
-
])
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
const res = typeof choice.message.content === "string" ?
|
|
400
|
-
AiResponse.AiResponse.fromText({
|
|
401
|
-
role: AiRole.model,
|
|
402
|
-
content: choice.message.content!
|
|
403
|
-
}) :
|
|
404
|
-
AiResponse.AiResponse.empty
|
|
405
|
-
|
|
406
|
-
if (choice.message.tool_calls && choice.message.tool_calls.length > 0) {
|
|
407
|
-
return res.withToolCallsJson(choice.message.tool_calls.map((toolCall) => ({
|
|
408
|
-
id: toolCall.id,
|
|
409
|
-
name: toolCall.function.name,
|
|
410
|
-
params: toolCall.function.arguments
|
|
411
|
-
})))
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
return Effect.succeed(res)
|
|
415
|
-
})
|
|
416
|
-
)
|
|
417
|
-
|
|
418
|
-
const makeSystemMessage = (content: string): typeof Generated.ChatCompletionRequestSystemMessage.Encoded => {
|
|
419
|
-
return {
|
|
420
|
-
role: "system",
|
|
421
|
-
content
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
const safeName = (name: string) => name.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/, "_")
|
|
426
|
-
|
|
427
|
-
const annotateRequest = (
|
|
428
|
-
span: Span,
|
|
429
|
-
request: typeof Generated.CreateChatCompletionRequest.Encoded
|
|
430
|
-
): void => {
|
|
431
|
-
addGenAIAnnotations(span, {
|
|
432
|
-
system: "openai",
|
|
433
|
-
operation: { name: "chat" },
|
|
434
|
-
request: {
|
|
435
|
-
model: request.model,
|
|
436
|
-
temperature: request.temperature,
|
|
437
|
-
topP: request.top_p,
|
|
438
|
-
maxTokens: request.max_tokens,
|
|
439
|
-
stopSequences: Arr.ensure(request.stop).filter(Predicate.isNotNullable),
|
|
440
|
-
frequencyPenalty: request.frequency_penalty,
|
|
441
|
-
presencePenalty: request.presence_penalty,
|
|
442
|
-
seed: request.seed
|
|
443
|
-
},
|
|
444
|
-
openai: {
|
|
445
|
-
request: {
|
|
446
|
-
responseFormat: request.response_format?.type,
|
|
447
|
-
serviceTier: request.service_tier
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
})
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
const annotateChatResponse = (
|
|
454
|
-
span: Span,
|
|
455
|
-
response: typeof Generated.CreateChatCompletionResponse.Type
|
|
456
|
-
): void => {
|
|
457
|
-
addGenAIAnnotations(span, {
|
|
458
|
-
response: {
|
|
459
|
-
id: response.id,
|
|
460
|
-
model: response.model,
|
|
461
|
-
finishReasons: response.choices.map((choice) => choice.finish_reason)
|
|
462
|
-
},
|
|
463
|
-
usage: {
|
|
464
|
-
inputTokens: response.usage?.prompt_tokens,
|
|
465
|
-
outputTokens: response.usage?.completion_tokens
|
|
466
|
-
},
|
|
467
|
-
openai: {
|
|
468
|
-
response: {
|
|
469
|
-
systemFingerprint: response.system_fingerprint,
|
|
470
|
-
serviceTier: response.service_tier
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
})
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
const annotateStreamResponse = (
|
|
477
|
-
span: Span,
|
|
478
|
-
response: StreamChunk
|
|
479
|
-
) => {
|
|
480
|
-
const usage = response.parts.find((part) => part._tag === "Usage")
|
|
481
|
-
if (Predicate.isNotNullable(usage)) {
|
|
482
|
-
addGenAIAnnotations(span, {
|
|
483
|
-
response: {
|
|
484
|
-
id: usage.id,
|
|
485
|
-
model: usage.model,
|
|
486
|
-
finishReasons: usage.finishReasons
|
|
487
|
-
},
|
|
488
|
-
usage: {
|
|
489
|
-
inputTokens: usage.inputTokens,
|
|
490
|
-
outputTokens: usage.outputTokens
|
|
491
|
-
},
|
|
492
|
-
openai: {
|
|
493
|
-
response: {
|
|
494
|
-
systemFingerprint: usage.systemFingerprint,
|
|
495
|
-
serviceTier: usage.serviceTier
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
})
|
|
499
|
-
}
|
|
500
|
-
}
|