openai 7.27.0 → 7.30.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 (335) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/client.d.mts +3 -0
  3. package/client.d.mts.map +1 -1
  4. package/client.d.ts +3 -0
  5. package/client.d.ts.map +1 -1
  6. package/client.js +3 -0
  7. package/client.js.map +1 -1
  8. package/client.mjs +3 -0
  9. package/client.mjs.map +1 -1
  10. package/helpers/standard-schema.d.mts +8 -3
  11. package/helpers/standard-schema.d.mts.map +1 -1
  12. package/helpers/standard-schema.d.ts +8 -3
  13. package/helpers/standard-schema.d.ts.map +1 -1
  14. package/helpers/standard-schema.js +1 -0
  15. package/helpers/standard-schema.js.map +1 -1
  16. package/helpers/standard-schema.mjs +1 -0
  17. package/helpers/standard-schema.mjs.map +1 -1
  18. package/helpers/zod.d.mts +2 -0
  19. package/helpers/zod.d.mts.map +1 -1
  20. package/helpers/zod.d.ts +2 -0
  21. package/helpers/zod.d.ts.map +1 -1
  22. package/helpers/zod.js +1 -0
  23. package/helpers/zod.js.map +1 -1
  24. package/helpers/zod.mjs +1 -0
  25. package/helpers/zod.mjs.map +1 -1
  26. package/lib/ChatCompletionStream.d.mts +2 -1
  27. package/lib/ChatCompletionStream.d.mts.map +1 -1
  28. package/lib/ChatCompletionStream.d.ts +2 -1
  29. package/lib/ChatCompletionStream.d.ts.map +1 -1
  30. package/lib/ChatCompletionStream.js +9 -2
  31. package/lib/ChatCompletionStream.js.map +1 -1
  32. package/lib/ChatCompletionStream.mjs +9 -2
  33. package/lib/ChatCompletionStream.mjs.map +1 -1
  34. package/lib/ResponsesParser.d.mts.map +1 -1
  35. package/lib/ResponsesParser.d.ts.map +1 -1
  36. package/lib/ResponsesParser.js +5 -0
  37. package/lib/ResponsesParser.js.map +1 -1
  38. package/lib/ResponsesParser.mjs +5 -0
  39. package/lib/ResponsesParser.mjs.map +1 -1
  40. package/lib/agents/agent-session-stream.d.mts +7 -0
  41. package/lib/agents/agent-session-stream.d.mts.map +1 -1
  42. package/lib/agents/agent-session-stream.d.ts +7 -0
  43. package/lib/agents/agent-session-stream.d.ts.map +1 -1
  44. package/lib/agents/agent-session-stream.js +8 -110
  45. package/lib/agents/agent-session-stream.js.map +1 -1
  46. package/lib/agents/agent-session-stream.mjs +9 -111
  47. package/lib/agents/agent-session-stream.mjs.map +1 -1
  48. package/lib/beta/agents/agent-session-create-stream.d.mts +41 -1
  49. package/lib/beta/agents/agent-session-create-stream.d.mts.map +1 -1
  50. package/lib/beta/agents/agent-session-create-stream.d.ts +41 -1
  51. package/lib/beta/agents/agent-session-create-stream.d.ts.map +1 -1
  52. package/lib/beta/agents/agent-session-create-stream.js +70 -2
  53. package/lib/beta/agents/agent-session-create-stream.js.map +1 -1
  54. package/lib/beta/agents/agent-session-create-stream.mjs +69 -2
  55. package/lib/beta/agents/agent-session-create-stream.mjs.map +1 -1
  56. package/lib/beta/agents/function-tool.d.mts.map +1 -1
  57. package/lib/beta/agents/function-tool.d.ts.map +1 -1
  58. package/lib/beta/agents/function-tool.js +22 -15
  59. package/lib/beta/agents/function-tool.js.map +1 -1
  60. package/lib/beta/agents/function-tool.mjs +22 -15
  61. package/lib/beta/agents/function-tool.mjs.map +1 -1
  62. package/lib/beta/agents/parse-result.d.mts +4 -2
  63. package/lib/beta/agents/parse-result.d.mts.map +1 -1
  64. package/lib/beta/agents/parse-result.d.ts +4 -2
  65. package/lib/beta/agents/parse-result.d.ts.map +1 -1
  66. package/lib/beta/agents/tool-dispatcher.d.mts +13 -0
  67. package/lib/beta/agents/tool-dispatcher.d.mts.map +1 -0
  68. package/lib/beta/agents/tool-dispatcher.d.ts +13 -0
  69. package/lib/beta/agents/tool-dispatcher.d.ts.map +1 -0
  70. package/lib/beta/agents/tool-dispatcher.js +185 -0
  71. package/lib/beta/agents/tool-dispatcher.js.map +1 -0
  72. package/lib/beta/agents/tool-dispatcher.mjs +181 -0
  73. package/lib/beta/agents/tool-dispatcher.mjs.map +1 -0
  74. package/lib/beta/agents/tool-error.d.mts +13 -0
  75. package/lib/beta/agents/tool-error.d.mts.map +1 -0
  76. package/lib/beta/agents/tool-error.d.ts +13 -0
  77. package/lib/beta/agents/tool-error.d.ts.map +1 -0
  78. package/lib/beta/agents/tool-error.js +3 -0
  79. package/lib/beta/agents/tool-error.js.map +1 -0
  80. package/lib/beta/agents/tool-error.mjs +2 -0
  81. package/lib/beta/agents/tool-error.mjs.map +1 -0
  82. package/lib/beta/agents/tool-stages.d.mts +12 -0
  83. package/lib/beta/agents/tool-stages.d.mts.map +1 -0
  84. package/lib/beta/agents/tool-stages.d.ts +12 -0
  85. package/lib/beta/agents/tool-stages.d.ts.map +1 -0
  86. package/lib/beta/agents/tool-stages.js +6 -0
  87. package/lib/beta/agents/tool-stages.js.map +1 -0
  88. package/lib/beta/agents/tool-stages.mjs +3 -0
  89. package/lib/beta/agents/tool-stages.mjs.map +1 -0
  90. package/lib/chat-completions/streaming.d.mts +11 -0
  91. package/lib/chat-completions/streaming.d.mts.map +1 -0
  92. package/lib/chat-completions/streaming.d.ts +11 -0
  93. package/lib/chat-completions/streaming.d.ts.map +1 -0
  94. package/lib/chat-completions/streaming.js +27 -0
  95. package/lib/chat-completions/streaming.js.map +1 -0
  96. package/lib/chat-completions/streaming.mjs +23 -0
  97. package/lib/chat-completions/streaming.mjs.map +1 -0
  98. package/package.json +1 -1
  99. package/resources/admin/organization/usage.d.mts +381 -20
  100. package/resources/admin/organization/usage.d.mts.map +1 -1
  101. package/resources/admin/organization/usage.d.ts +381 -20
  102. package/resources/admin/organization/usage.d.ts.map +1 -1
  103. package/resources/audio/audio.d.mts +4 -0
  104. package/resources/audio/audio.d.mts.map +1 -1
  105. package/resources/audio/audio.d.ts +4 -0
  106. package/resources/audio/audio.d.ts.map +1 -1
  107. package/resources/audio/audio.js +4 -0
  108. package/resources/audio/audio.js.map +1 -1
  109. package/resources/audio/audio.mjs +4 -0
  110. package/resources/audio/audio.mjs.map +1 -1
  111. package/resources/audio/index.d.mts +1 -0
  112. package/resources/audio/index.d.mts.map +1 -1
  113. package/resources/audio/index.d.ts +1 -0
  114. package/resources/audio/index.d.ts.map +1 -1
  115. package/resources/audio/index.js +3 -1
  116. package/resources/audio/index.js.map +1 -1
  117. package/resources/audio/index.mjs +1 -0
  118. package/resources/audio/index.mjs.map +1 -1
  119. package/resources/audio/speech.d.mts +2 -0
  120. package/resources/audio/speech.d.mts.map +1 -1
  121. package/resources/audio/speech.d.ts +2 -0
  122. package/resources/audio/speech.d.ts.map +1 -1
  123. package/resources/audio/voices.d.mts +119 -0
  124. package/resources/audio/voices.d.mts.map +1 -0
  125. package/resources/audio/voices.d.ts +119 -0
  126. package/resources/audio/voices.d.ts.map +1 -0
  127. package/resources/audio/voices.js +41 -0
  128. package/resources/audio/voices.js.map +1 -0
  129. package/resources/audio/voices.mjs +37 -0
  130. package/resources/audio/voices.mjs.map +1 -0
  131. package/resources/beta/agents/agents.d.mts +14 -10
  132. package/resources/beta/agents/agents.d.mts.map +1 -1
  133. package/resources/beta/agents/agents.d.ts +14 -10
  134. package/resources/beta/agents/agents.d.ts.map +1 -1
  135. package/resources/beta/agents/agents.js.map +1 -1
  136. package/resources/beta/agents/agents.mjs.map +1 -1
  137. package/resources/beta/agents/environments/templates.d.mts +6 -8
  138. package/resources/beta/agents/environments/templates.d.mts.map +1 -1
  139. package/resources/beta/agents/environments/templates.d.ts +6 -8
  140. package/resources/beta/agents/environments/templates.d.ts.map +1 -1
  141. package/resources/beta/agents/sessions/index.d.mts +1 -1
  142. package/resources/beta/agents/sessions/index.d.mts.map +1 -1
  143. package/resources/beta/agents/sessions/index.d.ts +1 -1
  144. package/resources/beta/agents/sessions/index.d.ts.map +1 -1
  145. package/resources/beta/agents/sessions/index.js +2 -2
  146. package/resources/beta/agents/sessions/index.js.map +1 -1
  147. package/resources/beta/agents/sessions/index.mjs +1 -1
  148. package/resources/beta/agents/sessions/index.mjs.map +1 -1
  149. package/resources/beta/agents/sessions/sessions.d.mts +8 -7
  150. package/resources/beta/agents/sessions/sessions.d.mts.map +1 -1
  151. package/resources/beta/agents/sessions/sessions.d.ts +8 -7
  152. package/resources/beta/agents/sessions/sessions.d.ts.map +1 -1
  153. package/resources/beta/agents/sessions/sessions.js +7 -4
  154. package/resources/beta/agents/sessions/sessions.js.map +1 -1
  155. package/resources/beta/agents/sessions/sessions.mjs +8 -5
  156. package/resources/beta/agents/sessions/sessions.mjs.map +1 -1
  157. package/resources/beta/agents/sessions/subagents/turns/turns.d.mts +2 -2
  158. package/resources/beta/agents/sessions/subagents/turns/turns.d.mts.map +1 -1
  159. package/resources/beta/agents/sessions/subagents/turns/turns.d.ts +2 -2
  160. package/resources/beta/agents/sessions/subagents/turns/turns.d.ts.map +1 -1
  161. package/resources/beta/agents/sessions/turns/index.d.mts +3 -0
  162. package/resources/beta/agents/sessions/turns/index.d.mts.map +1 -0
  163. package/resources/beta/agents/sessions/turns/index.d.ts +3 -0
  164. package/resources/beta/agents/sessions/turns/index.d.ts.map +1 -0
  165. package/resources/beta/agents/sessions/turns/index.js +9 -0
  166. package/resources/beta/agents/sessions/turns/index.js.map +1 -0
  167. package/resources/beta/agents/sessions/turns/index.mjs +4 -0
  168. package/resources/beta/agents/sessions/turns/index.mjs.map +1 -0
  169. package/resources/beta/agents/sessions/turns/items.d.mts +43 -0
  170. package/resources/beta/agents/sessions/turns/items.d.mts.map +1 -0
  171. package/resources/beta/agents/sessions/turns/items.d.ts +43 -0
  172. package/resources/beta/agents/sessions/turns/items.d.ts.map +1 -0
  173. package/resources/beta/agents/sessions/turns/items.js +40 -0
  174. package/resources/beta/agents/sessions/turns/items.js.map +1 -0
  175. package/resources/beta/agents/sessions/turns/items.mjs +36 -0
  176. package/resources/beta/agents/sessions/turns/items.mjs.map +1 -0
  177. package/resources/beta/agents/sessions/turns/turns.d.mts +128 -0
  178. package/resources/beta/agents/sessions/turns/turns.d.mts.map +1 -0
  179. package/resources/beta/agents/sessions/turns/turns.d.ts +128 -0
  180. package/resources/beta/agents/sessions/turns/turns.d.ts.map +1 -0
  181. package/resources/beta/agents/sessions/turns/turns.js +111 -0
  182. package/resources/beta/agents/sessions/turns/turns.js.map +1 -0
  183. package/resources/beta/agents/sessions/turns/turns.mjs +106 -0
  184. package/resources/beta/agents/sessions/turns/turns.mjs.map +1 -0
  185. package/resources/beta/agents/sessions/turns.d.mts +1 -123
  186. package/resources/beta/agents/sessions/turns.d.mts.map +1 -1
  187. package/resources/beta/agents/sessions/turns.d.ts +1 -123
  188. package/resources/beta/agents/sessions/turns.d.ts.map +1 -1
  189. package/resources/beta/agents/sessions/turns.js +2 -99
  190. package/resources/beta/agents/sessions/turns.js.map +1 -1
  191. package/resources/beta/agents/sessions/turns.mjs +1 -97
  192. package/resources/beta/agents/sessions/turns.mjs.map +1 -1
  193. package/resources/beta/beta.d.mts +2 -2
  194. package/resources/beta/beta.d.mts.map +1 -1
  195. package/resources/beta/beta.d.ts +2 -2
  196. package/resources/beta/beta.d.ts.map +1 -1
  197. package/resources/beta/beta.js.map +1 -1
  198. package/resources/beta/beta.mjs.map +1 -1
  199. package/resources/beta/index.d.mts +1 -1
  200. package/resources/beta/index.d.mts.map +1 -1
  201. package/resources/beta/index.d.ts +1 -1
  202. package/resources/beta/index.d.ts.map +1 -1
  203. package/resources/beta/index.js.map +1 -1
  204. package/resources/beta/index.mjs.map +1 -1
  205. package/resources/beta/responses/index.d.mts +1 -1
  206. package/resources/beta/responses/index.d.mts.map +1 -1
  207. package/resources/beta/responses/index.d.ts +1 -1
  208. package/resources/beta/responses/index.d.ts.map +1 -1
  209. package/resources/beta/responses/index.js.map +1 -1
  210. package/resources/beta/responses/index.mjs.map +1 -1
  211. package/resources/beta/responses/responses.d.mts +379 -9
  212. package/resources/beta/responses/responses.d.mts.map +1 -1
  213. package/resources/beta/responses/responses.d.ts +379 -9
  214. package/resources/beta/responses/responses.d.ts.map +1 -1
  215. package/resources/beta/responses/responses.js.map +1 -1
  216. package/resources/beta/responses/responses.mjs.map +1 -1
  217. package/resources/chat/completions/completions.d.mts +44 -9
  218. package/resources/chat/completions/completions.d.mts.map +1 -1
  219. package/resources/chat/completions/completions.d.ts +44 -9
  220. package/resources/chat/completions/completions.d.ts.map +1 -1
  221. package/resources/chat/completions/completions.js +5 -2
  222. package/resources/chat/completions/completions.js.map +1 -1
  223. package/resources/chat/completions/completions.mjs +5 -2
  224. package/resources/chat/completions/completions.mjs.map +1 -1
  225. package/resources/completions.d.mts +1 -1
  226. package/resources/completions.d.mts.map +1 -1
  227. package/resources/completions.d.ts +1 -1
  228. package/resources/completions.d.ts.map +1 -1
  229. package/resources/decisions.d.mts +196 -0
  230. package/resources/decisions.d.mts.map +1 -0
  231. package/resources/decisions.d.ts +196 -0
  232. package/resources/decisions.d.ts.map +1 -0
  233. package/resources/decisions.js +32 -0
  234. package/resources/decisions.js.map +1 -0
  235. package/resources/decisions.mjs +28 -0
  236. package/resources/decisions.mjs.map +1 -0
  237. package/resources/fine-tuning/jobs/jobs.d.mts +7 -2
  238. package/resources/fine-tuning/jobs/jobs.d.mts.map +1 -1
  239. package/resources/fine-tuning/jobs/jobs.d.ts +7 -2
  240. package/resources/fine-tuning/jobs/jobs.d.ts.map +1 -1
  241. package/resources/fine-tuning/jobs/jobs.js.map +1 -1
  242. package/resources/fine-tuning/jobs/jobs.mjs.map +1 -1
  243. package/resources/graders/grader-models.d.mts +1 -1
  244. package/resources/graders/grader-models.d.ts +1 -1
  245. package/resources/images.d.mts +61 -75
  246. package/resources/images.d.mts.map +1 -1
  247. package/resources/images.d.ts +61 -75
  248. package/resources/images.d.ts.map +1 -1
  249. package/resources/images.js +4 -7
  250. package/resources/images.js.map +1 -1
  251. package/resources/images.mjs +4 -7
  252. package/resources/images.mjs.map +1 -1
  253. package/resources/index.d.mts +1 -0
  254. package/resources/index.d.mts.map +1 -1
  255. package/resources/index.d.ts +1 -0
  256. package/resources/index.d.ts.map +1 -1
  257. package/resources/index.js +3 -1
  258. package/resources/index.js.map +1 -1
  259. package/resources/index.mjs +1 -0
  260. package/resources/index.mjs.map +1 -1
  261. package/resources/realtime/realtime.d.mts +16 -4
  262. package/resources/realtime/realtime.d.mts.map +1 -1
  263. package/resources/realtime/realtime.d.ts +16 -4
  264. package/resources/realtime/realtime.d.ts.map +1 -1
  265. package/resources/realtime/realtime.js.map +1 -1
  266. package/resources/realtime/realtime.mjs.map +1 -1
  267. package/resources/responses/responses.d.mts +381 -9
  268. package/resources/responses/responses.d.mts.map +1 -1
  269. package/resources/responses/responses.d.ts +381 -9
  270. package/resources/responses/responses.d.ts.map +1 -1
  271. package/resources/responses/responses.js.map +1 -1
  272. package/resources/responses/responses.mjs.map +1 -1
  273. package/resources/shared.d.mts +69 -0
  274. package/resources/shared.d.mts.map +1 -1
  275. package/resources/shared.d.ts +69 -0
  276. package/resources/shared.d.ts.map +1 -1
  277. package/resources/videos.d.mts +5 -0
  278. package/resources/videos.d.mts.map +1 -1
  279. package/resources/videos.d.ts +5 -0
  280. package/resources/videos.d.ts.map +1 -1
  281. package/resources/webhooks/webhooks.d.mts +211 -6
  282. package/resources/webhooks/webhooks.d.mts.map +1 -1
  283. package/resources/webhooks/webhooks.d.ts +211 -6
  284. package/resources/webhooks/webhooks.d.ts.map +1 -1
  285. package/resources/webhooks/webhooks.js.map +1 -1
  286. package/resources/webhooks/webhooks.mjs.map +1 -1
  287. package/src/client.ts +21 -0
  288. package/src/helpers/standard-schema.ts +11 -4
  289. package/src/helpers/zod.ts +4 -0
  290. package/src/lib/ChatCompletionStream.ts +10 -3
  291. package/src/lib/ResponsesParser.ts +8 -0
  292. package/src/lib/agents/agent-session-stream.ts +20 -124
  293. package/src/lib/beta/agents/agent-session-create-stream.ts +87 -1
  294. package/src/lib/beta/agents/function-tool.ts +23 -15
  295. package/src/lib/beta/agents/tool-dispatcher.ts +226 -0
  296. package/src/lib/beta/agents/tool-error.ts +12 -0
  297. package/src/lib/beta/agents/tool-stages.ts +14 -0
  298. package/src/lib/chat-completions/streaming.ts +35 -0
  299. package/src/resources/admin/organization/usage.ts +438 -20
  300. package/src/resources/audio/audio.ts +6 -0
  301. package/src/resources/audio/index.ts +1 -0
  302. package/src/resources/audio/speech.ts +2 -0
  303. package/src/resources/audio/voices.ts +152 -0
  304. package/src/resources/beta/agents/agents.ts +16 -9
  305. package/src/resources/beta/agents/environments/templates.ts +6 -8
  306. package/src/resources/beta/agents/sessions/index.ts +7 -1
  307. package/src/resources/beta/agents/sessions/sessions.ts +18 -8
  308. package/src/resources/beta/agents/sessions/subagents/turns/turns.ts +2 -2
  309. package/src/resources/beta/agents/sessions/turns/index.ts +4 -0
  310. package/src/resources/beta/agents/sessions/turns/items.ts +79 -0
  311. package/src/resources/beta/agents/sessions/turns/turns.ts +383 -0
  312. package/src/resources/beta/agents/sessions/turns.ts +1 -373
  313. package/src/resources/beta/beta.ts +2 -0
  314. package/src/resources/beta/index.ts +1 -0
  315. package/src/resources/beta/responses/index.ts +1 -0
  316. package/src/resources/beta/responses/responses.ts +471 -8
  317. package/src/resources/chat/completions/completions.ts +67 -19
  318. package/src/resources/completions.ts +1 -1
  319. package/src/resources/decisions.ts +290 -0
  320. package/src/resources/fine-tuning/jobs/jobs.ts +7 -2
  321. package/src/resources/graders/grader-models.ts +1 -1
  322. package/src/resources/images.ts +62 -76
  323. package/src/resources/index.ts +9 -0
  324. package/src/resources/realtime/realtime.ts +16 -4
  325. package/src/resources/responses/api.md +1 -0
  326. package/src/resources/responses/responses.ts +473 -8
  327. package/src/resources/shared.ts +70 -0
  328. package/src/resources/videos.ts +6 -0
  329. package/src/resources/webhooks/api.md +5 -0
  330. package/src/resources/webhooks/webhooks.ts +273 -1
  331. package/src/version.ts +1 -1
  332. package/version.d.mts +1 -1
  333. package/version.d.ts +1 -1
  334. package/version.js +1 -1
  335. package/version.mjs +1 -1
