openai 6.47.0 → 6.49.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 (212) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/azure.d.mts.map +1 -1
  3. package/azure.d.ts.map +1 -1
  4. package/azure.js +5 -1
  5. package/azure.js.map +1 -1
  6. package/azure.mjs +5 -1
  7. package/azure.mjs.map +1 -1
  8. package/helpers/standard-schema.d.mts +104 -0
  9. package/helpers/standard-schema.d.mts.map +1 -0
  10. package/helpers/standard-schema.d.ts +104 -0
  11. package/helpers/standard-schema.d.ts.map +1 -0
  12. package/helpers/standard-schema.js +320 -0
  13. package/helpers/standard-schema.js.map +1 -0
  14. package/helpers/standard-schema.mjs +314 -0
  15. package/helpers/standard-schema.mjs.map +1 -0
  16. package/helpers/zod.d.mts +26 -3
  17. package/helpers/zod.d.mts.map +1 -1
  18. package/helpers/zod.d.ts +26 -3
  19. package/helpers/zod.d.ts.map +1 -1
  20. package/helpers/zod.js +97 -7
  21. package/helpers/zod.js.map +1 -1
  22. package/helpers/zod.mjs +96 -7
  23. package/helpers/zod.mjs.map +1 -1
  24. package/internal/headers.d.mts.map +1 -1
  25. package/internal/headers.d.ts.map +1 -1
  26. package/internal/headers.js +7 -3
  27. package/internal/headers.js.map +1 -1
  28. package/internal/headers.mjs +7 -3
  29. package/internal/headers.mjs.map +1 -1
  30. package/lib/AbstractChatCompletionRunner.d.mts.map +1 -1
  31. package/lib/AbstractChatCompletionRunner.d.ts.map +1 -1
  32. package/lib/AbstractChatCompletionRunner.js +43 -1
  33. package/lib/AbstractChatCompletionRunner.js.map +1 -1
  34. package/lib/AbstractChatCompletionRunner.mjs +43 -1
  35. package/lib/AbstractChatCompletionRunner.mjs.map +1 -1
  36. package/lib/ChatCompletionStream.d.mts +2 -1
  37. package/lib/ChatCompletionStream.d.mts.map +1 -1
  38. package/lib/ChatCompletionStream.d.ts +2 -1
  39. package/lib/ChatCompletionStream.d.ts.map +1 -1
  40. package/lib/ChatCompletionStream.js +53 -14
  41. package/lib/ChatCompletionStream.js.map +1 -1
  42. package/lib/ChatCompletionStream.mjs +53 -14
  43. package/lib/ChatCompletionStream.mjs.map +1 -1
  44. package/lib/ResponsesParser.d.mts.map +1 -1
  45. package/lib/ResponsesParser.d.ts.map +1 -1
  46. package/lib/ResponsesParser.js +3 -5
  47. package/lib/ResponsesParser.js.map +1 -1
  48. package/lib/ResponsesParser.mjs +3 -5
  49. package/lib/ResponsesParser.mjs.map +1 -1
  50. package/lib/jsonschema.d.mts +3 -0
  51. package/lib/jsonschema.d.mts.map +1 -1
  52. package/lib/jsonschema.d.ts +3 -0
  53. package/lib/jsonschema.d.ts.map +1 -1
  54. package/lib/transform.d.mts +25 -1
  55. package/lib/transform.d.mts.map +1 -1
  56. package/lib/transform.d.ts +25 -1
  57. package/lib/transform.d.ts.map +1 -1
  58. package/lib/transform.js +1521 -82
  59. package/lib/transform.js.map +1 -1
  60. package/lib/transform.mjs +1515 -82
  61. package/lib/transform.mjs.map +1 -1
  62. package/package.json +1 -1
  63. package/resources/admin/organization/audit-logs.d.mts +2 -2
  64. package/resources/admin/organization/audit-logs.d.mts.map +1 -1
  65. package/resources/admin/organization/audit-logs.d.ts +2 -2
  66. package/resources/admin/organization/audit-logs.d.ts.map +1 -1
  67. package/resources/admin/organization/index.d.mts +1 -0
  68. package/resources/admin/organization/index.d.mts.map +1 -1
  69. package/resources/admin/organization/index.d.ts +1 -0
  70. package/resources/admin/organization/index.d.ts.map +1 -1
  71. package/resources/admin/organization/index.js +3 -1
  72. package/resources/admin/organization/index.js.map +1 -1
  73. package/resources/admin/organization/index.mjs +1 -0
  74. package/resources/admin/organization/index.mjs.map +1 -1
  75. package/resources/admin/organization/organization.d.mts +4 -0
  76. package/resources/admin/organization/organization.d.mts.map +1 -1
  77. package/resources/admin/organization/organization.d.ts +4 -0
  78. package/resources/admin/organization/organization.d.ts.map +1 -1
  79. package/resources/admin/organization/organization.js +4 -0
  80. package/resources/admin/organization/organization.js.map +1 -1
  81. package/resources/admin/organization/organization.mjs +4 -0
  82. package/resources/admin/organization/organization.mjs.map +1 -1
  83. package/resources/admin/organization/projects/index.d.mts +2 -1
  84. package/resources/admin/organization/projects/index.d.mts.map +1 -1
  85. package/resources/admin/organization/projects/index.d.ts +2 -1
  86. package/resources/admin/organization/projects/index.d.ts.map +1 -1
  87. package/resources/admin/organization/projects/index.js +7 -5
  88. package/resources/admin/organization/projects/index.js.map +1 -1
  89. package/resources/admin/organization/projects/index.mjs +2 -1
  90. package/resources/admin/organization/projects/index.mjs.map +1 -1
  91. package/resources/admin/organization/projects/projects.d.mts +6 -2
  92. package/resources/admin/organization/projects/projects.d.mts.map +1 -1
  93. package/resources/admin/organization/projects/projects.d.ts +6 -2
  94. package/resources/admin/organization/projects/projects.d.ts.map +1 -1
  95. package/resources/admin/organization/projects/projects.js +6 -2
  96. package/resources/admin/organization/projects/projects.js.map +1 -1
  97. package/resources/admin/organization/projects/projects.mjs +6 -2
  98. package/resources/admin/organization/projects/projects.mjs.map +1 -1
  99. package/resources/admin/organization/projects/service-accounts/api-keys.d.mts +58 -0
  100. package/resources/admin/organization/projects/service-accounts/api-keys.d.mts.map +1 -0
  101. package/resources/admin/organization/projects/service-accounts/api-keys.d.ts +58 -0
  102. package/resources/admin/organization/projects/service-accounts/api-keys.d.ts.map +1 -0
  103. package/resources/admin/organization/projects/service-accounts/api-keys.js +26 -0
  104. package/resources/admin/organization/projects/service-accounts/api-keys.js.map +1 -0
  105. package/resources/admin/organization/projects/service-accounts/api-keys.mjs +22 -0
  106. package/resources/admin/organization/projects/service-accounts/api-keys.mjs.map +1 -0
  107. package/resources/admin/organization/projects/service-accounts/index.d.mts +3 -0
  108. package/resources/admin/organization/projects/service-accounts/index.d.mts.map +1 -0
  109. package/resources/admin/organization/projects/service-accounts/index.d.ts +3 -0
  110. package/resources/admin/organization/projects/service-accounts/index.d.ts.map +1 -0
  111. package/resources/admin/organization/projects/service-accounts/index.js +9 -0
  112. package/resources/admin/organization/projects/service-accounts/index.js.map +1 -0
  113. package/resources/admin/organization/projects/service-accounts/index.mjs +4 -0
  114. package/resources/admin/organization/projects/service-accounts/index.mjs.map +1 -0
  115. package/resources/admin/organization/projects/service-accounts/service-accounts.d.mts +177 -0
  116. package/resources/admin/organization/projects/service-accounts/service-accounts.d.mts.map +1 -0
  117. package/resources/admin/organization/projects/service-accounts/service-accounts.d.ts +177 -0
  118. package/resources/admin/organization/projects/service-accounts/service-accounts.d.ts.map +1 -0
  119. package/resources/admin/organization/projects/service-accounts/service-accounts.js +109 -0
  120. package/resources/admin/organization/projects/service-accounts/service-accounts.js.map +1 -0
  121. package/resources/admin/organization/projects/service-accounts/service-accounts.mjs +104 -0
  122. package/resources/admin/organization/projects/service-accounts/service-accounts.mjs.map +1 -0
  123. package/resources/admin/organization/projects/service-accounts.d.mts +1 -167
  124. package/resources/admin/organization/projects/service-accounts.d.mts.map +1 -1
  125. package/resources/admin/organization/projects/service-accounts.d.ts +1 -167
  126. package/resources/admin/organization/projects/service-accounts.d.ts.map +1 -1
  127. package/resources/admin/organization/projects/service-accounts.js +2 -97
  128. package/resources/admin/organization/projects/service-accounts.js.map +1 -1
  129. package/resources/admin/organization/projects/service-accounts.mjs +1 -95
  130. package/resources/admin/organization/projects/service-accounts.mjs.map +1 -1
  131. package/resources/admin/organization/projects/spend-limit.d.mts +115 -0
  132. package/resources/admin/organization/projects/spend-limit.d.mts.map +1 -0
  133. package/resources/admin/organization/projects/spend-limit.d.ts +115 -0
  134. package/resources/admin/organization/projects/spend-limit.d.ts.map +1 -0
  135. package/resources/admin/organization/projects/spend-limit.js +67 -0
  136. package/resources/admin/organization/projects/spend-limit.js.map +1 -0
  137. package/resources/admin/organization/projects/spend-limit.mjs +63 -0
  138. package/resources/admin/organization/projects/spend-limit.mjs.map +1 -0
  139. package/resources/admin/organization/spend-limit.d.mts +108 -0
  140. package/resources/admin/organization/spend-limit.d.mts.map +1 -0
  141. package/resources/admin/organization/spend-limit.d.ts +108 -0
  142. package/resources/admin/organization/spend-limit.d.ts.map +1 -0
  143. package/resources/admin/organization/spend-limit.js +59 -0
  144. package/resources/admin/organization/spend-limit.js.map +1 -0
  145. package/resources/admin/organization/spend-limit.mjs +55 -0
  146. package/resources/admin/organization/spend-limit.mjs.map +1 -0
  147. package/resources/admin/organization/usage.d.mts +517 -88
  148. package/resources/admin/organization/usage.d.mts.map +1 -1
  149. package/resources/admin/organization/usage.d.ts +517 -88
  150. package/resources/admin/organization/usage.d.ts.map +1 -1
  151. package/resources/beta/responses/input-tokens.d.mts +6 -2
  152. package/resources/beta/responses/input-tokens.d.mts.map +1 -1
  153. package/resources/beta/responses/input-tokens.d.ts +6 -2
  154. package/resources/beta/responses/input-tokens.d.ts.map +1 -1
  155. package/resources/beta/responses/responses.d.mts +25 -15
  156. package/resources/beta/responses/responses.d.mts.map +1 -1
  157. package/resources/beta/responses/responses.d.ts +25 -15
  158. package/resources/beta/responses/responses.d.ts.map +1 -1
  159. package/resources/beta/responses/responses.js.map +1 -1
  160. package/resources/beta/responses/responses.mjs.map +1 -1
  161. package/resources/chat/completions/completions.d.mts +4 -3
  162. package/resources/chat/completions/completions.d.mts.map +1 -1
  163. package/resources/chat/completions/completions.d.ts +4 -3
  164. package/resources/chat/completions/completions.d.ts.map +1 -1
  165. package/resources/chat/completions/completions.js.map +1 -1
  166. package/resources/chat/completions/completions.mjs.map +1 -1
  167. package/resources/responses/input-tokens.d.mts +2 -1
  168. package/resources/responses/input-tokens.d.mts.map +1 -1
  169. package/resources/responses/input-tokens.d.ts +2 -1
  170. package/resources/responses/input-tokens.d.ts.map +1 -1
  171. package/resources/responses/responses.d.mts +9 -8
  172. package/resources/responses/responses.d.mts.map +1 -1
  173. package/resources/responses/responses.d.ts +9 -8
  174. package/resources/responses/responses.d.ts.map +1 -1
  175. package/resources/responses/responses.js.map +1 -1
  176. package/resources/responses/responses.mjs.map +1 -1
  177. package/resources/shared.d.mts +4 -1
  178. package/resources/shared.d.mts.map +1 -1
  179. package/resources/shared.d.ts +4 -1
  180. package/resources/shared.d.ts.map +1 -1
  181. package/src/azure.ts +5 -1
  182. package/src/helpers/standard-schema.ts +570 -0
  183. package/src/helpers/zod.ts +158 -29
  184. package/src/internal/headers.ts +7 -3
  185. package/src/lib/AbstractChatCompletionRunner.ts +43 -1
  186. package/src/lib/ChatCompletionStream.ts +56 -8
  187. package/src/lib/ResponsesParser.ts +7 -5
  188. package/src/lib/jsonschema.ts +3 -0
  189. package/src/lib/transform.ts +1930 -103
  190. package/src/resources/admin/organization/audit-logs.ts +169 -1
  191. package/src/resources/admin/organization/index.ts +6 -0
  192. package/src/resources/admin/organization/organization.ts +16 -0
  193. package/src/resources/admin/organization/projects/index.ts +7 -1
  194. package/src/resources/admin/organization/projects/projects.ts +29 -13
  195. package/src/resources/admin/organization/projects/service-accounts/api-keys.ts +80 -0
  196. package/src/resources/admin/organization/projects/service-accounts/index.ts +15 -0
  197. package/src/resources/admin/organization/projects/service-accounts/service-accounts.ts +284 -0
  198. package/src/resources/admin/organization/projects/service-accounts.ts +1 -264
  199. package/src/resources/admin/organization/projects/spend-limit.ts +156 -0
  200. package/src/resources/admin/organization/spend-limit.ts +144 -0
  201. package/src/resources/admin/organization/usage.ts +616 -88
  202. package/src/resources/beta/responses/input-tokens.ts +6 -2
  203. package/src/resources/beta/responses/responses.ts +25 -14
  204. package/src/resources/chat/completions/completions.ts +4 -3
  205. package/src/resources/responses/input-tokens.ts +2 -1
  206. package/src/resources/responses/responses.ts +9 -7
  207. package/src/resources/shared.ts +4 -1
  208. package/src/version.ts +1 -1
  209. package/version.d.mts +1 -1
  210. package/version.d.ts +1 -1
  211. package/version.js +1 -1
  212. package/version.mjs +1 -1
