@effect/ai-openai-compat 4.0.0-beta.7 → 4.0.0-beta.70

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 (38) hide show
  1. package/dist/OpenAiClient.d.ts +198 -50
  2. package/dist/OpenAiClient.d.ts.map +1 -1
  3. package/dist/OpenAiClient.js +57 -9
  4. package/dist/OpenAiClient.js.map +1 -1
  5. package/dist/OpenAiConfig.d.ts +76 -10
  6. package/dist/OpenAiConfig.d.ts.map +1 -1
  7. package/dist/OpenAiConfig.js +44 -7
  8. package/dist/OpenAiConfig.js.map +1 -1
  9. package/dist/OpenAiEmbeddingModel.d.ts +90 -0
  10. package/dist/OpenAiEmbeddingModel.d.ts.map +1 -0
  11. package/dist/OpenAiEmbeddingModel.js +122 -0
  12. package/dist/OpenAiEmbeddingModel.js.map +1 -0
  13. package/dist/OpenAiError.d.ts +109 -35
  14. package/dist/OpenAiError.d.ts.map +1 -1
  15. package/dist/OpenAiError.js +14 -1
  16. package/dist/OpenAiLanguageModel.d.ts +219 -13
  17. package/dist/OpenAiLanguageModel.d.ts.map +1 -1
  18. package/dist/OpenAiLanguageModel.js +42 -19
  19. package/dist/OpenAiLanguageModel.js.map +1 -1
  20. package/dist/OpenAiTelemetry.d.ts +35 -23
  21. package/dist/OpenAiTelemetry.d.ts.map +1 -1
  22. package/dist/OpenAiTelemetry.js +6 -4
  23. package/dist/OpenAiTelemetry.js.map +1 -1
  24. package/dist/index.d.ts +70 -6
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +70 -6
  27. package/dist/index.js.map +1 -1
  28. package/dist/internal/errors.js +4 -4
  29. package/dist/internal/errors.js.map +1 -1
  30. package/package.json +3 -3
  31. package/src/OpenAiClient.ts +232 -49
  32. package/src/OpenAiConfig.ts +77 -11
  33. package/src/OpenAiEmbeddingModel.ts +208 -0
  34. package/src/OpenAiError.ts +111 -35
  35. package/src/OpenAiLanguageModel.ts +273 -30
  36. package/src/OpenAiTelemetry.ts +36 -24
  37. package/src/index.ts +71 -6
  38. package/src/internal/errors.ts +4 -4
@@ -4,18 +4,19 @@
4
4
  * Provides a LanguageModel implementation for OpenAI's chat completions API,
5
5
  * supporting text generation, structured output, tool calling, and streaming.
6
6
  *
7
- * @since 1.0.0
7
+ * @since 4.0.0
8
8
  */
9
+ import * as Context from "effect/Context"
9
10
  import * as DateTime from "effect/DateTime"
10
11
  import * as Effect from "effect/Effect"
11
12
  import * as Encoding from "effect/Encoding"
12
13
  import { dual } from "effect/Function"
13
14
  import * as Layer from "effect/Layer"
15
+ import * as Option from "effect/Option"
14
16
  import * as Predicate from "effect/Predicate"
15
17
  import * as Redactable from "effect/Redactable"
16
18
  import type * as Schema from "effect/Schema"
17
19
  import * as AST from "effect/SchemaAST"
18
- import * as ServiceMap from "effect/ServiceMap"
19
20
  import * as Stream from "effect/Stream"
20
21
  import type { Span } from "effect/Tracer"
21
22
  import type { DeepMutable, Simplify } from "effect/Types"
@@ -60,10 +61,10 @@ type ImageDetail = "auto" | "low" | "high"
60
61
  /**
61
62
  * Service definition for OpenAI language model configuration.
62
63
  *
63
- * @since 1.0.0
64
64
  * @category context
65
+ * @since 4.0.0
65
66
  */