@@ -276,6 +276,14 @@ function getInputToolByName(
276
276
  );
277
277
  }
278
278
  }
279
+ // Hosted discovery exposes a deferred top-level function under its own name.
280
+ // A declared namespace above owns that identity, even if it has no matching function.
281
+ if (namespace === name) {
282
+ return input_tools.find(
283
+ (tool): tool is FunctionTool =>
284
+ tool.type === 'function' && tool.name === name && tool.defer_loading === true,
285
+ );
286
+ }
279
287
  return undefined;
280
288
  }
281
289
 
@@ -1,16 +1,15 @@
1
1
  import type { AgentOutputFormat, AgentResult } from '../beta/agents/output-format-types';
2
2
  import { TurnState } from './turn-state';
3
+ import { AgentToolDispatcher } from '../beta/agents/tool-dispatcher';
3
4
  import { agentFormatParser, parseAgentResultPromise } from '../beta/agents/parse-result';
4
5
  import { ResultCollection } from '../beta/agents/result-collection';
5
- import { APIUserAbortError, BadRequestError, OpenAIError } from '../../core/error';
6
+ import { APIUserAbortError, OpenAIError } from '../../core/error';
6
7
  import type { Stream } from '../../core/streaming';
7
8
  import { buildHeaders } from '../../internal/headers';