@@ -13,6 +13,7 @@ import {
13
13
  import { zodToJsonSchema as _zodToJsonSchema } from '../_vendor/zod-to-json-schema';
14
14
  import { AutoParseableResponseTool, makeParseableResponseTool } from '../lib/ResponsesParser';
15
15
  import { type ResponseFormatTextJSONSchemaConfig } from '../resources/responses/responses';
16
+ import { type RealtimeFunctionTool } from '../resources/realtime/realtime';
16
17
  import { toStrictJsonSchema } from '../lib/transform';
17
18
  import { JSONSchema } from '../lib/jsonschema';
18
19
 
@@ -37,38 +38,134 @@ type InferZodType<T extends ZodTypeLike> =
37
38
  : T extends { _zod: { output: infer Output } } ? Output
38
39
  : never;
39
40
 
40
- function zodV3ToJsonSchema(schema: z3.ZodType, options: { name: string }): Record<string, unknown> {
41
- return _zodToJsonSchema(schema, {
41
+ type ZodSchemaDefinitions = Record<string, ZodTypeLike>;
42
+
43
+ type ZodResponseFormatProps = Omit<ResponseFormatJSONSchema.JSONSchema, 'schema' | 'strict' | 'name'> & {
44
+ /**
45
+ * Schemas to extract into the generated JSON Schema definitions.
46
+ * Use this to reuse large shared schemas instead of inlining them at every occurrence.
47
+ */
48
+ schemaDefinitions?: ZodSchemaDefinitions | undefined;
49
+ };
50
+
51
+ function encodeSchemaDefinitionRefToken(token: string): string {
52
+ return encodeURIComponent(token.replace(/~/g, '~0').replace(/\//g, '~1'));
53
+ }
54
+
55
+ function validateSchemaDefinitions(schemaDefinitions: ZodSchemaDefinitions | undefined): void {
56
+ if (schemaDefinitions && Object.prototype.hasOwnProperty.call(schemaDefinitions, '__proto__')) {
57
+ throw new Error('schemaDefinitions cannot include "__proto__" as a definition name');
58
+ }
59
+ }
60
+
61
+ function escapeSchemaDefinitionRefs<T extends object>(
62
+ schema: T,
63
+ schemaDefinitions: ZodSchemaDefinitions | undefined,
64
+ ): T {
65
+ const refReplacements = new Map(
66
+ Object.keys(schemaDefinitions ?? {}).map((name) => [
67
+ `#/definitions/${name}`,
68
+ `#/definitions/${encodeSchemaDefinitionRefToken(name)}`,
69
+ ]),
70
+ );
71
+
72
+ const visit = (value: unknown): void => {
73
+ if (!value || typeof value !== 'object') return;
74
+
75
+ if (Array.isArray(value)) {
76
+ for (const child of value) visit(child);
77
+ return;
78
+ }
79
+
80
+ const record = value as Record<string, unknown>;
81
+ const ref = record['$ref'];
82
+ if (typeof ref === 'string') {
83
+ record['$ref'] = refReplacements.get(ref) ?? ref;
84
+ }
85
+
86
+ for (const child of Object.values(record)) visit(child);
87
+ };
88
+
89
+ visit(schema);
90
+ return schema;
91
+ }
92
+
93
+ function getZodV3RootName(name: string, schemaDefinitions: ZodSchemaDefinitions | undefined): string {
94
+ let rootName = name;
95
+ while (schemaDefinitions && Object.prototype.hasOwnProperty.call(schemaDefinitions, rootName)) {
96
+ rootName = `${rootName}_root`;
97
+ }
98
+ return rootName;
99
+ }
100
+
101
+ function zodV3ToJsonSchema(
102
+ schema: z3.ZodType,
103
+ options: { name: string; schemaDefinitions?: ZodSchemaDefinitions | undefined },
104
+ ): Record<string, unknown> {
105
+ const rootName = getZodV3RootName(options.name, options.schemaDefinitions);
106
+ const jsonSchema = _zodToJsonSchema(schema, {
42
107
  openaiStrictMode: true,
43
- name: options.name,
108
+ name: rootName,
44
109
  nameStrategy: 'duplicate-ref',
45
110
  $refStrategy: 'extract-to-root',
46
111
  nullableStrategy: 'property',
112
+ ...(options.schemaDefinitions ?
113
+ { definitions: options.schemaDefinitions as unknown as Record<string, z3.ZodType> }
114
+ : undefined),
47
115
  });
116
+
117
+ return escapeSchemaDefinitionRefs(jsonSchema, options.schemaDefinitions);
48
118
  }
49
119
 
50
- function zodV4ToJsonSchema(schema: ZodV4Schema): Record<string, unknown> {
51
- return toStrictJsonSchema(
52
- z4.toJSONSchema(schema, {
53
- target: 'draft-7',
54
- override: ({ zodSchema, jsonSchema }) => {
55
- const def = zodSchema._zod.def;
56
-
57
- if (def.type === 'union' && 'discriminator' in def && Array.isArray(jsonSchema.oneOf)) {
58
- if (jsonSchema.anyOf !== undefined) {
59
- throw new Error(
60
- 'Zod discriminated union generated both `anyOf` and `oneOf`, which cannot be represented in an OpenAI strict schema',
61
- );
62
- }
63
-
64
- // Discriminator values are mutually exclusive, so anyOf preserves the
65
- // union while staying inside the API's supported JSON Schema subset.
66
- jsonSchema.anyOf = jsonSchema.oneOf;
67
- delete jsonSchema.oneOf;
120
+ function zodV4ToJsonSchema(
121
+ schema: ZodV4Schema,
122
+ options: { schemaDefinitions?: ZodSchemaDefinitions | undefined } = {},
123
+ ): Record<string, unknown> {
124
+ const metadata = options.schemaDefinitions ? z4.registry<Record<string, unknown>>() : undefined;
125
+ for (const [name, definition] of Object.entries(options.schemaDefinitions ?? {})) {
126
+ metadata?.add(definition as unknown as z4.ZodType, { id: name });
127
+ }
128
+
129
+ const jsonSchema = z4.toJSONSchema(schema, {
130
+ target: 'draft-7',
131
+ ...(metadata ? { metadata } : undefined),
132
+ override: ({ zodSchema, jsonSchema }) => {
133
+ const def = zodSchema._zod.def;
134
+
135
+ if (def.type === 'union' && 'discriminator' in def && Array.isArray(jsonSchema.oneOf)) {
136
+ if (jsonSchema.anyOf !== undefined) {
137
+ throw new Error(
138
+ 'Zod discriminated union generated both `anyOf` and `oneOf`, which cannot be represented in an OpenAI strict schema',
139
+ );
68
140
  }
69
- },
70
- }) as JSONSchema,
71
- ) as Record<string, unknown>;
141
+
142
+ // Discriminator values are mutually exclusive, so anyOf preserves the
143
+ // union while staying inside the API's supported JSON Schema subset.
144
+ jsonSchema.anyOf = jsonSchema.oneOf;
145
+ delete jsonSchema.oneOf;
146
+ }
147
+ },
148
+ }) as JSONSchema;
149
+
150
+ const escapedSchema = escapeSchemaDefinitionRefs(jsonSchema, options.schemaDefinitions);
151
+
152
+ return toStrictJsonSchema(escapedSchema) as Record<string, unknown>;
153
+ }
154
+
155
+ function zodV3ToNonStrictJsonSchema(schema: z3.ZodType, options: { name: string }): Record<string, unknown> {
156
+ return _zodToJsonSchema(schema, {
157
+ name: options.name,
158
+ nameStrategy: 'duplicate-ref',
159
+ $refStrategy: 'extract-to-root',
160
+ pipeStrategy: 'input',
161
+ });
162
+ }
163
+
164
+ function zodV4ToNonStrictJsonSchema(schema: ZodV4Schema): Record<string, unknown> {
165
+ return z4.toJSONSchema(schema, {
166
+ target: 'draft-7',
167
+ io: 'input',
168
+ }) as Record<string, unknown>;
72
169
  }
73
170
 
74
171
  function isZodV4(zodObject: ZodSchema): zodObject is ZodV4Schema {
@@ -129,18 +226,23 @@ function parseZodObject<ZodInput extends ZodTypeLike>(
129
226
  export function zodResponseFormat<ZodInput extends ZodTypeLike>(
130
227
  zodObject: ZodInput,
131
228
  name: string,
132
- props?: Omit<ResponseFormatJSONSchema.JSONSchema, 'schema' | 'strict' | 'name'>,
229
+ props?: ZodResponseFormatProps,
133
230
  ): AutoParseableResponseFormat<InferZodType<ZodInput>> {
134
231
  const zodSchema = zodObject as unknown as ZodSchema;
232
+ const { schemaDefinitions, ...responseFormatProps } = props ?? {};
233
+ validateSchemaDefinitions(schemaDefinitions);
135
234
 
136
235
  return makeParseableResponseFormat<InferZodType<ZodInput>>(
137
236
  {
138
237
  type: 'json_schema',
139
238
  json_schema: {
140
- ...props,
239
+ ...responseFormatProps,
141
240
  name,
142
241
  strict: true,
143
- schema: isZodV4(zodSchema) ? zodV4ToJsonSchema(zodSchema) : zodV3ToJsonSchema(zodSchema, { name }),
242
+ schema:
243
+ isZodV4(zodSchema) ?
244
+ zodV4ToJsonSchema(zodSchema, { schemaDefinitions })
245
+ : zodV3ToJsonSchema(zodSchema, { name, schemaDefinitions }),
144
246
  },
145
247
  },
146
248
  (content) => parseZodObject(zodObject, content),
@@ -177,7 +279,7 @@ export function zodFunction<Parameters extends ZodTypeLike>(options: {
177
279
  function?: ((args: InferZodType<Parameters>) => unknown | Promise<unknown>) | undefined;
178
280
  description?: string | undefined;
179
281
  }): AutoParseableTool<{
180
- arguments: Parameters;
282
+ arguments: InferZodType<Parameters>;
181
283
  name: string;
182
284
  function: (args: InferZodType<Parameters>) => unknown;
183
285
  }> {
@@ -210,7 +312,7 @@ export function zodResponsesFunction<Parameters extends ZodTypeLike>(options: {
210
312
  function?: ((args: InferZodType<Parameters>) => unknown | Promise<unknown>) | undefined;
211
313
  description?: string | undefined;
212
314
  }): AutoParseableResponseTool<{
213
- arguments: Parameters;
315
+ arguments: InferZodType<Parameters>;
214
316
  name: string;
215
317
  function: (args: InferZodType<Parameters>) => unknown;
216
318
  }> {
@@ -233,3 +335,30 @@ export function zodResponsesFunction<Parameters extends ZodTypeLike>(options: {
233
335
  },
234
336
  );
235
337
  }
338
+
339
+ /**
340
+ * Creates a Realtime API `function` tool definition from the given Zod schema.
341
+ *
342
+ * Unlike {@link zodResponsesFunction}, this helper does not add `strict`
343
+ * because Realtime function tools do not support that field.
344
+ *
345
+ * This helper only creates the tool definition. Parse function-call arguments
346
+ * from Realtime events with the original Zod schema.
347
+ */
348
+ export function zodRealtimeFunction<Parameters extends ZodTypeLike>(options: {
349
+ name: string;
350
+ parameters: Parameters;
351
+ description?: string | undefined;
352
+ }): RealtimeFunctionTool {
353
+ const zodSchema = options.parameters as unknown as ZodSchema;
354
+
355
+ return {
356
+ type: 'function',
357
+ name: options.name,
358
+ parameters:
359
+ isZodV4(zodSchema) ?
360
+ zodV4ToNonStrictJsonSchema(zodSchema)
361
+ : zodV3ToNonStrictJsonSchema(zodSchema, { name: options.name }),
362
+ ...(options.description ? { description: options.description } : undefined),
363
+ };
364
+ }
@@ -12,6 +12,7 @@ export type HeadersLike =
12
12
  | NullableHeaders;
13
13
 
14
14
  const brand_privateNullableHeaders = /* @__PURE__ */ Symbol('brand.privateNullableHeaders');
15
+ const httpTokenHeaderName = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
15
16
 
16
17
  /**
17
18
  * @internal
@@ -74,16 +75,19 @@ export const buildHeaders = (newHeaders: HeadersLike[]): NullableHeaders => {
74
75
  for (const headers of newHeaders) {
75
76
  const seenHeaders = new Set<string>();
76
77
  for (const [name, value] of iterateHeaders(headers)) {
78
+ if (!httpTokenHeaderName.test(name)) {
79
+ throw new TypeError(`Header name must be a valid HTTP token ["${name}"]`);
80
+ }
77
81
  const lowerName = name.toLowerCase();
78
82
  if (!seenHeaders.has(lowerName)) {
79
- targetHeaders.delete(name);
83
+ targetHeaders.delete(lowerName);
80
84
  seenHeaders.add(lowerName);
81
85
  }
82
86
  if (value === null) {
83
- targetHeaders.delete(name);
87
+ targetHeaders.delete(lowerName);
84
88
  nullHeaders.add(lowerName);
85
89
  } else {
86
- targetHeaders.append(name, value);
90
+ targetHeaders.append(lowerName, value);
87
91
  nullHeaders.delete(lowerName);
88
92
  }
89
93
  }
@@ -5,6 +5,7 @@ import { uuid4 } from '../internal/utils/uuid';
5
5
  import { isAutoParsableTool, parseChatCompletion } from '../lib/parser';
6
6
  import type {
7
7
  ChatCompletion,
8
+ ChatCompletionAssistantMessageParam,
8
9
  ChatCompletionCreateParams,
9
10
  ChatCompletionMessage,
10
11
  ChatCompletionMessageFunctionToolCall,
@@ -49,6 +50,47 @@ function normalizeToolCallIds(chatCompletion: ChatCompletion): void {
49
50
  }
50
51
  }
51
52
 
53
+ /**
54
+ * Parsed completions contain response-only and helper-only fields. Keep those
55
+ * on runner.messages for callers, but only replay valid request fields.
56
+ */
57
+ function toRequestMessage(message: ChatCompletionMessageParam): ChatCompletionMessageParam {
58
+ if (!isAssistantMessage(message)) return message;
59
+
60
+ const requestMessage: ChatCompletionAssistantMessageParam = { role: 'assistant' };
61
+
62
+ if (message.audio != null) requestMessage.audio = { id: message.audio.id };
63
+ if (message.content !== undefined) requestMessage.content = message.content;
64
+ if (message.function_call != null) requestMessage.function_call = message.function_call;
65
+ if (message.name !== undefined) requestMessage.name = message.name;
66
+ if (message.refusal != null) requestMessage.refusal = message.refusal;
67
+ if (message.tool_calls !== undefined) {
68
+ requestMessage.tool_calls = message.tool_calls.map((toolCall) => {
69
+ if (toolCall.type === 'custom') {
70
+ return {
71
+ id: toolCall.id,
72
+ type: toolCall.type,
73
+ custom: {
74
+ input: toolCall.custom.input,
75
+ name: toolCall.custom.name,
76
+ },
77
+ };
78
+ }
79
+
80
+ return {
81
+ id: toolCall.id,
82
+ type: toolCall.type,
83
+ function: {
84
+ arguments: toolCall.function.arguments,
85
+ name: toolCall.function.name,
86
+ },
87
+ };
88
+ });
89
+ }
90
+
91
+ return requestMessage;
92
+ }
93
+
52
94
  export interface ChatCompletionRunnerContext {
53
95
  messages: ChatCompletionMessageParam[];
54
96
  abort(): void;
@@ -413,7 +455,7 @@ export class AbstractChatCompletionRunner<
413
455
  ...restParams,
414
456
  tool_choice,
415
457
  tools,
416
- messages: [...this.messages],
458
+ messages: this.messages.map(toRequestMessage),
417
459
  },
418
460
  options,
419
461
  );
@@ -20,6 +20,7 @@ import {
20
20
  } from '../lib/parser';
21
21
  import { ChatCompletionFunctionTool, ParsedChatCompletion } from '../resources/chat/completions';
22
22
  import {
23
+ type ChatCompletionAudio,
23
24
  ChatCompletionTokenLogprob,
24
25
  type ChatCompletion,
25
26
  type ChatCompletionChunk,
@@ -196,12 +197,14 @@ export class ChatCompletionStream<ParsedT = null>
196
197
  implements AsyncIterable<ChatCompletionChunk>
197
198
  {
198
199
  #params: ChatCompletionCreateParams | null;
200
+ #audioDoneChoiceIndexes: Set<number>;
199
201
  #choiceEventStates: ChoiceEventState[];
200
202
  #currentChatCompletionSnapshot: ChatCompletionSnapshot | undefined;
201
203
 
202
204
  constructor(params: ChatCompletionCreateParams | null) {
203
205
  super();
204
206
  this.#params = params;
207
+ this.#audioDoneChoiceIndexes = new Set();
205
208
  this.#choiceEventStates = [];
206
209
  }
207
210
 
@@ -240,6 +243,7 @@ export class ChatCompletionStream<ParsedT = null>
240
243
 
241
244
  #beginRequest() {
242
245
  if (this.ended) return;
246
+ this.#audioDoneChoiceIndexes = new Set();
243
247
  this.#currentChatCompletionSnapshot = undefined;
244
248
  }
245
249
 
@@ -428,9 +432,11 @@ export class ChatCompletionStream<ParsedT = null>
428
432
  if (!snapshot) {
429
433
  throw new OpenAIError(`request ended without sending any chunks`);
430
434
  }
435
+ const audioDoneChoiceIndexes = this.#audioDoneChoiceIndexes;
436
+ this.#audioDoneChoiceIndexes = new Set();
431
437
  this.#currentChatCompletionSnapshot = undefined;
432
438
  this.#choiceEventStates = [];
433
- return finalizeChatCompletion(snapshot, this.#params);
439
+ return finalizeChatCompletion(snapshot, this.#params, audioDoneChoiceIndexes);
434
440
  }
435
441
 
436
442
  protected override async _createChatCompletion(
@@ -575,15 +581,41 @@ export class ChatCompletionStream<ParsedT = null>
575
581
 
576
582
  if (!delta) continue; // Shouldn't happen; just in case.
577
583
 
578
- const { content, refusal, function_call, role, tool_calls, ...rest } = delta;
584
+ this.#audioDoneChoiceIndexes.delete(index);
585
+ const { audio, content, refusal, function_call, role, tool_calls, ...rest } = delta as typeof delta & {
586
+ audio?: Partial<ChatCompletionAudio> | null;
587
+ };
579
588
  assertIsEmpty(rest);
580
589
  Object.assign(choice.message, rest);
590
+ if (
591
+ audio?.expires_at != null &&
592
+ audio.id == null &&
593
+ audio.data == null &&
594
+ audio.transcript == null &&
595
+ content == null &&
596
+ refusal == null &&
597
+ function_call == null &&
598
+ role == null &&
599
+ tool_calls == null &&
600
+ Object.keys(rest).length === 0
601
+ ) {
602
+ this.#audioDoneChoiceIndexes.add(index);
603
+ }
581
604
 
582
605
  if (refusal) {
583
606
  choice.message.refusal = (choice.message.refusal || '') + refusal;
584
607
  }
585
608
 
586
609
  if (role) choice.message.role = role;
610
+ if (audio) {
611
+ const audioSnapshot = (choice.message.audio ??= {});
612
+ if (audio.id != null) audioSnapshot.id = audio.id;
613
+ if (audio.data != null) audioSnapshot.data = (audioSnapshot.data ?? '') + audio.data;
614
+ if (audio.transcript != null) {
615
+ audioSnapshot.transcript = (audioSnapshot.transcript ?? '') + audio.transcript;
616
+ }
617
+ if (audio.expires_at != null) audioSnapshot.expires_at = audio.expires_at;
618
+ }
587
619
  if (function_call) {
588
620
  if (!choice.message.function_call) {
589
621
  choice.message.function_call = function_call;
@@ -698,6 +730,7 @@ export class ChatCompletionStream<ParsedT = null>
698
730
  function finalizeChatCompletion<ParsedT>(
699
731
  snapshot: ChatCompletionSnapshot,
700
732
  params: ChatCompletionCreateParams | null,
733
+ audioDoneChoiceIndexes: ReadonlySet<number>,
701
734
  ): ParsedChatCompletion<ParsedT> {
702
735
  const { id, choices, created, model, system_fingerprint, ...rest } = snapshot;
703
736
  const completion: ChatCompletion = {
@@ -705,11 +738,16 @@ function finalizeChatCompletion<ParsedT>(
705
738
  id,
706
739
  choices: choices.map(
707
740
  ({ message, finish_reason, index, logprobs, ...choiceRest }): ChatCompletion.Choice => {
708
- if (!finish_reason) {
741
+ const { content = null, function_call, tool_calls, audio, ...messageRest } = message;
742
+ // Audio streams can end with an expires_at-only chunk after the
743
+ // generated audio, without a separate finish_reason.
744
+ const finishReason =
745
+ finish_reason ?? (audioDoneChoiceIndexes.has(index) && isCompleteAudio(audio) ? 'stop' : null);
746
+ if (!finishReason) {
709
747
  throw new OpenAIError(`missing finish_reason for choice ${index}`);
710
748
  }
711
749
 
712
- const { content = null, function_call, tool_calls, ...messageRest } = message;
750
+ const audioResponse = audio ? { audio: audio as ChatCompletionAudio } : {};
713
751
  const role = message.role as 'assistant'; // this is what we expect; in theory it could be different which would make our types a slight lie but would be fine.
714
752
  if (!role) {
715
753
  throw new OpenAIError(`missing role for choice ${index}`);
@@ -728,12 +766,13 @@ function finalizeChatCompletion<ParsedT>(
728
766
  return {
729
767
  ...choiceRest,
730
768
  message: {
769
+ ...audioResponse,
731
770
  content,
732
771
  function_call: { arguments: args, name },
733
772
  role,
734
773
  refusal: message.refusal ?? null,
735
774
  },
736
- finish_reason,
775
+ finish_reason: finishReason,
737
776
  index,
738
777
  logprobs,
739
778
  };
@@ -743,10 +782,11 @@ function finalizeChatCompletion<ParsedT>(
743
782
  return {
744
783
  ...choiceRest,
745
784
  index,
746
- finish_reason,
785
+ finish_reason: finishReason,
747
786
  logprobs,
748
787
  message: {
749
788
  ...messageRest,
789
+ ...audioResponse,
750
790
  role,
751
791
  content,
752
792
  refusal: message.refusal ?? null,
@@ -779,8 +819,8 @@ function finalizeChatCompletion<ParsedT>(
779
819
  }
780
820
  return {
781
821
  ...choiceRest,
782
- message: { ...messageRest, content, role, refusal: message.refusal ?? null },
783
- finish_reason,
822
+ message: { ...messageRest, ...audioResponse, content, role, refusal: message.refusal ?? null },
823
+ finish_reason: finishReason,
784
824
  index,
785
825
  logprobs,
786
826
  };
@@ -795,6 +835,12 @@ function finalizeChatCompletion<ParsedT>(
795
835
  return maybeParseChatCompletion(completion, params);
796
836
  }
797
837
 
838
+ function isCompleteAudio(
839
+ audio: Partial<ChatCompletionAudio> | null | undefined,
840
+ ): audio is ChatCompletionAudio {
841
+ return audio?.id != null && audio.data != null && audio.transcript != null && audio.expires_at != null;
842
+ }
843
+
798
844
  function str(x: unknown) {
799
845
  return JSON.stringify(x);
800
846
  }
@@ -875,6 +921,8 @@ export namespace ChatCompletionSnapshot {
875
921
  */
876
922
  content?: string | null;
877
923
 
924
+ audio?: Partial<ChatCompletionAudio> | null;
925
+
878
926
  refusal?: string | null;
879
927
 
880
928
  parsed?: unknown | null;
@@ -74,10 +74,7 @@ export function parseResponse<
74
74
  const output: Array<ParsedResponseOutputItem<ParsedT>> = response.output.map(
75
75
  (item): ParsedResponseOutputItem<ParsedT> => {
76
76
  if (item.type === 'function_call') {
77
- return {
78
- ...item,
79
- parsed_arguments: shouldParse ? parseToolCall(params, item) : null,
80
- };
77
+ return shouldParse ? parseToolCall(params, item) : { ...item, parsed_arguments: null };
81
78
  }
82
79
  if (item.type === 'message') {
83
80
  const content: Array<ParsedContent<ParsedT>> = item.content.map((content) => {
@@ -149,7 +146,12 @@ export function hasAutoParseableInput(params: ResponseCreateParamsWithTools): bo
149
146
  return true;
150
147
  }
151
148
 
152
- return false;
149
+ return (
150
+ Array.isArray(params.tools) &&
151
+ params.tools.some(
152
+ (tool) => isAutoParsableTool(tool) || (tool.type === 'function' && tool.strict === true),
153
+ )
154
+ );
153
155
  }
154
156
 
155
157
  type ToolOptions = {
@@ -61,6 +61,7 @@ export type JSONSchemaVersion = string;
61
61
  */
62
62
  export type JSONSchemaDefinition = JSONSchema | boolean;
63
63
  export interface JSONSchema {
64
+ $schema?: JSONSchemaVersion | undefined;
64
65
  $id?: string | undefined;
65
66
  $comment?: string | undefined;
66
67
 
@@ -86,6 +87,8 @@ export interface JSONSchema {
86
87
  maxLength?: number | undefined;
87
88
  minLength?: number | undefined;
88
89
  pattern?: string | undefined;
90
+ contentEncoding?: string | undefined;
91
+ contentMediaType?: string | undefined;
89
92
 
90
93
  /**
91
94
  * @see https://tools.ietf.org/html/draft-handrews-json-schema-validation-01#section-6.4