@effect/ai-openai-compat 4.0.0-beta.9 → 4.0.0-beta.90
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/OpenAiClient.d.ts +264 -52
- package/dist/OpenAiClient.d.ts.map +1 -1
- package/dist/OpenAiClient.js +97 -9
- package/dist/OpenAiClient.js.map +1 -1
- package/dist/OpenAiConfig.d.ts +68 -10
- package/dist/OpenAiConfig.d.ts.map +1 -1
- package/dist/OpenAiConfig.js +36 -7
- package/dist/OpenAiConfig.js.map +1 -1
- package/dist/OpenAiEmbeddingModel.d.ts +186 -0
- package/dist/OpenAiEmbeddingModel.d.ts.map +1 -0
- package/dist/OpenAiEmbeddingModel.js +190 -0
- package/dist/OpenAiEmbeddingModel.js.map +1 -0
- package/dist/OpenAiError.d.ts +109 -35
- package/dist/OpenAiError.d.ts.map +1 -1
- package/dist/OpenAiError.js +14 -1
- package/dist/OpenAiLanguageModel.d.ts +304 -20
- package/dist/OpenAiLanguageModel.d.ts.map +1 -1
- package/dist/OpenAiLanguageModel.js +157 -27
- package/dist/OpenAiLanguageModel.js.map +1 -1
- package/dist/OpenAiTelemetry.d.ts +76 -26
- package/dist/OpenAiTelemetry.d.ts.map +1 -1
- package/dist/OpenAiTelemetry.js +22 -10
- package/dist/OpenAiTelemetry.js.map +1 -1
- package/dist/index.d.ts +10 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -17
- package/dist/index.js.map +1 -1
- package/dist/internal/errors.js +4 -4
- package/dist/internal/errors.js.map +1 -1
- package/dist/internal/utilities.js +0 -6
- package/dist/internal/utilities.js.map +1 -1
- package/package.json +3 -3
- package/src/OpenAiClient.ts +273 -50
- package/src/OpenAiConfig.ts +69 -11
- package/src/OpenAiEmbeddingModel.ts +332 -0
- package/src/OpenAiError.ts +111 -35
- package/src/OpenAiLanguageModel.ts +426 -43
- package/src/OpenAiTelemetry.ts +81 -32
- package/src/index.ts +11 -17
- package/src/internal/errors.ts +4 -4
- package/src/internal/utilities.ts +0 -9
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OpenAI
|
|
2
|
+
* The `OpenAiLanguageModel` module adapts OpenAI-compatible chat completions
|
|
3
|
+
* providers to Effect AI's `LanguageModel` service. It builds a model service
|
|
4
|
+
* from a model id, translates prompts, files, tools, structured output schemas,
|
|
5
|
+
* and provider-specific options into `OpenAiClient` requests, and maps normal
|
|
6
|
+
* or streaming chat completion results back into Effect AI response content and
|
|
7
|
+
* metadata.
|
|
3
8
|
*
|
|
4
|
-
*
|
|
5
|
-
* supporting text generation, structured output, tool calling, and streaming.
|
|
6
|
-
*
|
|
7
|
-
* @since 1.0.0
|
|
9
|
+
* @since 4.0.0
|
|
8
10
|
*/
|
|
11
|
+
import * as Context from "effect/Context"
|
|
9
12
|
import * as DateTime from "effect/DateTime"
|
|
10
13
|
import * as Effect from "effect/Effect"
|
|
11
14
|
import * as Encoding from "effect/Encoding"
|
|
12
15
|
import { dual } from "effect/Function"
|
|
13
16
|
import * as Layer from "effect/Layer"
|
|
17
|
+
import * as Option from "effect/Option"
|
|
14
18
|
import * as Predicate from "effect/Predicate"
|
|
15
19
|
import * as Redactable from "effect/Redactable"
|
|
16
20
|
import type * as Schema from "effect/Schema"
|
|
17
21
|
import * as AST from "effect/SchemaAST"
|
|
18
|
-
import * as ServiceMap from "effect/ServiceMap"
|
|
19
22
|
import * as Stream from "effect/Stream"
|
|
20
23
|
import type { Span } from "effect/Tracer"
|
|
21
24
|
import type { DeepMutable, Simplify } from "effect/Types"
|
|
@@ -58,12 +61,20 @@ type ImageDetail = "auto" | "low" | "high"
|
|
|
58
61
|
// =============================================================================
|
|
59
62
|
|
|
60
63
|
/**
|
|
61
|
-
*
|
|
64
|
+
* Context service for OpenAI language model configuration.
|
|
65
|
+
*
|
|
66
|
+
* **When to use**
|
|
67
|
+
*
|
|
68
|
+
* Use as the context service for OpenAI-compatible language model request
|
|
69
|
+
* configuration, especially when a scoped operation should override the defaults
|
|
70
|
+
* supplied to `model`, `make`, or `layer`.
|
|
71
|
+
*
|
|
72
|
+
* @see {@link withConfigOverride} for scoping language model request overrides
|
|
62
73
|
*
|
|
63
|
-
* @since 1.0.0
|
|
64
74
|
* @category context
|
|
75
|
+
* @since 4.0.0
|
|
65
76
|
*/
|
|
66
|
-
export class Config extends
|
|
77
|
+
export class Config extends Context.Service<
|
|
67
78
|
Config,
|
|
68
79
|
Simplify<
|
|
69
80
|
& Partial<
|
|
@@ -101,6 +112,7 @@ export class Config extends ServiceMap.Service<
|
|
|
101
112
|
* Defaults to `true`.
|
|
102
113
|
*/
|
|
103
114
|
readonly strictJsonSchema?: boolean | undefined
|
|
115
|
+
readonly [x: string]: unknown
|
|
104
116
|
}
|
|
105
117
|
>
|
|
106
118
|
>()("@effect/ai-openai-compat/OpenAiLanguageModel/Config") {}
|
|
@@ -110,7 +122,16 @@ export class Config extends ServiceMap.Service<
|
|
|
110
122
|
// =============================================================================
|
|
111
123
|
|
|
112
124
|
declare module "effect/unstable/ai/Prompt" {
|
|
125
|
+
/**
|
|
126
|
+
* OpenAI-compatible options for file prompt parts.
|
|
127
|
+
*
|
|
128
|
+
* @category request
|
|
129
|
+
* @since 4.0.0
|
|
130
|
+
*/
|
|
113
131
|
export interface FilePartOptions extends ProviderOptions {
|
|
132
|
+
/**
|
|
133
|
+
* Provider-specific file options for OpenAI-compatible APIs.
|
|
134
|
+
*/
|
|
114
135
|
readonly openai?: {
|
|
115
136
|
/**
|
|
116
137
|
* The detail level of the image to be sent to the model. One of `high`, `low`, or `auto`. Defaults to `auto`.
|
|
@@ -119,7 +140,16 @@ declare module "effect/unstable/ai/Prompt" {
|
|
|
119
140
|
} | null
|
|
120
141
|
}
|
|
121
142
|
|
|
143
|
+
/**
|
|
144
|
+
* OpenAI-compatible options for reasoning prompt parts.
|
|
145
|
+
*
|
|
146
|
+
* @category request
|
|
147
|
+
* @since 4.0.0
|
|
148
|
+
*/
|
|
122
149
|
export interface ReasoningPartOptions extends ProviderOptions {
|
|
150
|
+
/**
|
|
151
|
+
* Provider-specific reasoning options for OpenAI-compatible APIs.
|
|
152
|
+
*/
|
|
123
153
|
readonly openai?: {
|
|
124
154
|
/**
|
|
125
155
|
* The ID of the item to reference.
|
|
@@ -134,40 +164,67 @@ declare module "effect/unstable/ai/Prompt" {
|
|
|
134
164
|
} | null
|
|
135
165
|
}
|
|
136
166
|
|
|
167
|
+
/**
|
|
168
|
+
* OpenAI-compatible options for assistant tool-call prompt parts.
|
|
169
|
+
*
|
|
170
|
+
* @category request
|
|
171
|
+
* @since 4.0.0
|
|
172
|
+
*/
|
|
137
173
|
export interface ToolCallPartOptions extends ProviderOptions {
|
|
174
|
+
/**
|
|
175
|
+
* Provider-specific tool-call options for OpenAI-compatible APIs.
|
|
176
|
+
*/
|
|
138
177
|
readonly openai?: {
|
|
139
178
|
/**
|
|
140
179
|
* The ID of the item to reference.
|
|
141
180
|
*/
|
|
142
181
|
readonly itemId?: string | null
|
|
143
182
|
/**
|
|
144
|
-
* The status
|
|
183
|
+
* The status to send for the tool-call item.
|
|
145
184
|
*/
|
|
146
185
|
readonly status?: MessageStatus | null
|
|
147
186
|
} | null
|
|
148
187
|
}
|
|
149
188
|
|
|
189
|
+
/**
|
|
190
|
+
* OpenAI-compatible options for tool-result prompt parts.
|
|
191
|
+
*
|
|
192
|
+
* @category request
|
|
193
|
+
* @since 4.0.0
|
|
194
|
+
*/
|
|
150
195
|
export interface ToolResultPartOptions extends ProviderOptions {
|
|
196
|
+
/**
|
|
197
|
+
* Provider-specific tool-result options for OpenAI-compatible APIs.
|
|
198
|
+
*/
|
|
151
199
|
readonly openai?: {
|
|
152
200
|
/**
|
|
153
201
|
* The ID of the item to reference.
|
|
154
202
|
*/
|
|
155
203
|
readonly itemId?: string | null
|
|
156
204
|
/**
|
|
157
|
-
* The status
|
|
205
|
+
* The status to send for the tool-result item.
|
|
158
206
|
*/
|
|
159
207
|
readonly status?: MessageStatus | null
|
|
160
208
|
} | null
|
|
161
209
|
}
|
|
162
210
|
|
|
211
|
+
/**
|
|
212
|
+
* OpenAI-compatible options for text prompt parts.
|
|
213
|
+
*
|
|
214
|
+
* @category request
|
|
215
|
+
* @since 4.0.0
|
|
216
|
+
*/
|
|
163
217
|
export interface TextPartOptions extends ProviderOptions {
|
|
218
|
+
/**
|
|
219
|
+
* Provider-specific text options for OpenAI-compatible APIs.
|
|
220
|
+
*/
|
|
164
221
|
readonly openai?: {
|
|
165
222
|
/**
|
|
166
223
|
* The ID of the item to reference.
|
|
167
224
|
*/
|
|
168
225
|
readonly itemId?: string | null
|
|
169
226
|
/**
|
|
170
|
-
* The status
|
|
227
|
+
* The status to send for the text item.
|
|
171
228
|
*/
|
|
172
229
|
readonly status?: MessageStatus | null
|
|
173
230
|
/**
|
|
@@ -179,8 +236,20 @@ declare module "effect/unstable/ai/Prompt" {
|
|
|
179
236
|
}
|
|
180
237
|
|
|
181
238
|
declare module "effect/unstable/ai/Response" {
|
|
239
|
+
/**
|
|
240
|
+
* OpenAI-compatible metadata attached to a complete text response part.
|
|
241
|
+
*
|
|
242
|
+
* @category response
|
|
243
|
+
* @since 4.0.0
|
|
244
|
+
*/
|
|
182
245
|
export interface TextPartMetadata extends ProviderMetadata {
|
|
246
|
+
/**
|
|
247
|
+
* Provider-specific metadata returned for the text part.
|
|
248
|
+
*/
|
|
183
249
|
readonly openai?: {
|
|
250
|
+
/**
|
|
251
|
+
* The OpenAI item ID associated with the text part.
|
|
252
|
+
*/
|
|
184
253
|
readonly itemId?: string | null
|
|
185
254
|
/**
|
|
186
255
|
* If the model emits a refusal content part, the refusal explanation
|
|
@@ -189,7 +258,7 @@ declare module "effect/unstable/ai/Response" {
|
|
|
189
258
|
*/
|
|
190
259
|
readonly refusal?: string | null
|
|
191
260
|
/**
|
|
192
|
-
* The status
|
|
261
|
+
* The status returned for the text item.
|
|
193
262
|
*/
|
|
194
263
|
readonly status?: MessageStatus | null
|
|
195
264
|
/**
|
|
@@ -199,55 +268,163 @@ declare module "effect/unstable/ai/Response" {
|
|
|
199
268
|
}
|
|
200
269
|
}
|
|
201
270
|
|
|
271
|
+
/**
|
|
272
|
+
* OpenAI-compatible metadata emitted when a streamed text part starts.
|
|
273
|
+
*
|
|
274
|
+
* @category response
|
|
275
|
+
* @since 4.0.0
|
|
276
|
+
*/
|
|
202
277
|
export interface TextStartPartMetadata extends ProviderMetadata {
|
|
278
|
+
/**
|
|
279
|
+
* Provider-specific metadata returned for the streamed text start.
|
|
280
|
+
*/
|
|
203
281
|
readonly openai?: {
|
|
282
|
+
/**
|
|
283
|
+
* The OpenAI item ID associated with the streamed text part.
|
|
284
|
+
*/
|
|
204
285
|
readonly itemId?: string | null
|
|
205
286
|
} | null
|
|
206
287
|
}
|
|
207
288
|
|
|
289
|
+
/**
|
|
290
|
+
* OpenAI-compatible metadata emitted when a streamed text part ends.
|
|
291
|
+
*
|
|
292
|
+
* @category response
|
|
293
|
+
* @since 4.0.0
|
|
294
|
+
*/
|
|
208
295
|
export interface TextEndPartMetadata extends ProviderMetadata {
|
|
296
|
+
/**
|
|
297
|
+
* Provider-specific metadata returned for the streamed text end.
|
|
298
|
+
*/
|
|
209
299
|
readonly openai?: {
|
|
300
|
+
/**
|
|
301
|
+
* The OpenAI item ID associated with the streamed text part.
|
|
302
|
+
*/
|
|
210
303
|
readonly itemId?: string | null
|
|
304
|
+
/**
|
|
305
|
+
* The annotations collected for the completed streamed text part.
|
|
306
|
+
*/
|
|
211
307
|
readonly annotations?: ReadonlyArray<Annotation> | null
|
|
212
308
|
} | null
|
|
213
309
|
}
|
|
214
310
|
|
|
311
|
+
/**
|
|
312
|
+
* OpenAI-compatible metadata attached to a complete reasoning response part.
|
|
313
|
+
*
|
|
314
|
+
* @category response
|
|
315
|
+
* @since 4.0.0
|
|
316
|
+
*/
|
|
215
317
|
export interface ReasoningPartMetadata extends ProviderMetadata {
|
|
318
|
+
/**
|
|
319
|
+
* Provider-specific metadata returned for the reasoning part.
|
|
320
|
+
*/
|
|
216
321
|
readonly openai?: {
|
|
322
|
+
/**
|
|
323
|
+
* The OpenAI item ID associated with the reasoning part.
|
|
324
|
+
*/
|
|
217
325
|
readonly itemId?: string | null
|
|
326
|
+
/**
|
|
327
|
+
* Encrypted reasoning content that can be sent back in later requests.
|
|
328
|
+
*/
|
|
218
329
|
readonly encryptedContent?: string | null
|
|
219
330
|
} | null
|
|
220
331
|
}
|
|
221
332
|
|
|
333
|
+
/**
|
|
334
|
+
* OpenAI-compatible metadata emitted when a streamed reasoning part starts.
|
|
335
|
+
*
|
|
336
|
+
* @category response
|
|
337
|
+
* @since 4.0.0
|
|
338
|
+
*/
|
|
222
339
|
export interface ReasoningStartPartMetadata extends ProviderMetadata {
|
|
340
|
+
/**
|
|
341
|
+
* Provider-specific metadata returned for the streamed reasoning start.
|
|
342
|
+
*/
|
|
223
343
|
readonly openai?: {
|
|
344
|
+
/**
|
|
345
|
+
* The OpenAI item ID associated with the reasoning part.
|
|
346
|
+
*/
|
|
224
347
|
readonly itemId?: string | null
|
|
348
|
+
/**
|
|
349
|
+
* Encrypted reasoning content that can be sent back in later requests.
|
|
350
|
+
*/
|
|
225
351
|
readonly encryptedContent?: string | null
|
|
226
352
|
} | null
|
|
227
353
|
}
|
|
228
354
|
|
|
355
|
+
/**
|
|
356
|
+
* OpenAI-compatible metadata emitted for a streamed reasoning delta.
|
|
357
|
+
*
|
|
358
|
+
* @category response
|
|
359
|
+
* @since 4.0.0
|
|
360
|
+
*/
|
|
229
361
|
export interface ReasoningDeltaPartMetadata extends ProviderMetadata {
|
|
362
|
+
/**
|
|
363
|
+
* Provider-specific metadata returned for the streamed reasoning delta.
|
|
364
|
+
*/
|
|
230
365
|
readonly openai?: {
|
|
366
|
+
/**
|
|
367
|
+
* The OpenAI item ID associated with the reasoning part.
|
|
368
|
+
*/
|
|
231
369
|
readonly itemId?: string | null
|
|
232
370
|
} | null
|
|
233
371
|
}
|
|
234
372
|
|
|
373
|
+
/**
|
|
374
|
+
* OpenAI-compatible metadata emitted when a streamed reasoning part ends.
|
|
375
|
+
*
|
|
376
|
+
* @category response
|
|
377
|
+
* @since 4.0.0
|
|
378
|
+
*/
|
|
235
379
|
export interface ReasoningEndPartMetadata extends ProviderMetadata {
|
|
380
|
+
/**
|
|
381
|
+
* Provider-specific metadata returned for the streamed reasoning end.
|
|
382
|
+
*/
|
|
236
383
|
readonly openai?: {
|
|
384
|
+
/**
|
|
385
|
+
* The OpenAI item ID associated with the reasoning part.
|
|
386
|
+
*/
|
|
237
387
|
readonly itemId?: string | null
|
|
388
|
+
/**
|
|
389
|
+
* Encrypted reasoning content that can be sent back in later requests.
|
|
390
|
+
*/
|
|
238
391
|
readonly encryptedContent?: string
|
|
239
392
|
} | null
|
|
240
393
|
}
|
|
241
394
|
|
|
395
|
+
/**
|
|
396
|
+
* OpenAI-compatible metadata attached to tool-call response parts.
|
|
397
|
+
*
|
|
398
|
+
* @category response
|
|
399
|
+
* @since 4.0.0
|
|
400
|
+
*/
|
|
242
401
|
export interface ToolCallPartMetadata extends ProviderMetadata {
|
|
402
|
+
/**
|
|
403
|
+
* Provider-specific metadata returned for the tool call.
|
|
404
|
+
*/
|
|
243
405
|
readonly openai?: {
|
|
406
|
+
/**
|
|
407
|
+
* The OpenAI item ID associated with the tool call.
|
|
408
|
+
*/
|
|
244
409
|
readonly itemId?: string | null
|
|
245
410
|
} | null
|
|
246
411
|
}
|
|
247
412
|
|
|
413
|
+
/**
|
|
414
|
+
* OpenAI-compatible metadata attached to document source citations.
|
|
415
|
+
*
|
|
416
|
+
* @category response
|
|
417
|
+
* @since 4.0.0
|
|
418
|
+
*/
|
|
248
419
|
export interface DocumentSourcePartMetadata extends ProviderMetadata {
|
|
420
|
+
/**
|
|
421
|
+
* Provider-specific citation metadata for OpenAI-compatible APIs.
|
|
422
|
+
*/
|
|
249
423
|
readonly openai?:
|
|
250
424
|
| {
|
|
425
|
+
/**
|
|
426
|
+
* Identifies a citation to an uploaded file.
|
|
427
|
+
*/
|
|
251
428
|
readonly type: "file_citation"
|
|
252
429
|
/**
|
|
253
430
|
* The index of the file in the list of files.
|
|
@@ -259,6 +436,9 @@ declare module "effect/unstable/ai/Response" {
|
|
|
259
436
|
readonly fileId: string
|
|
260
437
|
}
|
|
261
438
|
| {
|
|
439
|
+
/**
|
|
440
|
+
* Identifies a citation to a generated file path.
|
|
441
|
+
*/
|
|
262
442
|
readonly type: "file_path"
|
|
263
443
|
/**
|
|
264
444
|
* The index of the file in the list of files.
|
|
@@ -270,6 +450,9 @@ declare module "effect/unstable/ai/Response" {
|
|
|
270
450
|
readonly fileId: string
|
|
271
451
|
}
|
|
272
452
|
| {
|
|
453
|
+
/**
|
|
454
|
+
* Identifies a citation to a file inside a container.
|
|
455
|
+
*/
|
|
273
456
|
readonly type: "container_file_citation"
|
|
274
457
|
/**
|
|
275
458
|
* The ID of the file.
|
|
@@ -283,8 +466,20 @@ declare module "effect/unstable/ai/Response" {
|
|
|
283
466
|
| null
|
|
284
467
|
}
|
|
285
468
|
|
|
469
|
+
/**
|
|
470
|
+
* OpenAI-compatible metadata attached to URL source citations.
|
|
471
|
+
*
|
|
472
|
+
* @category response
|
|
473
|
+
* @since 4.0.0
|
|
474
|
+
*/
|
|
286
475
|
export interface UrlSourcePartMetadata extends ProviderMetadata {
|
|
476
|
+
/**
|
|
477
|
+
* Provider-specific URL citation metadata for OpenAI-compatible APIs.
|
|
478
|
+
*/
|
|
287
479
|
readonly openai?: {
|
|
480
|
+
/**
|
|
481
|
+
* Identifies a citation to a URL.
|
|
482
|
+
*/
|
|
288
483
|
readonly type: "url_citation"
|
|
289
484
|
/**
|
|
290
485
|
* The index of the first character of the URL citation in the message.
|
|
@@ -297,8 +492,20 @@ declare module "effect/unstable/ai/Response" {
|
|
|
297
492
|
} | null
|
|
298
493
|
}
|
|
299
494
|
|
|
495
|
+
/**
|
|
496
|
+
* OpenAI-compatible metadata attached to finish response parts.
|
|
497
|
+
*
|
|
498
|
+
* @category response
|
|
499
|
+
* @since 4.0.0
|
|
500
|
+
*/
|
|
300
501
|
export interface FinishPartMetadata extends ProviderMetadata {
|
|
502
|
+
/**
|
|
503
|
+
* Provider-specific metadata returned when generation finishes.
|
|
504
|
+
*/
|
|
301
505
|
readonly openai?: {
|
|
506
|
+
/**
|
|
507
|
+
* The service tier reported by the OpenAI-compatible provider.
|
|
508
|
+
*/
|
|
302
509
|
readonly serviceTier?: "default" | "auto" | "flex" | "scale" | "priority" | null
|
|
303
510
|
} | null
|
|
304
511
|
}
|
|
@@ -309,31 +516,56 @@ declare module "effect/unstable/ai/Response" {
|
|
|
309
516
|
// =============================================================================
|
|
310
517
|
|
|
311
518
|
/**
|
|
312
|
-
*
|
|
519
|
+
* Creates an OpenAI-compatible model descriptor that can be provided with `Effect.provide`.
|
|
520
|
+
*
|
|
521
|
+
* **When to use**
|
|
522
|
+
*
|
|
523
|
+
* Use when you want an OpenAI-compatible language model value that carries
|
|
524
|
+
* provider and model metadata and can be supplied directly to an Effect program.
|
|
525
|
+
*
|
|
526
|
+
* @see {@link layer} for creating a `LanguageModel.LanguageModel` layer directly
|
|
527
|
+
* @see {@link make} for constructing the language model service effectfully
|
|
528
|
+
*
|
|
313
529
|
* @category constructors
|
|
530
|
+
* @since 4.0.0
|
|
314
531
|
*/
|
|
315
532
|
export const model = (
|
|
316
533
|
model: string,
|
|
317
534
|
config?: Omit<typeof Config.Service, "model">
|
|
318
535
|
): AiModel.Model<"openai", LanguageModel.LanguageModel, OpenAiClient> =>
|
|
319
|
-
AiModel.make("openai", layer({ model, config }))
|
|
536
|
+
AiModel.make("openai", model, layer({ model, config }))
|
|
320
537
|
|
|
321
538
|
// TODO
|
|
322
539
|
// /**
|
|
323
|
-
// * @since
|
|
540
|
+
// * @since 4.0.0
|
|
324
541
|
// * @category constructors
|
|
325
542
|
// */
|
|
326
543
|
// export const modelWithTokenizer = (
|
|
327
544
|
// model: string,
|
|
328
545
|
// config?: Omit<typeof Config.Service, "model">
|
|
329
546
|
// ): AiModel.Model<"openai", LanguageModel.LanguageModel | Tokenizer.Tokenizer, OpenAiClient> =>
|
|
330
|
-
// AiModel.make("openai", layerWithTokenizer({ model, config }))
|
|
547
|
+
// AiModel.make("openai", model, layerWithTokenizer({ model, config }))
|
|
331
548
|
|
|
332
549
|
/**
|
|
333
|
-
* Creates an OpenAI
|
|
550
|
+
* Creates an OpenAI-compatible `LanguageModel` service from a model identifier and optional request defaults.
|
|
551
|
+
*
|
|
552
|
+
* **When to use**
|
|
553
|
+
*
|
|
554
|
+
* Use to construct an OpenAI-compatible chat-completions language model service
|
|
555
|
+
* backed by `OpenAiClient`.
|
|
556
|
+
*
|
|
557
|
+
* **Details**
|
|
558
|
+
*
|
|
559
|
+
* The returned effect requires `OpenAiClient`. Request defaults from the
|
|
560
|
+
* `config` option are merged with any `Config` service in the context, with
|
|
561
|
+
* context values taking precedence. The service supports both `generateText` and
|
|
562
|
+
* `streamText`.
|
|
563
|
+
*
|
|
564
|
+
* @see {@link layer} for providing the service as a `Layer`
|
|
565
|
+
* @see {@link model} for creating a model descriptor for `AiModel.provide`
|
|
334
566
|
*
|
|
335
|
-
* @since 1.0.0
|
|
336
567
|
* @category constructors
|
|
568
|
+
* @since 4.0.0
|
|
337
569
|
*/
|
|
338
570
|
export const make = Effect.fnUntraced(function*({ model, config: providerConfig }: {
|
|
339
571
|
readonly model: string
|
|
@@ -342,7 +574,7 @@ export const make = Effect.fnUntraced(function*({ model, config: providerConfig
|
|
|
342
574
|
const client = yield* OpenAiClient
|
|
343
575
|
|
|
344
576
|
const makeConfig = Effect.gen(function*() {
|
|
345
|
-
const services = yield* Effect.
|
|
577
|
+
const services = yield* Effect.context<never>()
|
|
346
578
|
return { model, ...providerConfig, ...services.mapUnsafe.get(Config.key) }
|
|
347
579
|
})
|
|
348
580
|
|
|
@@ -370,8 +602,9 @@ export const make = Effect.fnUntraced(function*({ model, config: providerConfig
|
|
|
370
602
|
config,
|
|
371
603
|
options
|
|
372
604
|
})
|
|
605
|
+
const { fileIdPrefixes: _fip, strictJsonSchema: _sjs, ...apiConfig } = config
|
|
373
606
|
const request: CreateResponse = {
|
|
374
|
-
...
|
|
607
|
+
...apiConfig,
|
|
375
608
|
input: messages,
|
|
376
609
|
include: include.size > 0 ? Array.from(include) : null,
|
|
377
610
|
text: {
|
|
@@ -386,6 +619,7 @@ export const make = Effect.fnUntraced(function*({ model, config: providerConfig
|
|
|
386
619
|
)
|
|
387
620
|
|
|
388
621
|
return yield* LanguageModel.make({
|
|
622
|
+
codecTransformer: toCodecOpenAI,
|
|
389
623
|
generateText: Effect.fnUntraced(
|
|
390
624
|
function*(options) {
|
|
391
625
|
const config = yield* makeConfig
|
|
@@ -423,17 +657,23 @@ export const make = Effect.fnUntraced(function*({ model, config: providerConfig
|
|
|
423
657
|
})
|
|
424
658
|
)
|
|
425
659
|
)
|
|
426
|
-
})
|
|
427
|
-
LanguageModel.CurrentCodecTransformer,
|
|
428
|
-
toCodecOpenAI
|
|
429
|
-
))
|
|
660
|
+
})
|
|
430
661
|
})
|
|
431
662
|
|
|
432
663
|
/**
|
|
433
|
-
* Creates a layer for the OpenAI language model.
|
|
664
|
+
* Creates a layer for the OpenAI-compatible language model.
|
|
665
|
+
*
|
|
666
|
+
* **When to use**
|
|
667
|
+
*
|
|
668
|
+
* Use when composing application layers and you want OpenAI-compatible APIs to
|
|
669
|
+
* satisfy `LanguageModel.LanguageModel` while supplying `OpenAiClient` from
|
|
670
|
+
* another layer.
|
|
671
|
+
*
|
|
672
|
+
* @see {@link make} for constructing the language model service effectfully
|
|
673
|
+
* @see {@link model} for creating an AI model descriptor
|
|
434
674
|
*
|
|
435
|
-
* @since 1.0.0
|
|
436
675
|
* @category layers
|
|
676
|
+
* @since 4.0.0
|
|
437
677
|
*/
|
|
438
678
|
export const layer = (options: {
|
|
439
679
|
readonly model: string
|
|
@@ -442,39 +682,99 @@ export const layer = (options: {
|
|
|
442
682
|
Layer.effect(LanguageModel.LanguageModel, make(options))
|
|
443
683
|
|
|
444
684
|
/**
|
|
445
|
-
* Provides config overrides for OpenAI language model operations.
|
|
685
|
+
* Provides scoped config overrides for OpenAI-compatible language model operations.
|
|
686
|
+
*
|
|
687
|
+
* **When to use**
|
|
688
|
+
*
|
|
689
|
+
* Use to override request configuration for a single language model effect
|
|
690
|
+
* without changing the defaults supplied to `model`, `make`, or `layer`.
|
|
691
|
+
*
|
|
692
|
+
* **Details**
|
|
693
|
+
*
|
|
694
|
+
* Existing `Config` values from the Effect context are merged with `overrides`,
|
|
695
|
+
* and the override values take precedence.
|
|
696
|
+
*
|
|
697
|
+
* @see {@link Config} for the configuration shape
|
|
446
698
|
*
|
|
447
|
-
* @since 1.0.0
|
|
448
699
|
* @category configuration
|
|
700
|
+
* @since 4.0.0
|
|
449
701
|
*/
|
|
450
702
|
export const withConfigOverride: {
|
|
451
703
|
/**
|
|
452
|
-
* Provides config overrides for OpenAI language model operations.
|
|
704
|
+
* Provides scoped config overrides for OpenAI-compatible language model operations.
|
|
705
|
+
*
|
|
706
|
+
* **When to use**
|
|
707
|
+
*
|
|
708
|
+
* Use to override request configuration for a single language model effect
|
|
709
|
+
* without changing the defaults supplied to `model`, `make`, or `layer`.
|
|
710
|
+
*
|
|
711
|
+
* **Details**
|
|
712
|
+
*
|
|
713
|
+
* Existing `Config` values from the Effect context are merged with `overrides`,
|
|
714
|
+
* and the override values take precedence.
|
|
715
|
+
*
|
|
716
|
+
* @see {@link Config} for the configuration shape
|
|
453
717
|
*
|
|
454
|
-
* @since 1.0.0
|
|
455
718
|
* @category configuration
|
|
719
|
+
* @since 4.0.0
|
|
456
720
|
*/
|
|
457
721
|
(overrides: typeof Config.Service): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Config>>
|
|
458
722
|
/**
|
|
459
|
-
* Provides config overrides for OpenAI language model operations.
|
|
723
|
+
* Provides scoped config overrides for OpenAI-compatible language model operations.
|
|
724
|
+
*
|
|
725
|
+
* **When to use**
|
|
726
|
+
*
|
|
727
|
+
* Use to override request configuration for a single language model effect
|
|
728
|
+
* without changing the defaults supplied to `model`, `make`, or `layer`.
|
|
729
|
+
*
|
|
730
|
+
* **Details**
|
|
731
|
+
*
|
|
732
|
+
* Existing `Config` values from the Effect context are merged with `overrides`,
|
|
733
|
+
* and the override values take precedence.
|
|
734
|
+
*
|
|
735
|
+
* @see {@link Config} for the configuration shape
|
|
460
736
|
*
|
|
461
|
-
* @since 1.0.0
|
|
462
737
|
* @category configuration
|
|
738
|
+
* @since 4.0.0
|
|
463
739
|
*/
|
|
464
740
|
<A, E, R>(self: Effect.Effect<A, E, R>, overrides: typeof Config.Service): Effect.Effect<A, E, Exclude<R, Config>>
|
|
465
741
|
} = dual<
|
|
466
742
|
/**
|
|
467
|
-
* Provides config overrides for OpenAI language model operations.
|
|
743
|
+
* Provides scoped config overrides for OpenAI-compatible language model operations.
|
|
744
|
+
*
|
|
745
|
+
* **When to use**
|
|
746
|
+
*
|
|
747
|
+
* Use to override request configuration for a single language model effect
|
|
748
|
+
* without changing the defaults supplied to `model`, `make`, or `layer`.
|
|
749
|
+
*
|
|
750
|
+
* **Details**
|
|
751
|
+
*
|
|
752
|
+
* Existing `Config` values from the Effect context are merged with `overrides`,
|
|
753
|
+
* and the override values take precedence.
|
|
754
|
+
*
|
|
755
|
+
* @see {@link Config} for the configuration shape
|
|
468
756
|
*
|
|
469
|
-
* @since 1.0.0
|
|
470
757
|
* @category configuration
|
|
758
|
+
* @since 4.0.0
|
|
471
759
|
*/
|
|
472
760
|
(overrides: typeof Config.Service) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Config>>,
|
|
473
761
|
/**
|
|
474
|
-
* Provides config overrides for OpenAI language model operations.
|
|
762
|
+
* Provides scoped config overrides for OpenAI-compatible language model operations.
|
|
763
|
+
*
|
|
764
|
+
* **When to use**
|
|
765
|
+
*
|
|
766
|
+
* Use to override request configuration for a single language model effect
|
|
767
|
+
* without changing the defaults supplied to `model`, `make`, or `layer`.
|
|
768
|
+
*
|
|
769
|
+
* **Details**
|
|
770
|
+
*
|
|
771
|
+
* Existing `Config` values from the Effect context are merged with `overrides`,
|
|
772
|
+
* and the override values take precedence.
|
|
773
|
+
*
|
|
774
|
+
* @see {@link Config} for the configuration shape
|
|
475
775
|
*
|
|
476
|
-
* @since 1.0.0
|
|
477
776
|
* @category configuration
|
|
777
|
+
* @since 4.0.0
|
|
478
778
|
*/
|
|
479
779
|
<A, E, R>(self: Effect.Effect<A, E, R>, overrides: typeof Config.Service) => Effect.Effect<A, E, Exclude<R, Config>>
|
|
480
780
|
>(2, (self, overrides) =>
|
|
@@ -782,7 +1082,7 @@ const buildHttpRequestDetails = (
|
|
|
782
1082
|
method: request.method,
|
|
783
1083
|
url: request.url,
|
|
784
1084
|
urlParams: Array.from(request.urlParams),
|
|
785
|
-
hash: request.hash,
|
|
1085
|
+
hash: Option.getOrUndefined(request.hash),
|
|
786
1086
|
headers: Redactable.redact(request.headers) as Record<string, string>
|
|
787
1087
|
})
|
|
788
1088
|
|
|
@@ -834,6 +1134,11 @@ const makeResponse = Effect.fnUntraced(
|
|
|
834
1134
|
const message = choice?.message
|
|
835
1135
|
|
|
836
1136
|
if (message !== undefined) {
|
|
1137
|
+
const reasoning = message.reasoning ?? message.reasoning_content
|
|
1138
|
+
if (Predicate.isNotNullish(reasoning) && reasoning.length > 0) {
|
|
1139
|
+
parts.push({ type: "reasoning", text: reasoning })
|
|
1140
|
+
}
|
|
1141
|
+
|
|
837
1142
|
if (
|
|
838
1143
|
message.content !== undefined && Predicate.isNotNull(message.content) && message.content.length > 0
|
|
839
1144
|
) {
|
|
@@ -907,6 +1212,8 @@ const makeStreamResponse = Effect.fnUntraced(
|
|
|
907
1212
|
let metadataEmitted = false
|
|
908
1213
|
let textStarted = false
|
|
909
1214
|
let textId = ""
|
|
1215
|
+
let reasoningStarted = false
|
|
1216
|
+
let reasoningId = ""
|
|
910
1217
|
let hasToolCalls = false
|
|
911
1218
|
const activeToolCalls: Record<number, ActiveToolCall> = {}
|
|
912
1219
|
|
|
@@ -915,6 +1222,14 @@ const makeStreamResponse = Effect.fnUntraced(
|
|
|
915
1222
|
const parts: Array<Response.StreamPartEncoded> = []
|
|
916
1223
|
|
|
917
1224
|
if (event === "[DONE]") {
|
|
1225
|
+
if (reasoningStarted) {
|
|
1226
|
+
parts.push({
|
|
1227
|
+
type: "reasoning-end",
|
|
1228
|
+
id: reasoningId,
|
|
1229
|
+
metadata: { openai: { ...makeItemIdMetadata(reasoningId) } }
|
|
1230
|
+
})
|
|
1231
|
+
}
|
|
1232
|
+
|
|
918
1233
|
if (textStarted) {
|
|
919
1234
|
parts.push({
|
|
920
1235
|
type: "text-end",
|
|
@@ -972,6 +1287,7 @@ const makeStreamResponse = Effect.fnUntraced(
|
|
|
972
1287
|
if (!metadataEmitted) {
|
|
973
1288
|
metadataEmitted = true
|
|
974
1289
|
textId = `${event.id}_message`
|
|
1290
|
+
reasoningId = `${event.id}_reasoning`
|
|
975
1291
|
parts.push({
|
|
976
1292
|
type: "response-metadata",
|
|
977
1293
|
id: event.id,
|
|
@@ -986,7 +1302,29 @@ const makeStreamResponse = Effect.fnUntraced(
|
|
|
986
1302
|
return parts
|
|
987
1303
|
}
|
|
988
1304
|
|
|
1305
|
+
const reasoningDelta = choice.delta?.reasoning ?? choice.delta?.reasoning_content
|
|
1306
|
+
if (Predicate.isNotNullish(reasoningDelta) && reasoningDelta.length > 0) {
|
|
1307
|
+
if (!reasoningStarted) {
|
|
1308
|
+
reasoningStarted = true
|
|
1309
|
+
parts.push({
|
|
1310
|
+
type: "reasoning-start",
|
|
1311
|
+
id: reasoningId,
|
|
1312
|
+
metadata: { openai: { ...makeItemIdMetadata(reasoningId) } }
|
|
1313
|
+
})
|
|
1314
|
+
}
|
|
1315
|
+
parts.push({ type: "reasoning-delta", id: reasoningId, delta: reasoningDelta })
|
|
1316
|
+
}
|
|
1317
|
+
|
|
989
1318
|
if (choice.delta?.content !== undefined && Predicate.isNotNull(choice.delta.content)) {
|
|
1319
|
+
if (reasoningStarted) {
|
|
1320
|
+
reasoningStarted = false
|
|
1321
|
+
parts.push({
|
|
1322
|
+
type: "reasoning-end",
|
|
1323
|
+
id: reasoningId,
|
|
1324
|
+
metadata: { openai: { ...makeItemIdMetadata(reasoningId) } }
|
|
1325
|
+
})
|
|
1326
|
+
}
|
|
1327
|
+
|
|
990
1328
|
if (!textStarted) {
|
|
991
1329
|
textStarted = true
|
|
992
1330
|
parts.push({
|
|
@@ -1002,11 +1340,13 @@ const makeStreamResponse = Effect.fnUntraced(
|
|
|
1002
1340
|
hasToolCalls = hasToolCalls || choice.delta.tool_calls.length > 0
|
|
1003
1341
|
choice.delta.tool_calls.forEach((deltaTool, indexInChunk) => {
|
|
1004
1342
|
const toolIndex = deltaTool.index ?? indexInChunk
|
|
1005
|
-
const
|
|
1343
|
+
const activeToolCall = activeToolCalls[toolIndex]
|
|
1344
|
+
const toolId = activeToolCall?.id ?? deltaTool.id ?? `${event.id}_tool_${toolIndex}`
|
|
1006
1345
|
const providerToolName = deltaTool.function?.name
|
|
1007
|
-
const toolName =
|
|
1346
|
+
const toolName = Predicate.isNotNullish(providerToolName)
|
|
1347
|
+
? toolNameMapper.getCustomName(providerToolName)
|
|
1348
|
+
: activeToolCall?.name ?? toolNameMapper.getCustomName("unknown_tool")
|
|
1008
1349
|
const argumentsDelta = deltaTool.function?.arguments ?? ""
|
|
1009
|
-
const activeToolCall = activeToolCalls[toolIndex]
|
|
1010
1350
|
|
|
1011
1351
|
if (Predicate.isUndefined(activeToolCall)) {
|
|
1012
1352
|
activeToolCalls[toolIndex] = {
|
|
@@ -1124,7 +1464,7 @@ const unsupportedSchemaError = (error: unknown, method: string): AiError.AiError
|
|
|
1124
1464
|
})
|
|
1125
1465
|
})
|
|
1126
1466
|
|
|
1127
|
-
const tryJsonSchema = <S extends Schema.
|
|
1467
|
+
const tryJsonSchema = <S extends Schema.Constraint>(schema: S, method: string) =>
|
|
1128
1468
|
Effect.try({
|
|
1129
1469
|
try: () => Tool.getJsonSchemaFromSchema(schema, { transformer: toCodecOpenAI }),
|
|
1130
1470
|
catch: (error) => unsupportedSchemaError(error, method)
|
|
@@ -1169,7 +1509,7 @@ const prepareTools = Effect.fnUntraced(function*<Tools extends ReadonlyArray<Too
|
|
|
1169
1509
|
|
|
1170
1510
|
// Convert the tools in the toolkit to the provider-defined format
|
|
1171
1511
|
for (const tool of allowedTools) {
|
|
1172
|
-
if (Tool.isUserDefined(tool)) {
|
|
1512
|
+
if (Tool.isUserDefined(tool) || Tool.isDynamic(tool)) {
|
|
1173
1513
|
const strict = Tool.getStrictMode(tool) ?? config.strictJsonSchema ?? true
|
|
1174
1514
|
const parameters = yield* tryToolJsonSchema(tool, "prepareTools")
|
|
1175
1515
|
tools.push({
|
|
@@ -1220,6 +1560,7 @@ const toChatCompletionsRequest = (payload: CreateResponse): CreateResponseReques
|
|
|
1220
1560
|
const toolChoice = toChatToolChoice(payload.tool_choice)
|
|
1221
1561
|
|
|
1222
1562
|
return {
|
|
1563
|
+
...extractCustomRequestProperties(payload),
|
|
1223
1564
|
model: payload.model ?? "",
|
|
1224
1565
|
messages: messages.length > 0 ? messages : [{ role: "user", content: "" }],
|
|
1225
1566
|
...(payload.temperature !== undefined ? { temperature: payload.temperature } : undefined),
|
|
@@ -1231,12 +1572,54 @@ const toChatCompletionsRequest = (payload: CreateResponse): CreateResponseReques
|
|
|
1231
1572
|
? { parallel_tool_calls: payload.parallel_tool_calls }
|
|
1232
1573
|
: undefined),
|
|
1233
1574
|
...(payload.service_tier !== undefined ? { service_tier: payload.service_tier } : undefined),
|
|
1575
|
+
...(payload.reasoning !== undefined ? { reasoning: payload.reasoning } : undefined),
|
|
1234
1576
|
...(responseFormat !== undefined ? { response_format: responseFormat } : undefined),
|
|
1235
1577
|
...(tools.length > 0 ? { tools } : undefined),
|
|
1236
1578
|
...(toolChoice !== undefined ? { tool_choice: toolChoice } : undefined)
|
|
1237
1579
|
}
|
|
1238
1580
|
}
|
|
1239
1581
|
|
|
1582
|
+
const createResponseKnownProperties = new Set<string>([
|
|
1583
|
+
"metadata",
|
|
1584
|
+
"top_logprobs",
|
|
1585
|
+
"temperature",
|
|
1586
|
+
"top_p",
|
|
1587
|
+
"user",
|
|
1588
|
+
"safety_identifier",
|
|
1589
|
+
"prompt_cache_key",
|
|
1590
|
+
"service_tier",
|
|
1591
|
+
"prompt_cache_retention",
|
|
1592
|
+
"previous_response_id",
|
|
1593
|
+
"model",
|
|
1594
|
+
"reasoning",
|
|
1595
|
+
"background",
|
|
1596
|
+
"max_output_tokens",
|
|
1597
|
+
"max_tool_calls",
|
|
1598
|
+
"text",
|
|
1599
|
+
"tools",
|
|
1600
|
+
"tool_choice",
|
|
1601
|
+
"truncation",
|
|
1602
|
+
"input",
|
|
1603
|
+
"include",
|
|
1604
|
+
"parallel_tool_calls",
|
|
1605
|
+
"store",
|
|
1606
|
+
"instructions",
|
|
1607
|
+
"stream",
|
|
1608
|
+
"conversation",
|
|
1609
|
+
"modalities",
|
|
1610
|
+
"seed"
|
|
1611
|
+
])
|
|
1612
|
+
|
|
1613
|
+
const extractCustomRequestProperties = (payload: CreateResponse): Record<string, unknown> => {
|
|
1614
|
+
const customProperties: Record<string, unknown> = {}
|
|
1615
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
1616
|
+
if (!createResponseKnownProperties.has(key)) {
|
|
1617
|
+
customProperties[key] = value
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
return customProperties
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1240
1623
|
const toChatResponseFormat = (
|
|
1241
1624
|
format: TextResponseFormatConfiguration | undefined
|
|
1242
1625
|
): CreateResponseRequestJson["response_format"] | undefined => {
|