8
9
  import type { RequestOptions } from '../../internal/request-options';
9
10
  import { uuid4 } from '../../internal/utils/uuid';
10
- import { isObj } from '../../internal/utils/values';
11
- import { isInputContent } from '../beta/agents/tool-output';
11
+ import type { AgentToolError } from '../beta/agents/tool-error';
12
12
  import type {
13
- AgentFunctionCallItem,
14
13
  AgentFunctionCallOutputParam,
15
14
  AgentSessionEvent,
16
15
  AgentSessionInputMessageParam,
@@ -33,39 +32,16 @@ export type AgentSessionStreamParams<T = never> = {
33
32
  input: string | AgentSessionInputMessageParam[];
34
33
  /** Registered functions run after their call event is yielded; unknown functions remain manual. */
35
34
  toolHandlers?: Record<string, AgentToolHandler>;
35
+ /**
36
+ * Beta: use alongside `toolHandlers` to log or monitor local argument validation,
37
+ * handler execution, and output serialization failures. Does not observe API or
38
+ * transport errors. Observer errors are ignored; model-visible errors remain sanitized.
39
+ */
40
+ onToolError?: (failure: AgentToolError) => void | PromiseLike<void>;
36
41
  /** Key for the input submission only; request headers take precedence, case-insensitively. */
37
42
  idempotencyKey?: string;
38
43
  } & ([T] extends [never] ? unknown : { outputFormat: AgentOutputFormat<T> });
39
44
 
40
- type ToolResult = AgentSessionInputParam.SessionInputParamAgentSessionInputToolResult;
41
-
42
- function normalizedOutput(value: unknown): AgentFunctionCallOutputParam | null {
43
- if (value === null) {
44
- return null;
45
- }
46
- if (typeof value === 'string' || (Array.isArray(value) && value.every(isInputContent))) {
47
- return value;
48
- }
49
- throw new OpenAIError('Tool output must be text, content, a JSON object, or null');
50
- }
51
-
52
- // oxlint-disable-next-line anti-slop/no-object-parameters -- The public AgentToolOutput contract accepts arbitrary JSON-serializable object results.
53
- function toolResult(call: AgentFunctionCallItem, value: AgentToolOutput): ToolResult {
54
- const output = isObj(value) ? JSON.stringify(value) : value;
55
- // Detect unserializable callback results inside the redacted failure boundary.
56
- const serialized = JSON.stringify(output);
57
- if (serialized === undefined) {
58
- throw new OpenAIError('Tool output must be JSON serializable');
59
- }
60
- return {
61
- type: 'agent.session.input.tool_result',
62
- turn_id: call.turn_id,
63
- call_id: call.call_id,
64
- success: true,
65
- output: normalizedOutput(typeof output === 'string' ? output : JSON.parse(serialized)),
66
- };
67
- }
68
-
69
45
  async function cancelBody(response: Response | undefined): Promise<void> {
70
46
  try {
71
47
  await response?.body?.cancel();
@@ -100,7 +76,7 @@ export class AgentSessionStream<T = never> implements AsyncIterable<AgentSession
100
76
  #sessions: Sessions;
101
77
  #sessionID: string;
102
78
  #input: AgentSessionInputParam.SessionInputParamAgentSessionInputMessage;
103
- #handlers: Map<string, AgentToolHandler>;
79
+ #dispatcher: AgentToolDispatcher;
104
80
  #inputKey: string | undefined;
105
81
  #options: RequestOptions;
106
82
 
@@ -125,7 +101,6 @@ export class AgentSessionStream<T = never> implements AsyncIterable<AgentSession
125
101
  this.#sessions = sessions;
126
102
  this.#sessionID = sessionID;
127
103
  this.#input = { type: 'agent.session.input.message', input };
128
- this.#handlers = new Map(Object.entries(params.toolHandlers ?? {}));
129
104
  const headers = buildHeaders([options?.headers]);
130
105
  this.#inputKey = headers.nulls.has('idempotency-key')
131
106
  ? undefined
@@ -137,9 +112,16 @@ export class AgentSessionStream<T = never> implements AsyncIterable<AgentSession
137
112
  headers.nulls.delete('idempotency-key');
138
113
  const { idempotencyKey: _key, ...rest } = options ?? {};
139
114
  this.#options = { ...rest, headers };
115
+ this.#dispatcher = new AgentToolDispatcher(
116
+ sessions,
117
+ params.toolHandlers ?? {},
118
+ this.controller,
119
+ this.#options,
120
+ params.onToolError,
121
+ );
140
122
  this.#collection = new ResultCollection(
141
123
  () => this.#iterate(),
142
- (name) => this.#handlers.has(name),
124
+ (name) => this.#dispatcher.canHandle(name),
143
125
  sessionID,
144
126
  );
145
127
  }