66
- export class Config extends ServiceMap.Service<
67
+ export class Config extends Context.Service<
67
68
  Config,
68
69
  Simplify<
69
70
  & Partial<
@@ -101,6 +102,7 @@ export class Config extends ServiceMap.Service<
101
102
  * Defaults to `true`.
102
103
  */
103
104
  readonly strictJsonSchema?: boolean | undefined
105
+ readonly [x: string]: unknown
104
106
  }
105
107
  >
106
108
  >()("@effect/ai-openai-compat/OpenAiLanguageModel/Config") {}
@@ -110,7 +112,16 @@ export class Config extends ServiceMap.Service<
110
112
  // =============================================================================
111
113
 
112
114
  declare module "effect/unstable/ai/Prompt" {
115
+ /**
116
+ * OpenAI-compatible options for file prompt parts.
117
+ *
118
+ * @category request
119
+ * @since 4.0.0
120
+ */
113
121
  export interface FilePartOptions extends ProviderOptions {
122
+ /**
123
+ * Provider-specific file options for OpenAI-compatible APIs.
124
+ */
114
125
  readonly openai?: {
115
126
  /**
116
127
  * The detail level of the image to be sent to the model. One of `high`, `low`, or `auto`. Defaults to `auto`.
@@ -119,7 +130,16 @@ declare module "effect/unstable/ai/Prompt" {
119
130
  } | null
120
131
  }
121
132
 
133
+ /**
134
+ * OpenAI-compatible options for reasoning prompt parts.
135
+ *
136
+ * @category request
137
+ * @since 4.0.0
138
+ */
122
139
  export interface ReasoningPartOptions extends ProviderOptions {
140
+ /**
141
+ * Provider-specific reasoning options for OpenAI-compatible APIs.
142
+ */
123
143
  readonly openai?: {
124
144
  /**
125
145
  * The ID of the item to reference.
@@ -134,40 +154,67 @@ declare module "effect/unstable/ai/Prompt" {
134
154
  } | null
135
155
  }
136
156
 
157
+ /**
158
+ * OpenAI-compatible options for assistant tool-call prompt parts.
159
+ *
160
+ * @category request
161
+ * @since 4.0.0
162
+ */
137
163
  export interface ToolCallPartOptions extends ProviderOptions {
164
+ /**
165
+ * Provider-specific tool-call options for OpenAI-compatible APIs.
166
+ */
138
167
  readonly openai?: {
139
168
  /**
140
169
  * The ID of the item to reference.
141
170
  */
142
171
  readonly itemId?: string | null
143
172
  /**
144
- * The status of item.
173
+ * The status to send for the tool-call item.
145
174
  */
146
175
  readonly status?: MessageStatus | null
147
176
  } | null
148
177
  }
149
178
 
179
+ /**
180
+ * OpenAI-compatible options for tool-result prompt parts.
181
+ *
182
+ * @category request
183
+ * @since 4.0.0
184
+ */
150
185
  export interface ToolResultPartOptions extends ProviderOptions {
186
+ /**
187
+ * Provider-specific tool-result options for OpenAI-compatible APIs.
188
+ */
151
189
  readonly openai?: {
152
190
  /**
153
191
  * The ID of the item to reference.
154
192
  */
155
193
  readonly itemId?: string | null
156
194
  /**
157
- * The status of item.
195
+ * The status to send for the tool-result item.
158
196
  */
159
197
  readonly status?: MessageStatus | null
160
198
  } | null
161
199
  }
162
200
 
201
+ /**
202
+ * OpenAI-compatible options for text prompt parts.
203
+ *
204
+ * @category request
205
+ * @since 4.0.0
206
+ */
163
207
  export interface TextPartOptions extends ProviderOptions {
208
+ /**
209
+ * Provider-specific text options for OpenAI-compatible APIs.
210
+ */
164
211
  readonly openai?: {
165
212
  /**
166
213
  * The ID of the item to reference.
167
214
  */
168
215
  readonly itemId?: string | null
169
216
  /**
170
- * The status of item.
217
+ * The status to send for the text item.
171
218
  */
172
219
  readonly status?: MessageStatus | null
173
220
  /**
@@ -179,8 +226,20 @@ declare module "effect/unstable/ai/Prompt" {
179
226
  }
180
227
 
181
228
  declare module "effect/unstable/ai/Response" {
229
+ /**
230
+ * OpenAI-compatible metadata attached to a complete text response part.
231
+ *
232
+ * @category response
233
+ * @since 4.0.0
234
+ */
182
235
  export interface TextPartMetadata extends ProviderMetadata {
236
+ /**
237
+ * Provider-specific metadata returned for the text part.
238
+ */
183
239
  readonly openai?: {
240
+ /**
241
+ * The OpenAI item ID associated with the text part.
242
+ */
184
243
  readonly itemId?: string | null
185
244
  /**
186
245
  * If the model emits a refusal content part, the refusal explanation
@@ -189,7 +248,7 @@ declare module "effect/unstable/ai/Response" {
189
248
  */
190
249
  readonly refusal?: string | null
191
250
  /**
192
- * The status of item.
251
+ * The status returned for the text item.
193
252
  */
194
253
  readonly status?: MessageStatus | null
195
254
  /**
@@ -199,55 +258,163 @@ declare module "effect/unstable/ai/Response" {
199
258
  }
200
259
  }
201
260
 
261
+ /**
262
+ * OpenAI-compatible metadata emitted when a streamed text part starts.
263
+ *
264
+ * @category response
265
+ * @since 4.0.0
266
+ */
202
267
  export interface TextStartPartMetadata extends ProviderMetadata {
268
+ /**
269
+ * Provider-specific metadata returned for the streamed text start.
270
+ */
203
271
  readonly openai?: {
272
+ /**
273
+ * The OpenAI item ID associated with the streamed text part.
274
+ */
204
275
  readonly itemId?: string | null
205
276
  } | null
206
277
  }
207
278
 
279
+ /**
280
+ * OpenAI-compatible metadata emitted when a streamed text part ends.
281
+ *
282
+ * @category response
283
+ * @since 4.0.0
284
+ */
208
285
  export interface TextEndPartMetadata extends ProviderMetadata {
286
+ /**
287
+ * Provider-specific metadata returned for the streamed text end.
288
+ */
209
289
  readonly openai?: {
290
+ /**
291
+ * The OpenAI item ID associated with the streamed text part.
292
+ */
210
293
  readonly itemId?: string | null
294
+ /**
295
+ * The annotations collected for the completed streamed text part.
296
+ */
211
297
  readonly annotations?: ReadonlyArray<Annotation> | null
212
298
  } | null
213
299
  }
214
300
 
301
+ /**
302
+ * OpenAI-compatible metadata attached to a complete reasoning response part.
303
+ *
304
+ * @category response
305
+ * @since 4.0.0
306
+ */
215
307
  export interface ReasoningPartMetadata extends ProviderMetadata {
308
+ /**
309
+ * Provider-specific metadata returned for the reasoning part.
310
+ */
216
311
  readonly openai?: {
312
+ /**
313
+ * The OpenAI item ID associated with the reasoning part.
314
+ */
217
315
  readonly itemId?: string | null
316
+ /**
317
+ * Encrypted reasoning content that can be sent back in later requests.
318
+ */
218
319
  readonly encryptedContent?: string | null
219
320
  } | null
220
321
  }
221
322
 
323
+ /**
324
+ * OpenAI-compatible metadata emitted when a streamed reasoning part starts.
325
+ *
326
+ * @category response
327
+ * @since 4.0.0
328
+ */
222
329
  export interface ReasoningStartPartMetadata extends ProviderMetadata {
330
+ /**
331
+ * Provider-specific metadata returned for the streamed reasoning start.
332
+ */
223
333
  readonly openai?: {
334
+ /**
335
+ * The OpenAI item ID associated with the reasoning part.
336
+ */
224
337
  readonly itemId?: string | null
338
+ /**
339
+ * Encrypted reasoning content that can be sent back in later requests.
340
+ */
225
341
  readonly encryptedContent?: string | null
226
342
  } | null
227
343
  }
228
344
 
345
+ /**
346
+ * OpenAI-compatible metadata emitted for a streamed reasoning delta.
347
+ *
348
+ * @category response
349
+ * @since 4.0.0
350
+ */
229
351
  export interface ReasoningDeltaPartMetadata extends ProviderMetadata {
352
+ /**
353
+ * Provider-specific metadata returned for the streamed reasoning delta.
354
+ */
230
355
  readonly openai?: {
356
+ /**
357
+ * The OpenAI item ID associated with the reasoning part.
358
+ */
231
359
  readonly itemId?: string | null
232
360
  } | null
233
361
  }
234
362
 
363
+ /**
364
+ * OpenAI-compatible metadata emitted when a streamed reasoning part ends.
365
+ *
366
+ * @category response
367
+ * @since 4.0.0
368
+ */
235
369
  export interface ReasoningEndPartMetadata extends ProviderMetadata {
370
+ /**
371
+ * Provider-specific metadata returned for the streamed reasoning end.
372
+ */
236
373
  readonly openai?: {
374
+ /**
375
+ * The OpenAI item ID associated with the reasoning part.
376
+ */
237
377
  readonly itemId?: string | null
378
+ /**
379
+ * Encrypted reasoning content that can be sent back in later requests.
380
+ */
238
381
  readonly encryptedContent?: string
239
382
  } | null
240
383
  }
241
384
 
385
+ /**
386
+ * OpenAI-compatible metadata attached to tool-call response parts.
387
+ *
388
+ * @category response
389
+ * @since 4.0.0
390
+ */
242
391
  export interface ToolCallPartMetadata extends ProviderMetadata {
392
+ /**
393
+ * Provider-specific metadata returned for the tool call.
394
+ */
243
395
  readonly openai?: {
396
+ /**
397
+ * The OpenAI item ID associated with the tool call.
398
+ */
244
399
  readonly itemId?: string | null
245
400
  } | null
246
401
  }
247
402
 
403
+ /**
404
+ * OpenAI-compatible metadata attached to document source citations.
405
+ *
406
+ * @category response
407
+ * @since 4.0.0
408
+ */
248
409
  export interface DocumentSourcePartMetadata extends ProviderMetadata {
410
+ /**
411
+ * Provider-specific citation metadata for OpenAI-compatible APIs.
412
+ */
249
413
  readonly openai?:
250
414
  | {
415
+ /**
416
+ * Identifies a citation to an uploaded file.
417
+ */
251
418
  readonly type: "file_citation"
252
419
  /**
253
420
  * The index of the file in the list of files.
@@ -259,6 +426,9 @@ declare module "effect/unstable/ai/Response" {
259
426
  readonly fileId: string
260
427
  }
261
428
  | {
429
+ /**
430
+ * Identifies a citation to a generated file path.
431
+ */
262
432
  readonly type: "file_path"
263
433
  /**
264
434
  * The index of the file in the list of files.
@@ -270,6 +440,9 @@ declare module "effect/unstable/ai/Response" {
270
440
  readonly fileId: string
271
441
  }
272
442
  | {
443
+ /**
444
+ * Identifies a citation to a file inside a container.
445
+ */
273
446
  readonly type: "container_file_citation"
274
447
  /**
275
448
  * The ID of the file.
@@ -283,8 +456,20 @@ declare module "effect/unstable/ai/Response" {
283
456
  | null
284
457
  }
285
458
 
459
+ /**
460
+ * OpenAI-compatible metadata attached to URL source citations.
461
+ *
462
+ * @category response
463
+ * @since 4.0.0
464
+ */
286
465
  export interface UrlSourcePartMetadata extends ProviderMetadata {
466
+ /**
467
+ * Provider-specific URL citation metadata for OpenAI-compatible APIs.
468
+ */
287
469
  readonly openai?: {
470
+ /**
471
+ * Identifies a citation to a URL.
472
+ */
288
473
  readonly type: "url_citation"
289
474
  /**
290
475
  * The index of the first character of the URL citation in the message.
@@ -297,8 +482,20 @@ declare module "effect/unstable/ai/Response" {
297
482
  } | null
298
483
  }
299
484
 
485
+ /**
486
+ * OpenAI-compatible metadata attached to finish response parts.
487
+ *
488
+ * @category response
489
+ * @since 4.0.0
490
+ */
300
491
  export interface FinishPartMetadata extends ProviderMetadata {
492
+ /**
493
+ * Provider-specific metadata returned when generation finishes.
494
+ */
301
495
  readonly openai?: {
496
+ /**
497
+ * The service tier reported by the OpenAI-compatible provider.
498
+ */
302
499
  readonly serviceTier?: "default" | "auto" | "flex" | "scale" | "priority" | null
303
500
  } | null
304
501
  }
@@ -309,31 +506,33 @@ declare module "effect/unstable/ai/Response" {
309
506
  // =============================================================================
310
507
 
311
508
  /**
312
- * @since 1.0.0
509
+ * Creates an AI model descriptor for an OpenAI-compatible language model.
510
+ *
313
511
  * @category constructors
512
+ * @since 4.0.0
314
513
  */
315
514
  export const model = (
316
515
  model: string,
317
516
  config?: Omit<typeof Config.Service, "model">
318
517
  ): AiModel.Model<"openai", LanguageModel.LanguageModel, OpenAiClient> =>
319
- AiModel.make("openai", layer({ model, config }))
518
+ AiModel.make("openai", model, layer({ model, config }))
320
519
 
321
520
  // TODO
322
521
  // /**
323
- // * @since 1.0.0
522
+ // * @since 4.0.0
324
523
  // * @category constructors
325
524
  // */
326
525
  // export const modelWithTokenizer = (
327
526
  // model: string,
328
527
  // config?: Omit<typeof Config.Service, "model">
329
528
  // ): AiModel.Model<"openai", LanguageModel.LanguageModel | Tokenizer.Tokenizer, OpenAiClient> =>
330
- // AiModel.make("openai", layerWithTokenizer({ model, config }))
529
+ // AiModel.make("openai", model, layerWithTokenizer({ model, config }))
331
530
 
332
531
  /**
333
532
  * Creates an OpenAI language model service.
334
533
  *
335
- * @since 1.0.0
336
534
  * @category constructors
535
+ * @since 4.0.0
337
536
  */
338
537
  export const make = Effect.fnUntraced(function*({ model, config: providerConfig }: {
339
538
  readonly model: string
@@ -342,7 +541,7 @@ export const make = Effect.fnUntraced(function*({ model, config: providerConfig
342
541
  const client = yield* OpenAiClient
343
542
 
344
543
  const makeConfig = Effect.gen(function*() {
345
- const services = yield* Effect.services<never>()
544
+ const services = yield* Effect.context<never>()
346
545
  return { model, ...providerConfig, ...services.mapUnsafe.get(Config.key) }
347
546
  })
348
547
 
@@ -370,8 +569,9 @@ export const make = Effect.fnUntraced(function*({ model, config: providerConfig
370
569
  config,
371
570
  options
372
571
  })
572
+ const { fileIdPrefixes: _fip, strictJsonSchema: _sjs, ...apiConfig } = config
373
573
  const request: CreateResponse = {
374
- ...config,
574
+ ...apiConfig,
375
575
  input: messages,
376
576
  include: include.size > 0 ? Array.from(include) : null,
377
577
  text: {
@@ -386,6 +586,7 @@ export const make = Effect.fnUntraced(function*({ model, config: providerConfig
386
586
  )
387
587
 
388
588
  return yield* LanguageModel.make({
589
+ codecTransformer: toCodecOpenAI,
389
590
  generateText: Effect.fnUntraced(
390
591
  function*(options) {
391
592
  const config = yield* makeConfig
@@ -423,17 +624,14 @@ export const make = Effect.fnUntraced(function*({ model, config: providerConfig
423
624
  })
424
625
  )
425
626
  )
426
- }).pipe(Effect.provideService(
427
- LanguageModel.CurrentCodecTransformer,
428
- toCodecOpenAI
429
- ))
627
+ })
430
628
  })
431
629
 
432
630
  /**
433
631
  * Creates a layer for the OpenAI language model.
434
632
  *
435
- * @since 1.0.0
436
633
  * @category layers
634
+ * @since 4.0.0
437
635
  */
438
636
  export const layer = (options: {
439
637
  readonly model: string
@@ -444,37 +642,37 @@ export const layer = (options: {
444
642
  /**
445
643
  * Provides config overrides for OpenAI language model operations.
446
644
  *
447
- * @since 1.0.0
448
645
  * @category configuration
646
+ * @since 4.0.0
449
647
  */
450
648
  export const withConfigOverride: {
451
649
  /**
452
650
  * Provides config overrides for OpenAI language model operations.
453
651
  *
454
- * @since 1.0.0
455
652
  * @category configuration
653
+ * @since 4.0.0
456
654
  */
457
655
  (overrides: typeof Config.Service): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Config>>
458
656
  /**
459
657
  * Provides config overrides for OpenAI language model operations.
460
658
  *
461
- * @since 1.0.0
462
659
  * @category configuration
660
+ * @since 4.0.0
463
661
  */
464
662
  <A, E, R>(self: Effect.Effect<A, E, R>, overrides: typeof Config.Service): Effect.Effect<A, E, Exclude<R, Config>>
465
663
  } = dual<
466
664
  /**
467
665
  * Provides config overrides for OpenAI language model operations.
468
666
  *
469
- * @since 1.0.0
470
667
  * @category configuration
668
+ * @since 4.0.0
471
669
  */
472
670
  (overrides: typeof Config.Service) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Config>>,
473
671
  /**
474
672
  * Provides config overrides for OpenAI language model operations.
475
673
  *
476
- * @since 1.0.0
477
674
  * @category configuration
675
+ * @since 4.0.0
478
676
  */
479
677
  <A, E, R>(self: Effect.Effect<A, E, R>, overrides: typeof Config.Service) => Effect.Effect<A, E, Exclude<R, Config>>
480
678
  >(2, (self, overrides) =>
@@ -782,7 +980,7 @@ const buildHttpRequestDetails = (
782
980
  method: request.method,
783
981
  url: request.url,
784
982
  urlParams: Array.from(request.urlParams),
785
- hash: request.hash,
983
+ hash: Option.getOrUndefined(request.hash),
786
984
  headers: Redactable.redact(request.headers) as Record<string, string>
787
985
  })
788
986
 
@@ -1002,11 +1200,13 @@ const makeStreamResponse = Effect.fnUntraced(
1002
1200
  hasToolCalls = hasToolCalls || choice.delta.tool_calls.length > 0
1003
1201
  choice.delta.tool_calls.forEach((deltaTool, indexInChunk) => {
1004
1202
  const toolIndex = deltaTool.index ?? indexInChunk
1005
- const toolId = deltaTool.id ?? `${event.id}_tool_${toolIndex}`
1203
+ const activeToolCall = activeToolCalls[toolIndex]
1204
+ const toolId = activeToolCall?.id ?? deltaTool.id ?? `${event.id}_tool_${toolIndex}`
1006
1205
  const providerToolName = deltaTool.function?.name
1007
- const toolName = toolNameMapper.getCustomName(providerToolName ?? "unknown_tool")
1206
+ const toolName = providerToolName !== undefined
1207
+ ? toolNameMapper.getCustomName(providerToolName)
1208
+ : activeToolCall?.name ?? toolNameMapper.getCustomName("unknown_tool")
1008
1209
  const argumentsDelta = deltaTool.function?.arguments ?? ""
1009
- const activeToolCall = activeToolCalls[toolIndex]
1010
1210
 
1011
1211
  if (Predicate.isUndefined(activeToolCall)) {
1012
1212
  activeToolCalls[toolIndex] = {
@@ -1169,7 +1369,7 @@ const prepareTools = Effect.fnUntraced(function*<Tools extends ReadonlyArray<Too
1169
1369
 
1170
1370
  // Convert the tools in the toolkit to the provider-defined format
1171
1371
  for (const tool of allowedTools) {
1172
- if (Tool.isUserDefined(tool)) {
1372
+ if (Tool.isUserDefined(tool) || Tool.isDynamic(tool)) {
1173
1373
  const strict = Tool.getStrictMode(tool) ?? config.strictJsonSchema ?? true
1174
1374
  const parameters = yield* tryToolJsonSchema(tool, "prepareTools")
1175
1375
  tools.push({
@@ -1220,6 +1420,7 @@ const toChatCompletionsRequest = (payload: CreateResponse): CreateResponseReques
1220
1420
  const toolChoice = toChatToolChoice(payload.tool_choice)
1221
1421
 
1222
1422
  return {
1423
+ ...extractCustomRequestProperties(payload),
1223
1424
  model: payload.model ?? "",
1224
1425
  messages: messages.length > 0 ? messages : [{ role: "user", content: "" }],
1225
1426
  ...(payload.temperature !== undefined ? { temperature: payload.temperature } : undefined),
@@ -1231,12 +1432,54 @@ const toChatCompletionsRequest = (payload: CreateResponse): CreateResponseReques
1231
1432
  ? { parallel_tool_calls: payload.parallel_tool_calls }
1232
1433
  : undefined),
1233
1434
  ...(payload.service_tier !== undefined ? { service_tier: payload.service_tier } : undefined),
1435
+ ...(payload.reasoning !== undefined ? { reasoning: payload.reasoning } : undefined),
1234
1436
  ...(responseFormat !== undefined ? { response_format: responseFormat } : undefined),
1235
1437
  ...(tools.length > 0 ? { tools } : undefined),
1236
1438
  ...(toolChoice !== undefined ? { tool_choice: toolChoice } : undefined)
1237
1439
  }
1238
1440
  }
1239
1441
 
1442
+ const createResponseKnownProperties = new Set<string>([
1443
+ "metadata",
1444
+ "top_logprobs",
1445
+ "temperature",
1446
+ "top_p",
1447
+ "user",
1448
+ "safety_identifier",
1449
+ "prompt_cache_key",
1450
+ "service_tier",
1451
+ "prompt_cache_retention",
1452
+ "previous_response_id",
1453
+ "model",
1454
+ "reasoning",
1455
+ "background",
1456
+ "max_output_tokens",
1457
+ "max_tool_calls",
1458
+ "text",
1459
+ "tools",
1460
+ "tool_choice",
1461
+ "truncation",
1462
+ "input",
1463
+ "include",
1464
+ "parallel_tool_calls",
1465
+ "store",
1466
+ "instructions",
1467
+ "stream",
1468
+ "conversation",
1469
+ "modalities",
1470
+ "seed"
1471
+ ])
1472
+
1473
+ const extractCustomRequestProperties = (payload: CreateResponse): Record<string, unknown> => {
1474
+ const customProperties: Record<string, unknown> = {}
1475
+ for (const [key, value] of Object.entries(payload)) {
1476
+ if (!createResponseKnownProperties.has(key)) {
1477
+ customProperties[key] = value
1478
+ }
1479
+ }
1480
+ return customProperties
1481
+ }
1482
+
1240
1483
  const toChatResponseFormat = (
1241
1484
  format: TextResponseFormatConfiguration | undefined
1242
1485
  ): CreateResponseRequestJson["response_format"] | undefined => {