@@ -216,10 +198,7 @@ export class AgentSessionStream<T = never> implements AsyncIterable<AgentSession
216
198
  continue;
217
199
  }
218
200
  const terminal = state.terminal(event);
219
- const pendingCall = state.call(event);
220
- const handler = pendingCall && this.#handlers.get(pendingCall.name);
221
- // Freeze dispatch identity and arguments before exposing the original event.
222
- const call = pendingCall && handler ? structuredClone(pendingCall) : undefined;
201
+ const dispatch = this.#dispatcher.prepare(state.call(event), this.#sessionID);
223
202
  if (terminal) {
224
203
  this.#stream.controller.abort();
225
204
  }
@@ -228,12 +207,7 @@ export class AgentSessionStream<T = never> implements AsyncIterable<AgentSession
228
207
  return;
229
208
  }
230
209
  this.#checkAbort();
231
- if (!call || !handler) {
232
- continue;
233
- }
234
- const result = await this.#result(call, handler);
235
- this.#checkAbort();
236
- await this.#submit(result, options);
210
+ await dispatch?.();
237
211
  }
238
212
  this.#checkAbort();
239
213
  throw new OpenAIError('Session event stream ended before the turn reached idle or failed');
@@ -244,26 +218,6 @@ export class AgentSessionStream<T = never> implements AsyncIterable<AgentSession
244
218
  }
245
219
  }
246
220
 
247
- async #result(call: AgentFunctionCallItem, handler: AgentToolHandler): Promise<ToolResult> {
248
- try {
249
- const args: unknown = typeof call.arguments === 'string' ? JSON.parse(call.arguments) : call.arguments;
250
- if (!isObj(args)) {
251
- throw new OpenAIError('Function arguments must be a JSON object');
252
- }
253
- // SAFETY: Arguments were parsed as JSON and checked to be a non-null non-array object before invoking the handler.
254
- return toolResult(call, await this.#wait(() => handler(args as Record<string, unknown>)));
255
- } catch {
256
- this.#checkAbort();
257
- return {
258
- type: 'agent.session.input.tool_result',
259
- turn_id: call.turn_id,
260
- call_id: call.call_id,
261
- success: false,
262
- error: 'Tool handler failed.',
263
- };
264
- }
265
- }
266
-
267
221
  #checkAbort(): void {
268
222
  if (this.controller.signal.aborted) {
269
223
  throw this.#abortError();
@@ -279,62 +233,4 @@ export class AgentSessionStream<T = never> implements AsyncIterable<AgentSession
279
233
  });
280
234
  return error;
281
235
  }
282
-
283
- async #wait<Value>(action: () => Value | PromiseLike<Value>): Promise<Value> {
284
- let onAbort: (() => void) | undefined;
285
- // oxlint-disable-next-line promise/avoid-new -- Bridge the caller's AbortSignal while a handler or registration delay is pending.
286
- const aborted = new Promise<never>((_resolve, reject) => {
287
- onAbort = () => reject(this.#abortError());
288
- this.controller.signal.addEventListener('abort', onAbort, { once: true });
289
- });
290
- try {
291
- this.#checkAbort();
292
- // Capture synchronous throws before racing cancellation, so both promises
293
- // always have rejection handlers even if the callback aborts and throws.
294
- const invoke = async () => await action();
295
- return await Promise.race([invoke(), aborted]);
296
- } finally {
297
- if (onAbort) {
298
- this.controller.signal.removeEventListener('abort', onAbort);
299
- }
300
- }
301
- }
302
-
303
- async #submit(result: ToolResult, options: RequestOptions, key = uuid4(), attempt = 0): Promise<void> {
304
- this.#checkAbort();
305
- try {
306
- await this.#sessions.events.create(
307
- this.#sessionID,
308
- { events: [result], 'Idempotency-Key': key },
309
- options,
310
- );
311
- } catch (error) {
312
- const delay = [100, 300, 600][attempt];
313
- if (
314
- delay === undefined ||
315
- !(error instanceof BadRequestError) ||
316
- error.code !== 'invalid_request_error' ||
317
- !error.error ||
318
- !('message' in error.error) ||
319
- error.error.message !== `Unknown pending tool call: ${result.call_id}`
320
- ) {
321
- throw error;
322
- }
323
- let timer: ReturnType<typeof setTimeout> | undefined;
324
- try {
325
- await this.#wait(
326
- () =>
327
- // oxlint-disable-next-line promise/avoid-new -- Own the registration timer so cancellation clears it promptly.
328
- new Promise<void>((resolve) => {
329
- timer = setTimeout(resolve, delay);
330
- }),
331
- );
332
- } finally {
333
- if (timer !== undefined) {
334
- clearTimeout(timer);
335
- }
336
- }
337
- await this.#submit(result, options, key, attempt + 1);
338
- }
339
- }
340
236
  }
@@ -1,3 +1,10 @@
1
+ import { APIUserAbortError, OpenAIError } from '../../../core/error';
2
+ import { buildHeaders } from '../../../internal/headers';
3
+ import type { RequestOptions } from '../../../internal/request-options';
4
+ import type { Sessions, SessionCreateParams } from '../../../resources/beta/agents/sessions/sessions';
5
+ import type { AgentToolHandler } from '../../agents/agent-session-stream';
6
+ import { TurnState } from '../../agents/turn-state';
7
+ import { AgentToolDispatcher } from './tool-dispatcher';
1
8
  import type { AgentOutputFormat, AgentResult } from './output-format-types';
2
9
  import type { Stream } from '../../../core/streaming';
3
10
  import type { AgentSessionEvent } from '../../../resources/beta/agents/agents';
@@ -12,16 +19,57 @@ export type AgentSessionCreateStream<T = never> = Stream<AgentSessionEvent> & {
12
19
  withResultCollection: () => AgentSessionCreateStream<T>;
13
20
  };
14
21
 
22
+ async function* dispatchCreationTools(
23
+ source: () => AsyncIterator<AgentSessionEvent>,
24
+ dispatcher: AgentToolDispatcher,
25
+ signal: AbortSignal,
26
+ ): AsyncGenerator<AgentSessionEvent> {
27
+ const state = new TurnState();
28
+ let sessionID: string | undefined;
29
+ for await (const event of { [Symbol.asyncIterator]: source }) {
30
+ if (event.type === 'agent.session.created') {
31
+ sessionID ??= event.session.id;
32
+ }
33
+ const dispatch = state.accept(event) ? dispatcher.prepare(state.call(event), sessionID) : undefined;
34
+ yield event;
35
+ if (signal.aborted) {
36
+ return;
37
+ }
38
+ try {
39
+ await dispatch?.();
40
+ } catch (error) {
41
+ if (signal.aborted && error instanceof APIUserAbortError) {
42
+ return;
43
+ }
44
+ throw error;
45
+ }
46
+ }
47
+ }
48
+
15
49
  /** Add beta result collection without replacing custom stream instances.
16
50
  * @internal
17
51
  */
18
52
  export function withAgentTurnResult<T = never>(
19
53
  stream: Stream<AgentSessionEvent>,
20
54
  format?: AgentOutputFormat<T>,
55
+ tools?: {
56
+ sessions: Sessions;
57
+ handlers: Record<string, AgentToolHandler>;
58
+ options?: RequestOptions | undefined;
59
+ },
21
60
  ): AgentSessionCreateStream<T> {
22
61
  let collection: ResultCollection;
23
62
  stream.__betaTransformIterator((source) => {
24
- collection = new ResultCollection(source, undefined, undefined, stream.controller.signal);
63
+ // A tool result has its own POST endpoint, independent of creation overrides.
64
+ const { path: _path, method: _method, stream: _stream, ...options } = tools?.options ?? {};
65
+ const dispatcher =
66
+ tools && new AgentToolDispatcher(tools.sessions, tools.handlers, stream.controller, options);
67
+ collection = new ResultCollection(
68
+ dispatcher ? () => dispatchCreationTools(source, dispatcher, stream.controller.signal) : source,
69
+ dispatcher ? (name) => dispatcher.canHandle(name) : undefined,
70
+ undefined,
71
+ stream.controller.signal,
72
+ );
25
73
  return () => collection.iterate();
26
74
  });
27
75
  let parsed: Promise<AgentResult<T>> | undefined;
@@ -34,3 +82,41 @@ export function withAgentTurnResult<T = never>(
34
82
  });
35
83
  return result;
36
84
  }
85
+
86
+ /** Remove local callbacks without changing ordinary creation requests. @internal */
87
+ export function captureCreationTools(body: SessionCreateParams, options?: RequestOptions) {
88
+ const descriptor = Object.getOwnPropertyDescriptor(body, 'toolHandlers');
89
+ if (!descriptor) {
90
+ return { body, options };
91
+ }
92
+ const handlers = body.toolHandlers;
93
+ if (handlers === undefined && 'value' in descriptor) {
94
+ return { body, options };
95
+ }
96
+ const descriptors = Object.getOwnPropertyDescriptors(body);
97
+ delete descriptors.toolHandlers;
98
+ const capturedOptions = { ...options };
99
+ if ('toJSON' in body || capturedOptions.body !== undefined) {
100
+ throw new OpenAIError('Creation tool handlers cannot customize request body serialization');
101
+ }
102
+ if (handlers === undefined) {
103
+ // SAFETY: Preserve request fields while removing the accessor so serialization cannot evaluate it again.
104
+ return {
105
+ body: Object.create(Object.getPrototypeOf(body), descriptors) as SessionCreateParams,
106
+ options: capturedOptions,
107
+ };
108
+ }
109
+ const { stream } = body;
110
+ if (stream !== true) {
111
+ throw new OpenAIError('toolHandlers requires stream: true');
112
+ }
113
+ capturedOptions.headers = buildHeaders([capturedOptions.headers]);
114
+ descriptors.stream = { value: stream, enumerable: true, configurable: true, writable: true };
115
+ // SAFETY: Preserve request fields, omitting callbacks and fixing the validated streaming mode.
116
+ const request = Object.create(Object.getPrototypeOf(body), descriptors) as SessionCreateParams;
117
+ return {
118
+ body: request,
119
+ options: capturedOptions,
120
+ handlers: handlers && Object.fromEntries(Object.entries(handlers)),
121
+ };
122
+ }
@@ -3,6 +3,8 @@ import type { AgentToolHandler } from '../../agents/agent-session-stream';
3
3
  import type { AutoParseableResponseTool } from '../../ResponsesParser';
4
4
  import type { AgentToolParam } from '../../../resources/beta/agents/agents';
5
5
  import { isInputContent } from './tool-output';
6
+ import { toolStages } from './tool-stages';
7
+ import type { StagedToolHandler } from './tool-stages';
6
8
 
7
9
  /** A beta Agents function definition paired with its local, validating handler. */
8
10
  export interface AgentFunctionTool {
@@ -32,6 +34,26 @@ export function functionTool<Arguments>(
32
34
  if (!execute || !tool.parameters) {
33
35
  throw new OpenAIError('Agents function tools require a callback and argument schema');
34
36
  }
37
+ const handler: StagedToolHandler = async (arguments_, setStage) => {
38
+ setStage?.('arguments');
39
+ const parsed = parse(JSON.stringify(arguments_));
40
+ setStage?.('execution');
41
+ const result: unknown = await execute(parsed);
42
+ setStage?.('output');
43
+ if (Array.isArray(result)) {
44
+ return result.length > 0 && result.every(isInputContent) ? result : JSON.stringify(result);
45
+ }
46
+ // oxlint-disable-next-line anti-slop/no-runtime-typeof -- Existing schema-tool callbacks return arbitrary application values; adapt them to the Agents dispatcher's output contract.
47
+ if (typeof result === 'object' || typeof result === 'string') {
48
+ return result;
49
+ }
50
+ const text = result === undefined ? 'undefined' : JSON.stringify(result);
51
+ if (text === undefined) {
52
+ throw new OpenAIError('Tool output must be JSON serializable');
53
+ }
54
+ return text;
55
+ };
56
+ Object.defineProperty(handler, toolStages, { value: true });
35
57
  return {
36
58
  name: tool.name,
37
59
  definition: {
@@ -41,20 +63,6 @@ export function functionTool<Arguments>(
41
63
  parameters: tool.parameters,
42
64
  ...(tool.defer_loading === undefined ? {} : { defer_loading: tool.defer_loading }),
43
65
  },
44
- handler: async (arguments_) => {
45
- const result: unknown = await execute(parse(JSON.stringify(arguments_)));
46
- if (Array.isArray(result)) {
47
- return result.length > 0 && result.every(isInputContent) ? result : JSON.stringify(result);
48
- }
49
- // oxlint-disable-next-line anti-slop/no-runtime-typeof -- Existing schema-tool callbacks return arbitrary application values; adapt them to the Agents dispatcher's output contract.
50
- if (typeof result === 'object' || typeof result === 'string') {
51
- return result;
52
- }
53
- const text = result === undefined ? 'undefined' : JSON.stringify(result);
54
- if (text === undefined) {
55
- throw new OpenAIError('Tool output must be JSON serializable');
56
- }
57
- return text;
58
- },
66
+ handler,
59
67
  };
60
68
  }
@@ -0,0 +1,226 @@
1
+ import { APIUserAbortError, BadRequestError, OpenAIError } from '../../../core/error';
2
+ import { buildHeaders } from '../../../internal/headers';
3
+ import type { RequestOptions } from '../../../internal/request-options';
4
+ import { uuid4 } from '../../../internal/utils/uuid';
5
+ import { isObj } from '../../../internal/utils/values';
6
+ import { isInputContent } from './tool-output';
7
+ import type { AgentToolError } from './tool-error';
8
+ import { toolStages } from './tool-stages';
9
+ import type { StagedToolHandler } from './tool-stages';
10
+ import type {
11
+ AgentToolHandler,
12
+ AgentToolOutput,
13
+ AgentSessionStreamParams,
14
+ } from '../../agents/agent-session-stream';
15
+ import type {
16
+ AgentFunctionCallItem,
17
+ AgentFunctionCallOutputParam,
18
+ AgentSessionInputParam,
19
+ } from '../../../resources/beta/agents/agents';
20
+ import type { Sessions } from '../../../resources/beta/agents/sessions/sessions';
21
+
22
+ type ToolResult = AgentSessionInputParam.SessionInputParamAgentSessionInputToolResult;
23
+
24
+ function normalizedOutput(value: unknown): AgentFunctionCallOutputParam | null {
25
+ if (value === null) {
26
+ return null;
27
+ }
28
+ if (typeof value === 'string' || (Array.isArray(value) && value.every(isInputContent))) {
29
+ return value;
30
+ }
31
+ throw new OpenAIError('Tool output must be text, content, a JSON object, or null');
32
+ }
33
+
34
+ // oxlint-disable-next-line anti-slop/no-object-parameters -- The public AgentToolOutput contract accepts arbitrary JSON-serializable object results.
35
+ function toolResult(call: AgentFunctionCallItem, value: AgentToolOutput): ToolResult {
36
+ const output = isObj(value) ? JSON.stringify(value) : value;
37
+ // Detect unserializable callback results inside the redacted failure boundary.
38
+ const serialized = JSON.stringify(output);
39
+ if (serialized === undefined) {
40
+ throw new OpenAIError('Tool output must be JSON serializable');
41
+ }
42
+ return {
43
+ type: 'agent.session.input.tool_result',
44
+ turn_id: call.turn_id,
45
+ call_id: call.call_id,
46
+ success: true,
47
+ output: normalizedOutput(typeof output === 'string' ? output : JSON.parse(serialized)),
48
+ };
49
+ }
50
+
51
+ /** Shared local function dispatch for creation and follow-up streams. @internal */
52
+ export class AgentToolDispatcher {
53
+ readonly #handlers: Map<string, AgentToolHandler>;
54
+ readonly #options: RequestOptions;
55
+ readonly #sessions: Sessions;
56
+ readonly #controller: AbortController;
57
+ readonly #onToolError: AgentSessionStreamParams['onToolError'];
58
+
59
+ constructor(
60
+ sessions: Sessions,
61
+ handlers: Record<string, AgentToolHandler>,
62
+ controller: AbortController,
63
+ options?: RequestOptions,
64
+ onToolError?: AgentSessionStreamParams['onToolError'],
65
+ ) {
66
+ this.#sessions = sessions;
67
+ this.#controller = controller;
68
+ this.#onToolError = onToolError;
69
+ this.#handlers = new Map(Object.entries(handlers));
70
+ const headers = buildHeaders([options?.headers]);
71
+ headers.values.delete('idempotency-key');
72
+ headers.nulls.delete('idempotency-key');
73
+ const { idempotencyKey: _key, ...rest } = options ?? {};
74
+ this.#options = { ...rest, headers, signal: controller.signal };
75
+ }
76
+
77
+ canHandle(name: string): boolean {
78
+ return typeof this.#handlers.get(name) === 'function';
79
+ }
80
+
81
+ /** Capture routing and arguments before the caller can mutate the yielded event. */
82
+ prepare(
83
+ call: AgentFunctionCallItem | undefined,
84
+ sessionID: string | undefined,
85
+ ): (() => Promise<void>) | undefined {
86
+ const handler = call && this.#handlers.get(call.name);
87
+ if (!call || typeof handler !== 'function') {
88
+ return;
89
+ }
90
+ if (!sessionID) {
91
+ throw new OpenAIError('Tool call received before the session creation event');
92
+ }
93
+ const snapshot = structuredClone(call);
94
+ return async () => {
95
+ this.#checkAbort();
96
+ const result = await this.#result(snapshot, handler, sessionID);
97
+ this.#checkAbort();
98
+ await this.#submit(sessionID, result);
99
+ };
100
+ }
101
+
102
+ async #result(
103
+ call: AgentFunctionCallItem,
104
+ handler: StagedToolHandler,
105
+ sessionID: string,
106
+ ): Promise<ToolResult> {
107
+ let stage: AgentToolError['stage'] = 'arguments';
108
+ try {
109
+ const args: unknown = typeof call.arguments === 'string' ? JSON.parse(call.arguments) : call.arguments;
110
+ if (!isObj(args)) {
111
+ throw new OpenAIError('Function arguments must be a JSON object');
112
+ }
113
+ stage = 'execution';
114
+ // SAFETY: Arguments were parsed as JSON and checked to be a non-null non-array object before invoking the handler.
115
+ const arguments_ = args as Record<string, unknown>;
116
+ const output = await this.#wait(() =>
117
+ this.#onToolError && handler[toolStages]
118
+ ? handler(arguments_, (value) => {
119
+ stage = value;
120
+ })
121
+ : handler(arguments_),
122
+ );
123
+ stage = 'output';
124
+ return toolResult(call, output);
125
+ } catch (error) {
126
+ this.#checkAbort();
127
+ if (this.#onToolError) {
128
+ const failure: AgentToolError = Object.freeze({
129
+ error,
130
+ stage,
131
+ tool_name: call.name,
132
+ session_id: sessionID,
133
+ turn_id: call.turn_id,
134
+ call_id: call.call_id,
135
+ });
136
+ try {
137
+ await this.#wait(() => this.#onToolError?.(failure));
138
+ } catch {
139
+ // Observers must not prevent the original sanitized tool failure from being submitted.
140
+ this.#checkAbort();
141
+ }
142
+ }
143
+ return {
144
+ type: 'agent.session.input.tool_result',
145
+ turn_id: call.turn_id,
146
+ call_id: call.call_id,
147
+ success: false,
148
+ error: 'Tool handler failed.',
149
+ };
150
+ }
151
+ }
152
+
153
+ #checkAbort(): void {
154
+ if (this.#controller.signal.aborted) {
155
+ throw this.#abortError();
156
+ }
157
+ }
158
+
159
+ #abortError(): APIUserAbortError {
160
+ const error = new APIUserAbortError();
161
+ Object.defineProperty(error, 'cause', {
162
+ value: this.#controller.signal.reason,
163
+ writable: true,
164
+ configurable: true,
165
+ });
166
+ return error;
167
+ }
168
+
169
+ async #wait<Value>(action: () => Value | PromiseLike<Value>): Promise<Value> {
170
+ let onAbort: (() => void) | undefined;
171
+ // oxlint-disable-next-line promise/avoid-new -- Bridge the caller's AbortSignal while a handler or registration delay is pending.
172
+ const aborted = new Promise<never>((_resolve, reject) => {
173
+ onAbort = () => reject(this.#abortError());
174
+ this.#controller.signal.addEventListener('abort', onAbort, { once: true });
175
+ });
176
+ try {
177
+ this.#checkAbort();
178
+ // Capture synchronous throws before racing cancellation, so both promises
179
+ // always have rejection handlers even if the callback aborts and throws.
180
+ const invoke = async () => await action();
181
+ return await Promise.race([invoke(), aborted]);
182
+ } finally {
183
+ if (onAbort) {
184
+ this.#controller.signal.removeEventListener('abort', onAbort);
185
+ }
186
+ }
187
+ }
188
+
189
+ async #submit(sessionID: string, result: ToolResult, key = uuid4(), attempt = 0): Promise<void> {
190
+ this.#checkAbort();
191
+ try {
192
+ await this.#sessions.events.create(
193
+ sessionID,
194
+ { events: [result], 'Idempotency-Key': key },
195
+ this.#options,
196
+ );
197
+ } catch (error) {
198
+ const delay = [100, 300, 600][attempt];
199
+ if (
200
+ delay === undefined ||
201
+ !(error instanceof BadRequestError) ||
202
+ error.code !== 'invalid_request_error' ||
203
+ !error.error ||
204
+ !('message' in error.error) ||
205
+ error.error.message !== `Unknown pending tool call: ${result.call_id}`
206
+ ) {
207
+ throw error;
208
+ }
209
+ let timer: ReturnType<typeof setTimeout> | undefined;
210
+ try {
211
+ await this.#wait(
212
+ () =>
213
+ // oxlint-disable-next-line promise/avoid-new -- Own the registration timer so cancellation clears it promptly.
214
+ new Promise<void>((resolve) => {
215
+ timer = setTimeout(resolve, delay);
216
+ }),
217
+ );
218
+ } finally {
219
+ if (timer !== undefined) {
220
+ clearTimeout(timer);
221
+ }
222
+ }
223
+ await this.#submit(sessionID, result, key, attempt + 1);
224
+ }
225
+ }
226
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Beta diagnostic for logging or monitoring failures from local `toolHandlers`.
3
+ * The original error is local only; API and transport failures propagate separately.
4
+ */
5
+ export interface AgentToolError {
6
+ readonly error: unknown;
7
+ readonly tool_name: string;
8
+ readonly session_id: string;
9
+ readonly turn_id: string;
10
+ readonly call_id: string;
11
+ readonly stage: 'arguments' | 'execution' | 'output';
12
+ }
@@ -0,0 +1,14 @@
1
+ import type { AgentToolHandler } from '../../agents/agent-session-stream';
2
+ import type { AgentToolError } from './tool-error';
3
+
4
+ /** @internal */
5
+ export const toolStages = Symbol.for('openai.beta.agents.toolStages');
6
+
7
+ /**
8
+ * Marks handlers that accept stage updates, including across ESM/CJS imports.
9
+ * @internal
10
+ */
11
+ export type StagedToolHandler = ((
12
+ arguments_: Parameters<AgentToolHandler>[0],
13
+ setStage?: (stage: AgentToolError['stage']) => void,
14
+ ) => ReturnType<AgentToolHandler>) & { [toolStages]?: true };