@earendil-works/pi-ai 1.3.0 → 1.5.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 (304) hide show
  1. package/README.md +113 -38
  2. package/dist/api/anthropic-messages.d.ts.map +1 -1
  3. package/dist/api/anthropic-messages.js +66 -81
  4. package/dist/api/anthropic-messages.js.map +1 -1
  5. package/dist/api/azure-openai-responses.d.ts.map +1 -1
  6. package/dist/api/azure-openai-responses.js +8 -10
  7. package/dist/api/azure-openai-responses.js.map +1 -1
  8. package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  9. package/dist/api/bedrock-converse-stream.js +137 -103
  10. package/dist/api/bedrock-converse-stream.js.map +1 -1
  11. package/dist/api/classifier-shared.d.ts.map +1 -1
  12. package/dist/api/classifier-shared.js +4 -3
  13. package/dist/api/classifier-shared.js.map +1 -1
  14. package/dist/api/cloudflare-workers-ai-system-one.d.ts.map +1 -1
  15. package/dist/api/cloudflare-workers-ai-system-one.js +8 -0
  16. package/dist/api/cloudflare-workers-ai-system-one.js.map +1 -1
  17. package/dist/api/constrained-sampling.d.ts +15 -1
  18. package/dist/api/constrained-sampling.d.ts.map +1 -1
  19. package/dist/api/constrained-sampling.js +51 -18
  20. package/dist/api/constrained-sampling.js.map +1 -1
  21. package/dist/api/google-generative-ai.d.ts.map +1 -1
  22. package/dist/api/google-generative-ai.js +4 -10
  23. package/dist/api/google-generative-ai.js.map +1 -1
  24. package/dist/api/google-shared.d.ts +2 -1
  25. package/dist/api/google-shared.d.ts.map +1 -1
  26. package/dist/api/google-shared.js +58 -3
  27. package/dist/api/google-shared.js.map +1 -1
  28. package/dist/api/google-vertex.d.ts.map +1 -1
  29. package/dist/api/google-vertex.js +9 -15
  30. package/dist/api/google-vertex.js.map +1 -1
  31. package/dist/api/lazy.d.ts +7 -2
  32. package/dist/api/lazy.d.ts.map +1 -1
  33. package/dist/api/lazy.js +24 -5
  34. package/dist/api/lazy.js.map +1 -1
  35. package/dist/api/llama-cpp-classify.d.ts.map +1 -1
  36. package/dist/api/llama-cpp-classify.js +2 -1
  37. package/dist/api/llama-cpp-classify.js.map +1 -1
  38. package/dist/api/mistral-conversations.d.ts.map +1 -1
  39. package/dist/api/mistral-conversations.js +19 -46
  40. package/dist/api/mistral-conversations.js.map +1 -1
  41. package/dist/api/openai-codex-responses.d.ts.map +1 -1
  42. package/dist/api/openai-codex-responses.js +17 -16
  43. package/dist/api/openai-codex-responses.js.map +1 -1
  44. package/dist/api/openai-completions.d.ts.map +1 -1
  45. package/dist/api/openai-completions.js +56 -62
  46. package/dist/api/openai-completions.js.map +1 -1
  47. package/dist/api/openai-responses-shared.d.ts +16 -0
  48. package/dist/api/openai-responses-shared.d.ts.map +1 -1
  49. package/dist/api/openai-responses-shared.js +119 -66
  50. package/dist/api/openai-responses-shared.js.map +1 -1
  51. package/dist/api/openai-responses.d.ts.map +1 -1
  52. package/dist/api/openai-responses.js +17 -15
  53. package/dist/api/openai-responses.js.map +1 -1
  54. package/dist/api/openrouter-images.d.ts.map +1 -1
  55. package/dist/api/openrouter-images.js +5 -3
  56. package/dist/api/openrouter-images.js.map +1 -1
  57. package/dist/api/pi-messages.d.ts +2 -0
  58. package/dist/api/pi-messages.d.ts.map +1 -1
  59. package/dist/api/pi-messages.js +27 -12
  60. package/dist/api/pi-messages.js.map +1 -1
  61. package/dist/api/simple-options.d.ts.map +1 -1
  62. package/dist/api/simple-options.js +2 -1
  63. package/dist/api/simple-options.js.map +1 -1
  64. package/dist/api/system-one-shared.d.ts +29 -2
  65. package/dist/api/system-one-shared.d.ts.map +1 -1
  66. package/dist/api/system-one-shared.js +55 -3
  67. package/dist/api/system-one-shared.js.map +1 -1
  68. package/dist/api/typesafe-system-one.d.ts.map +1 -1
  69. package/dist/api/typesafe-system-one.js +10 -0
  70. package/dist/api/typesafe-system-one.js.map +1 -1
  71. package/dist/auth/oauth/github-copilot.d.ts.map +1 -1
  72. package/dist/auth/oauth/github-copilot.js +4 -11
  73. package/dist/auth/oauth/github-copilot.js.map +1 -1
  74. package/dist/auth/oauth/kimi-coding.d.ts.map +1 -1
  75. package/dist/auth/oauth/kimi-coding.js +4 -22
  76. package/dist/auth/oauth/kimi-coding.js.map +1 -1
  77. package/dist/auth/oauth/meta.d.ts.map +1 -1
  78. package/dist/auth/oauth/meta.js +1 -14
  79. package/dist/auth/oauth/meta.js.map +1 -1
  80. package/dist/auth/oauth/radius.d.ts.map +1 -1
  81. package/dist/auth/oauth/radius.js +9 -3
  82. package/dist/auth/oauth/radius.js.map +1 -1
  83. package/dist/auth/oauth/trusted-url.d.ts +7 -0
  84. package/dist/auth/oauth/trusted-url.d.ts.map +1 -0
  85. package/dist/auth/oauth/trusted-url.js +12 -0
  86. package/dist/auth/oauth/trusted-url.js.map +1 -0
  87. package/dist/auth/types.d.ts +4 -0
  88. package/dist/auth/types.d.ts.map +1 -1
  89. package/dist/auth/types.js.map +1 -1
  90. package/dist/cli.js +6 -2
  91. package/dist/cli.js.map +1 -1
  92. package/dist/compat/extension-oauth-types.d.ts +4 -0
  93. package/dist/compat/extension-oauth-types.d.ts.map +1 -1
  94. package/dist/compat/extension-oauth-types.js.map +1 -1
  95. package/dist/index.d.ts +4 -3
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +4 -2
  98. package/dist/index.js.map +1 -1
  99. package/dist/models.d.ts +4 -0
  100. package/dist/models.d.ts.map +1 -1
  101. package/dist/models.generated.js +1 -1
  102. package/dist/models.generated.js.map +1 -1
  103. package/dist/models.js +20 -6
  104. package/dist/models.js.map +1 -1
  105. package/dist/providers/amazon-bedrock.models.js +1 -1
  106. package/dist/providers/amazon-bedrock.models.js.map +1 -1
  107. package/dist/providers/ant-ling.models.js +1 -1
  108. package/dist/providers/ant-ling.models.js.map +1 -1
  109. package/dist/providers/anthropic.models.js +1 -1
  110. package/dist/providers/anthropic.models.js.map +1 -1
  111. package/dist/providers/azure.models.js +1 -1
  112. package/dist/providers/azure.models.js.map +1 -1
  113. package/dist/providers/baseten.models.js +1 -1
  114. package/dist/providers/baseten.models.js.map +1 -1
  115. package/dist/providers/cerebras.models.js +1 -1
  116. package/dist/providers/cerebras.models.js.map +1 -1
  117. package/dist/providers/cloudflare-ai-gateway.models.js +1 -1
  118. package/dist/providers/cloudflare-ai-gateway.models.js.map +1 -1
  119. package/dist/providers/cloudflare-workers-ai.models.js +1 -1
  120. package/dist/providers/cloudflare-workers-ai.models.js.map +1 -1
  121. package/dist/providers/compat-schema.d.ts +444 -304
  122. package/dist/providers/compat-schema.d.ts.map +1 -1
  123. package/dist/providers/compat-schema.js +155 -109
  124. package/dist/providers/compat-schema.js.map +1 -1
  125. package/dist/providers/data/.manifest.json +1 -1
  126. package/dist/providers/data/amazon-bedrock.json +1 -1
  127. package/dist/providers/data/anthropic.json +1 -1
  128. package/dist/providers/data/azure.json +1 -1
  129. package/dist/providers/data/baseten.json +1 -1
  130. package/dist/providers/data/cerebras.json +1 -1
  131. package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  132. package/dist/providers/data/cloudflare-workers-ai.json +1 -1
  133. package/dist/providers/data/fireworks.json +1 -1
  134. package/dist/providers/data/github-copilot.json +1 -1
  135. package/dist/providers/data/google-vertex.json +1 -1
  136. package/dist/providers/data/google.json +1 -1
  137. package/dist/providers/data/groq.json +1 -1
  138. package/dist/providers/data/huggingface.json +1 -1
  139. package/dist/providers/data/kimi-coding.json +1 -1
  140. package/dist/providers/data/minimax-cn.json +1 -1
  141. package/dist/providers/data/minimax.json +1 -1
  142. package/dist/providers/data/mistral.json +1 -1
  143. package/dist/providers/data/moonshotai-cn.json +1 -1
  144. package/dist/providers/data/moonshotai.json +1 -1
  145. package/dist/providers/data/nvidia.json +1 -1
  146. package/dist/providers/data/openai-codex.json +1 -1
  147. package/dist/providers/data/openai.json +1 -1
  148. package/dist/providers/data/opencode-go.json +1 -1
  149. package/dist/providers/data/opencode.json +1 -1
  150. package/dist/providers/data/openrouter.json +1 -1
  151. package/dist/providers/data/qwen-token-plan-cn.json +1 -1
  152. package/dist/providers/data/qwen-token-plan-individual.json +1 -1
  153. package/dist/providers/data/qwen-token-plan.json +1 -1
  154. package/dist/providers/data/radius.json +1 -1
  155. package/dist/providers/data/together.json +1 -1
  156. package/dist/providers/data/typesafe.json +1 -1
  157. package/dist/providers/data/vercel-ai-gateway.json +1 -1
  158. package/dist/providers/data/xai.json +1 -1
  159. package/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
  160. package/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
  161. package/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
  162. package/dist/providers/data/xiaomi.json +1 -1
  163. package/dist/providers/data/zai-coding-cn.json +1 -1
  164. package/dist/providers/data/zai.json +1 -1
  165. package/dist/providers/deepseek.models.js +1 -1
  166. package/dist/providers/deepseek.models.js.map +1 -1
  167. package/dist/providers/faux.d.ts.map +1 -1
  168. package/dist/providers/faux.js +7 -2
  169. package/dist/providers/faux.js.map +1 -1
  170. package/dist/providers/fireworks.models.js +1 -1
  171. package/dist/providers/fireworks.models.js.map +1 -1
  172. package/dist/providers/github-copilot.models.js +1 -1
  173. package/dist/providers/github-copilot.models.js.map +1 -1
  174. package/dist/providers/google-vertex.models.js +1 -1
  175. package/dist/providers/google-vertex.models.js.map +1 -1
  176. package/dist/providers/google.models.js +1 -1
  177. package/dist/providers/google.models.js.map +1 -1
  178. package/dist/providers/groq.models.js +1 -1
  179. package/dist/providers/groq.models.js.map +1 -1
  180. package/dist/providers/huggingface.models.js +1 -1
  181. package/dist/providers/huggingface.models.js.map +1 -1
  182. package/dist/providers/kimi-coding.models.js +1 -1
  183. package/dist/providers/kimi-coding.models.js.map +1 -1
  184. package/dist/providers/meta.models.js +1 -1
  185. package/dist/providers/meta.models.js.map +1 -1
  186. package/dist/providers/minimax-cn.models.js +1 -1
  187. package/dist/providers/minimax-cn.models.js.map +1 -1
  188. package/dist/providers/minimax.models.js +1 -1
  189. package/dist/providers/minimax.models.js.map +1 -1
  190. package/dist/providers/mistral.models.js +1 -1
  191. package/dist/providers/mistral.models.js.map +1 -1
  192. package/dist/providers/model-schema.d.ts +65 -65
  193. package/dist/providers/model-schema.d.ts.map +1 -1
  194. package/dist/providers/model-schema.js +44 -31
  195. package/dist/providers/model-schema.js.map +1 -1
  196. package/dist/providers/moonshotai-cn.models.js +1 -1
  197. package/dist/providers/moonshotai-cn.models.js.map +1 -1
  198. package/dist/providers/moonshotai.models.js +1 -1
  199. package/dist/providers/moonshotai.models.js.map +1 -1
  200. package/dist/providers/nvidia.models.js +1 -1
  201. package/dist/providers/nvidia.models.js.map +1 -1
  202. package/dist/providers/openai-codex.models.js +1 -1
  203. package/dist/providers/openai-codex.models.js.map +1 -1
  204. package/dist/providers/openai.models.js +1 -1
  205. package/dist/providers/openai.models.js.map +1 -1
  206. package/dist/providers/opencode-go.models.js +1 -1
  207. package/dist/providers/opencode-go.models.js.map +1 -1
  208. package/dist/providers/opencode.js +1 -1
  209. package/dist/providers/opencode.js.map +1 -1
  210. package/dist/providers/opencode.models.js +1 -1
  211. package/dist/providers/opencode.models.js.map +1 -1
  212. package/dist/providers/openrouter.models.js +1 -1
  213. package/dist/providers/openrouter.models.js.map +1 -1
  214. package/dist/providers/qwen-token-plan-cn.models.js +1 -1
  215. package/dist/providers/qwen-token-plan-cn.models.js.map +1 -1
  216. package/dist/providers/qwen-token-plan-individual.models.js +1 -1
  217. package/dist/providers/qwen-token-plan-individual.models.js.map +1 -1
  218. package/dist/providers/qwen-token-plan.models.js +1 -1
  219. package/dist/providers/qwen-token-plan.models.js.map +1 -1
  220. package/dist/providers/radius-config.d.ts.map +1 -1
  221. package/dist/providers/radius-config.js +2 -1
  222. package/dist/providers/radius-config.js.map +1 -1
  223. package/dist/providers/radius.models.js +1 -1
  224. package/dist/providers/radius.models.js.map +1 -1
  225. package/dist/providers/schema-builders.d.ts +10 -0
  226. package/dist/providers/schema-builders.d.ts.map +1 -0
  227. package/dist/providers/schema-builders.js +18 -0
  228. package/dist/providers/schema-builders.js.map +1 -0
  229. package/dist/providers/together.models.js +1 -1
  230. package/dist/providers/together.models.js.map +1 -1
  231. package/dist/providers/typesafe.models.js +1 -1
  232. package/dist/providers/typesafe.models.js.map +1 -1
  233. package/dist/providers/vercel-ai-gateway.models.js +1 -1
  234. package/dist/providers/vercel-ai-gateway.models.js.map +1 -1
  235. package/dist/providers/xai.models.js +1 -1
  236. package/dist/providers/xai.models.js.map +1 -1
  237. package/dist/providers/xiaomi-token-plan-ams.models.js +1 -1
  238. package/dist/providers/xiaomi-token-plan-ams.models.js.map +1 -1
  239. package/dist/providers/xiaomi-token-plan-cn.models.js +1 -1
  240. package/dist/providers/xiaomi-token-plan-cn.models.js.map +1 -1
  241. package/dist/providers/xiaomi-token-plan-sgp.models.js +1 -1
  242. package/dist/providers/xiaomi-token-plan-sgp.models.js.map +1 -1
  243. package/dist/providers/xiaomi.models.js +1 -1
  244. package/dist/providers/xiaomi.models.js.map +1 -1
  245. package/dist/providers/zai-coding-cn.models.js +1 -1
  246. package/dist/providers/zai-coding-cn.models.js.map +1 -1
  247. package/dist/providers/zai.models.js +1 -1
  248. package/dist/providers/zai.models.js.map +1 -1
  249. package/dist/telemetry.d.ts +288 -0
  250. package/dist/telemetry.d.ts.map +1 -0
  251. package/dist/telemetry.js +192 -0
  252. package/dist/telemetry.js.map +1 -0
  253. package/dist/types.d.ts +25 -7
  254. package/dist/types.d.ts.map +1 -1
  255. package/dist/types.js.map +1 -1
  256. package/dist/utils/error-body.d.ts.map +1 -1
  257. package/dist/utils/error-body.js +2 -1
  258. package/dist/utils/error-body.js.map +1 -1
  259. package/dist/utils/identity.d.ts +65 -0
  260. package/dist/utils/identity.d.ts.map +1 -0
  261. package/dist/utils/identity.js +141 -0
  262. package/dist/utils/identity.js.map +1 -0
  263. package/dist/utils/openrouter-cost.d.ts +24 -0
  264. package/dist/utils/openrouter-cost.d.ts.map +1 -0
  265. package/dist/utils/openrouter-cost.js +34 -0
  266. package/dist/utils/openrouter-cost.js.map +1 -0
  267. package/dist/utils/overflow.d.ts +1 -0
  268. package/dist/utils/overflow.d.ts.map +1 -1
  269. package/dist/utils/overflow.js +8 -1
  270. package/dist/utils/overflow.js.map +1 -1
  271. package/dist/utils/retry.d.ts.map +1 -1
  272. package/dist/utils/retry.js +19 -7
  273. package/dist/utils/retry.js.map +1 -1
  274. package/dist/utils/streaming-json.d.ts +84 -0
  275. package/dist/utils/streaming-json.d.ts.map +1 -0
  276. package/dist/utils/streaming-json.js +513 -0
  277. package/dist/utils/streaming-json.js.map +1 -0
  278. package/dist/utils/{typebox-helpers.d.ts → string-enum.d.ts} +5 -5
  279. package/dist/utils/string-enum.d.ts.map +1 -0
  280. package/dist/utils/{typebox-helpers.js → string-enum.js} +5 -6
  281. package/dist/utils/string-enum.js.map +1 -0
  282. package/dist/utils/text.d.ts +7 -0
  283. package/dist/utils/text.d.ts.map +1 -1
  284. package/dist/utils/text.js +9 -0
  285. package/dist/utils/text.js.map +1 -1
  286. package/dist/utils/transcript.d.ts +23 -9
  287. package/dist/utils/transcript.d.ts.map +1 -1
  288. package/dist/utils/transcript.js +30 -19
  289. package/dist/utils/transcript.js.map +1 -1
  290. package/dist/utils/validation.d.ts +5 -3
  291. package/dist/utils/validation.d.ts.map +1 -1
  292. package/dist/utils/validation.js +27 -277
  293. package/dist/utils/validation.js.map +1 -1
  294. package/dist/utils/version.d.ts +2 -0
  295. package/dist/utils/version.d.ts.map +1 -0
  296. package/dist/utils/version.js +3 -0
  297. package/dist/utils/version.js.map +1 -0
  298. package/package.json +11 -10
  299. package/dist/utils/pi-user-agent.d.ts +0 -2
  300. package/dist/utils/pi-user-agent.d.ts.map +0 -1
  301. package/dist/utils/pi-user-agent.js +0 -12
  302. package/dist/utils/pi-user-agent.js.map +0 -1
  303. package/dist/utils/typebox-helpers.d.ts.map +0 -1
  304. package/dist/utils/typebox-helpers.js.map +0 -1
@@ -1,6 +1,7 @@
1
1
  import type { Tool as OpenAITool, ResponseCreateParamsStreaming, ResponseInput, ResponseStreamEvent } from "openai/resources/responses/responses.js";
2
2
  import type { Api, AssistantMessage, Model, StreamOptions, Tool, TranscriptContext, Usage } from "../types.ts";
3
3
  import type { AssistantMessageEventStream } from "../utils/event-stream.ts";
4
+ import { type TranscriptToolSupport } from "../utils/transcript.ts";
4
5
  export interface OpenAIResponsesStreamOptions {
5
6
  onProviderStreamEvent?: StreamOptions["onProviderStreamEvent"];
6
7
  serviceTier?: ResponseCreateParamsStreaming["service_tier"];
@@ -33,6 +34,21 @@ export interface ConvertResponsesToolsOptions {
33
34
  supportsOpenAIGrammarTools?: boolean;
34
35
  toolSearchResult?: boolean;
35
36
  }
37
+ /**
38
+ * How a Responses transport expresses tool changes.
39
+ *
40
+ * `additional_tools` items accumulate: a later item adds tools and replaces same-name
41
+ * definitions from earlier items, but it cannot replace a top-level tool and cannot remove any
42
+ * tool (verified with strict schemas on the OpenAI, Codex, and Copilot backends, October 2026).
43
+ * Like Codex, every tool is therefore declared in `additional_tools` items, starting with one
44
+ * at the head of the input, and removals are announced as text. Synthetic tool search can
45
+ * only add tools. Without mid-conversation system messages there is nothing to anchor.
46
+ */
47
+ export declare function getResponsesToolSupport(options: {
48
+ supportsMidConvoSystemMessages?: boolean;
49
+ supportsAdditionalTools?: boolean;
50
+ supportsToolSearch?: boolean;
51
+ }): TranscriptToolSupport;
36
52
  export declare function convertResponsesMessages<TApi extends Api>(model: Model<TApi>, context: TranscriptContext, allowedToolCallProviders: ReadonlySet<string>, options?: ConvertResponsesMessagesOptions): ResponseInput;
37
53
  export declare function convertResponsesTools(tools: readonly Tool[], options?: ConvertResponsesToolsOptions): OpenAITool[];
38
54
  export declare function processResponsesStream<TApi extends Api>(openaiStream: AsyncIterable<ResponseStreamEvent>, output: AssistantMessage, stream: AssistantMessageEventStream, model: Model<TApi>, options?: OpenAIResponsesStreamOptions): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"openai-responses-shared.d.ts","sourceRoot":"","sources":["../../src/api/openai-responses-shared.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,IAAI,IAAI,UAAU,EAElB,6BAA6B,EAC7B,aAAa,EAQb,mBAAmB,EAEnB,MAAM,yCAAyC,CAAC;AAEjD,OAAO,KAAK,EACX,GAAG,EACH,gBAAgB,EAEhB,KAAK,EAEL,aAAa,EAKb,IAAI,EAEJ,iBAAiB,EACjB,KAAK,EACL,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AA6E5E,MAAM,WAAW,4BAA4B;IAC5C,qBAAqB,CAAC,EAAE,aAAa,CAAC,uBAAuB,CAAC,CAAC;IAC/D,WAAW,CAAC,EAAE,6BAA6B,CAAC,cAAc,CAAC,CAAC;IAC5D,0BAA0B,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzD,kBAAkB,CAAC,EAAE,CACpB,mBAAmB,EAAE,6BAA6B,CAAC,cAAc,CAAC,GAAG,SAAS,EAC9E,kBAAkB,EAAE,6BAA6B,CAAC,cAAc,CAAC,GAAG,SAAS,KACzE,6BAA6B,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAC/D,uBAAuB,CAAC,EAAE,CACzB,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,6BAA6B,CAAC,cAAc,CAAC,GAAG,SAAS,KAClE,IAAI,CAAC;CACV;AAED,MAAM,WAAW,+BAA+B;IAC/C,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,0BAA0B,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzD,0GAA0G;IAC1G,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,WAAW,CAAC,EAAE,4BAA4B,CAAC;IAC3C;;;;;;;;OAQG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,4BAA4B;IAC5C,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC3B;AAMD,wBAAgB,wBAAwB,CAAC,IAAI,SAAS,GAAG,EACxD,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,iBAAiB,EAC1B,wBAAwB,EAAE,WAAW,CAAC,MAAM,CAAC,EAC7C,OAAO,CAAC,EAAE,+BAA+B,GACvC,aAAa,CA0Nf;AAMD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,EAAE,OAAO,CAAC,EAAE,4BAA4B,GAAG,UAAU,EAAE,CAqClH;AAoCD,wBAAsB,sBAAsB,CAAC,IAAI,SAAS,GAAG,EAC5D,YAAY,EAAE,aAAa,CAAC,mBAAmB,CAAC,EAChD,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,2BAA2B,EACnC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,CAAC,EAAE,4BAA4B,GACpC,OAAO,CAAC,IAAI,CAAC,CAkVf"}
1
+ {"version":3,"file":"openai-responses-shared.d.ts","sourceRoot":"","sources":["../../src/api/openai-responses-shared.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,IAAI,IAAI,UAAU,EAElB,6BAA6B,EAC7B,aAAa,EAQb,mBAAmB,EAEnB,MAAM,yCAAyC,CAAC;AAEjD,OAAO,KAAK,EACX,GAAG,EACH,gBAAgB,EAEhB,KAAK,EAEL,aAAa,EAKb,IAAI,EAEJ,iBAAiB,EACjB,KAAK,EACL,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAK5E,OAAO,EAA6C,KAAK,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAyE/G,MAAM,WAAW,4BAA4B;IAC5C,qBAAqB,CAAC,EAAE,aAAa,CAAC,uBAAuB,CAAC,CAAC;IAC/D,WAAW,CAAC,EAAE,6BAA6B,CAAC,cAAc,CAAC,CAAC;IAC5D,0BAA0B,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzD,kBAAkB,CAAC,EAAE,CACpB,mBAAmB,EAAE,6BAA6B,CAAC,cAAc,CAAC,GAAG,SAAS,EAC9E,kBAAkB,EAAE,6BAA6B,CAAC,cAAc,CAAC,GAAG,SAAS,KACzE,6BAA6B,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAC/D,uBAAuB,CAAC,EAAE,CACzB,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,6BAA6B,CAAC,cAAc,CAAC,GAAG,SAAS,KAClE,IAAI,CAAC;CACV;AAED,MAAM,WAAW,+BAA+B;IAC/C,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,0BAA0B,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzD,0GAA0G;IAC1G,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,WAAW,CAAC,EAAE,4BAA4B,CAAC;IAC3C;;;;;;;;OAQG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,4BAA4B;IAC5C,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC3B;AAMD;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAChD,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC7B,GAAG,qBAAqB,CAGxB;AAkBD,wBAAgB,wBAAwB,CAAC,IAAI,SAAS,GAAG,EACxD,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,iBAAiB,EAC1B,wBAAwB,EAAE,WAAW,CAAC,MAAM,CAAC,EAC7C,OAAO,CAAC,EAAE,+BAA+B,GACvC,aAAa,CA4Of;AAMD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,EAAE,OAAO,CAAC,EAAE,4BAA4B,GAAG,UAAU,EAAE,CAqClH;AA2BD,wBAAsB,sBAAsB,CAAC,IAAI,SAAS,GAAG,EAC5D,YAAY,EAAE,aAAa,CAAC,mBAAmB,CAAC,EAChD,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,2BAA2B,EACnC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,CAAC,EAAE,4BAA4B,GACpC,OAAO,CAAC,IAAI,CAAC,CA+Tf"}
@@ -1,10 +1,10 @@
1
1
  import { calculateCost } from "../models.js";
2
2
  import { shortHash } from "../utils/hash.js";
3
- import { parseStreamingJson, parseToolCallArguments } from "../utils/json-parse.js";
4
3
  import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
4
+ import { ToolCallArgumentsStream } from "../utils/streaming-json.js";
5
5
  import { getSystemMessageText, renderSystemMessageUpdate } from "../utils/text.js";
6
6
  import { resolveTranscript, resolveTranscriptTools } from "../utils/transcript.js";
7
- import { appendGrammarToolInputJsonDelta, getGrammarToolInput, getJsonSchemaToolParameters, resolveGrammarConstrainedSampling, resolveJsonSchemaStrictSampling, } from "./constrained-sampling.js";
7
+ import { appendGrammarToolInputJsonDelta, closeGrammarToolInputJson, getGrammarToolInput, getJsonSchemaToolParameters, resolveGrammarConstrainedSampling, resolveJsonSchemaStrictSampling, } from "./constrained-sampling.js";
8
8
  import { transformMessages } from "./transform-messages.js";
9
9
  // =============================================================================
10
10
  // Utilities
@@ -40,7 +40,7 @@ function convertToolResultOutput(model, content) {
40
40
  .map((c) => c.text)
41
41
  .join("\n");
42
42
  const images = content.filter((c) => c.type === "image");
43
- const hasText = textResult.length > 0;
43
+ const hasText = textResult.trim().length > 0;
44
44
  if (images.length === 0 || !model.input.includes("image")) {
45
45
  return sanitizeSurrogates(hasText ? textResult : images.length > 0 ? "(see attached image)" : "(no tool output)");
46
46
  }
@@ -60,6 +60,34 @@ function convertToolResultOutput(model, content) {
60
60
  // =============================================================================
61
61
  // Message conversion
62
62
  // =============================================================================
63
+ /**
64
+ * How a Responses transport expresses tool changes.
65
+ *
66
+ * `additional_tools` items accumulate: a later item adds tools and replaces same-name
67
+ * definitions from earlier items, but it cannot replace a top-level tool and cannot remove any
68
+ * tool (verified with strict schemas on the OpenAI, Codex, and Copilot backends, October 2026).
69
+ * Like Codex, every tool is therefore declared in `additional_tools` items, starting with one
70
+ * at the head of the input, and removals are announced as text. Synthetic tool search can
71
+ * only add tools. Without mid-conversation system messages there is nothing to anchor.
72
+ */
73
+ export function getResponsesToolSupport(options) {
74
+ if (options.supportsMidConvoSystemMessages && options.supportsAdditionalTools)
75
+ return "changes";
76
+ return options.supportsToolSearch ? "additions" : "none";
77
+ }
78
+ /**
79
+ * Precedes every additional_tools item after the first. Without it, models read the latest item as
80
+ * the complete tool set once a removal was announced; Codex precedes its incremental tool batches
81
+ * with the same guidance. Restating the tools that are still unavailable keeps smaller models
82
+ * (gpt-5.6-luna, gpt-6-luna) from calling them again after later loads (verified October 2026).
83
+ */
84
+ function renderIncrementalToolsNotice(unavailable) {
85
+ const notice = "This is an incremental tools update. Previously declared tools remain available unless explicitly marked unavailable. A tool declared again here is available again, and its latest definition replaces the earlier one.";
86
+ return unavailable.size > 0 ? `${notice}\nStill unavailable: ${[...unavailable].join(", ")}.` : notice;
87
+ }
88
+ function renderToolRemovalNotice(names) {
89
+ return `The following tools are no longer available. Do not call them:\n${names.map((name) => `- ${name}`).join("\n")}`;
90
+ }
63
91
  export function convertResponsesMessages(model, context, allowedToolCallProviders, options) {
64
92
  const normalizedContext = resolveTranscript(context, options?.supportsMidConvoSystemMessages);
65
93
  const messages = [];
@@ -88,20 +116,30 @@ export function convertResponsesMessages(model, context, allowedToolCallProvider
88
116
  return `${normalizedCallId}|${normalizedItemId}`;
89
117
  };
90
118
  const transformedMessages = transformMessages(normalizedContext.messages, model, normalizeToolCallId);
91
- const transcriptTools = resolveTranscriptTools(normalizedContext.messages, (options?.supportsAdditionalTools ?? false) || (options?.supportsToolSearch ?? false));
119
+ const toolSupport = getResponsesToolSupport(options ?? {});
120
+ const transcriptTools = resolveTranscriptTools(normalizedContext.messages, toolSupport);
121
+ let declaredAdditionalTools = false;
122
+ /** Tools announced as removed and not declared again since. */
123
+ const unavailableTools = new Set();
92
124
  const appendSystemToolAdditions = (message, seed) => {
93
- const tools = transcriptTools.anchorsAdditions ? (message.toolsAdded ?? []) : [];
125
+ const tools = message.toolsAdded ?? [];
126
+ for (const tool of tools)
127
+ unavailableTools.delete(tool.name);
94
128
  if (tools.length === 0)
95
129
  return;
96
- if (options?.supportsAdditionalTools) {
130
+ if (toolSupport === "changes") {
131
+ if (declaredAdditionalTools) {
132
+ messages.push({ role: instructionRole, content: renderIncrementalToolsNotice(unavailableTools) });
133
+ }
134
+ declaredAdditionalTools = true;
97
135
  messages.push({
98
136
  type: "additional_tools",
99
137
  role: "developer",
100
- tools: convertResponsesTools(tools, options.toolOptions),
138
+ tools: convertResponsesTools(tools, options?.toolOptions),
101
139
  });
102
140
  return;
103
141
  }
104
- if (!options?.supportsToolSearch)
142
+ if (toolSupport !== "additions")
105
143
  return;
106
144
  const names = tools.map((tool) => tool.name);
107
145
  const callId = `pi_tool_load_${shortHash(`${seed}:${names.join(",")}`)}`;
@@ -117,7 +155,7 @@ export function convertResponsesMessages(model, context, allowedToolCallProvider
117
155
  call_id: callId,
118
156
  execution: "client",
119
157
  status: "completed",
120
- tools: convertResponsesTools(tools, { ...options.toolOptions, toolSearchResult: true }),
158
+ tools: convertResponsesTools(tools, { ...options?.toolOptions, toolSearchResult: true }),
121
159
  });
122
160
  };
123
161
  const includeInitialSystemMessage = options?.includeSystemPrompt ?? true;
@@ -131,13 +169,27 @@ export function convertResponsesMessages(model, context, allowedToolCallProvider
131
169
  const instructionRole = model.reasoning && compat?.supportsDeveloperRole !== false ? "developer" : "system";
132
170
  let msgIndex = 0;
133
171
  let sourceIndex = 0;
172
+ let systemIndex = 0;
134
173
  for (const msg of transformedMessages) {
135
174
  const isLeadingSystemMessage = sourceIndex++ === 0 && msg.role === "system";
136
175
  if (msg.role === "system") {
137
- if (!isLeadingSystemMessage)
176
+ // transformMessages keeps system messages in order, so their position matches the transcript.
177
+ const anchorsToolChanges = systemIndex++ >= transcriptTools.foldedSystemMessages;
178
+ if (anchorsToolChanges)
138
179
  appendSystemToolAdditions(msg, `system:${msgIndex}`);
139
180
  if (!isLeadingSystemMessage || includeInitialSystemMessage) {
140
- const text = isLeadingSystemMessage ? getSystemMessageText(msg) : renderSystemMessageUpdate(msg);
181
+ const parts = [isLeadingSystemMessage ? getSystemMessageText(msg) : renderSystemMessageUpdate(msg)];
182
+ if (anchorsToolChanges) {
183
+ // A redefinition is a removal plus an addition of the same name; only true removals are announced.
184
+ const added = new Set((msg.toolsAdded ?? []).map((tool) => tool.name));
185
+ const removed = (msg.toolsRemoved ?? []).map((tool) => tool.name).filter((name) => !added.has(name));
186
+ if (removed.length > 0)
187
+ parts.push(renderToolRemovalNotice(removed));
188
+ // Recorded after this message's additions, whose notice precedes this removal notice.
189
+ for (const name of removed)
190
+ unavailableTools.add(name);
191
+ }
192
+ const text = parts.filter((part) => part.length > 0).join("\n\n");
141
193
  if (text.length > 0) {
142
194
  messages.push({ role: instructionRole, content: sanitizeSurrogates(text) });
143
195
  }
@@ -316,24 +368,11 @@ export function convertResponsesTools(tools, options) {
316
368
  return functionTool;
317
369
  });
318
370
  }
319
- function getCustomToolCallInput(block) {
320
- const property = block.customInput?.property;
321
- if (property === undefined)
322
- return "";
323
- const value = block.arguments[property];
324
- return typeof value === "string" ? value : "";
325
- }
326
- function appendCustomToolCallInput(block, nextInput, close) {
327
- const customInput = block.customInput;
328
- if (!customInput)
329
- return undefined;
330
- const delta = appendGrammarToolInputJsonDelta(customInput.jsonBuffer, customInput.property, nextInput, close);
331
- block.arguments = { [customInput.property]: nextInput };
332
- return delta;
333
- }
334
371
  export async function processResponsesStream(openaiStream, output, stream, model, options) {
335
372
  let sawTerminalResponseEvent = false;
336
373
  const outputSlots = new Map();
374
+ // Tool calls whose output_item.done has not arrived yet.
375
+ const unfinishedToolCalls = new Set();
337
376
  const reasoningBlocksById = new Map();
338
377
  const applyMessagePhaseStopReason = (item) => {
339
378
  if (item.type === "message" && item.phase === "final_answer") {
@@ -377,19 +416,21 @@ export async function processResponsesStream(openaiStream, output, stream, model
377
416
  return slot;
378
417
  }
379
418
  if (item.type === "function_call") {
419
+ const args = new ToolCallArgumentsStream();
380
420
  const block = {
381
421
  type: "toolCall",
382
422
  id: `${item.call_id}|${item.id}`,
383
423
  name: item.name,
384
- arguments: {},
424
+ arguments: item.arguments ? args.append(item.arguments) : {},
385
425
  ...(item.namespace !== undefined ? { namespace: item.namespace } : {}),
386
- partialJson: item.arguments || "",
387
426
  };
388
427
  output.content.push(block);
428
+ unfinishedToolCalls.add(block);
389
429
  const slot = {
390
430
  type: "toolCall",
391
431
  block,
392
432
  contentIndex: output.content.length - 1,
433
+ input: { kind: "json", arguments: args },
393
434
  };
394
435
  outputSlots.set(outputIndex, slot);
395
436
  stream.push({ type: "toolcall_start", contentIndex: slot.contentIndex, partial: output });
@@ -404,16 +445,14 @@ export async function processResponsesStream(openaiStream, output, stream, model
404
445
  name: item.name,
405
446
  arguments: { [inputProperty]: input },
406
447
  ...(item.namespace !== undefined ? { namespace: item.namespace } : {}),
407
- customInput: {
408
- property: inputProperty,
409
- jsonBuffer: { input: "", started: false, closed: false },
410
- },
411
448
  };
412
449
  output.content.push(block);
450
+ unfinishedToolCalls.add(block);
413
451
  const slot = {
414
452
  type: "toolCall",
415
453
  block,
416
454
  contentIndex: output.content.length - 1,
455
+ input: customInput(inputProperty, input),
417
456
  };
418
457
  outputSlots.set(outputIndex, slot);
419
458
  stream.push({ type: "toolcall_start", contentIndex: slot.contentIndex, partial: output });
@@ -558,36 +597,31 @@ export async function processResponsesStream(openaiStream, output, stream, model
558
597
  }
559
598
  else if (event.type === "response.function_call_arguments.delta") {
560
599
  const slot = getSlot(event.output_index, "toolCall");
561
- if (!slot || slot.block.partialJson === undefined)
600
+ if (slot?.input.kind !== "json")
562
601
  continue;
563
- slot.block.partialJson += event.delta;
564
- slot.block.arguments = parseStreamingJson(slot.block.partialJson);
602
+ slot.block.arguments = slot.input.arguments.append(event.delta);
565
603
  pushToolCallDelta(slot, event.delta);
566
604
  }
567
605
  else if (event.type === "response.function_call_arguments.done") {
568
606
  const slot = getSlot(event.output_index, "toolCall");
569
- if (!slot || slot.block.partialJson === undefined)
607
+ if (slot?.input.kind !== "json")
570
608
  continue;
571
- const previousPartialJson = slot.block.partialJson;
572
- slot.block.partialJson = event.arguments;
573
- slot.block.arguments = parseStreamingJson(slot.block.partialJson);
574
- if (event.arguments.startsWith(previousPartialJson)) {
575
- const delta = event.arguments.slice(previousPartialJson.length);
576
- if (delta.length > 0)
577
- pushToolCallDelta(slot, delta);
578
- }
609
+ const replaced = slot.input.arguments.replace(event.arguments);
610
+ slot.block.arguments = replaced.arguments;
611
+ if (replaced.delta)
612
+ pushToolCallDelta(slot, replaced.delta);
579
613
  }
580
614
  else if (event.type === "response.custom_tool_call_input.delta") {
581
615
  const slot = getSlot(event.output_index, "toolCall");
582
- if (!slot || !slot.block.customInput)
616
+ if (slot?.input.kind !== "custom")
583
617
  continue;
584
- pushToolCallDelta(slot, appendCustomToolCallInput(slot.block, getCustomToolCallInput(slot.block) + event.delta, false));
618
+ pushToolCallDelta(slot, appendCustomInput(slot.block, slot.input, event.delta));
585
619
  }
586
620
  else if (event.type === "response.custom_tool_call_input.done") {
587
621
  const slot = getSlot(event.output_index, "toolCall");
588
- if (!slot || !slot.block.customInput)
622
+ if (slot?.input.kind !== "custom")
589
623
  continue;
590
- pushToolCallDelta(slot, appendCustomToolCallInput(slot.block, event.input, true));
624
+ pushToolCallDelta(slot, closeCustomInput(slot.block, slot.input, event.input));
591
625
  }
592
626
  else if (event.type === "response.output_item.done") {
593
627
  const item = event.item;
@@ -618,15 +652,13 @@ export async function processResponsesStream(openaiStream, output, stream, model
618
652
  });
619
653
  outputSlots.delete(event.output_index);
620
654
  }
621
- else if (item.type === "function_call" &&
622
- slot?.type === "toolCall" &&
623
- slot.block.partialJson !== undefined) {
624
- Object.assign(slot.block, parseToolCallArguments(item.arguments || slot.block.partialJson));
655
+ else if (item.type === "function_call" && slot?.type === "toolCall" && slot.input.kind === "json") {
656
+ if (item.arguments)
657
+ slot.input.arguments.replace(item.arguments);
658
+ Object.assign(slot.block, slot.input.arguments.finish());
625
659
  if (item.namespace !== undefined)
626
660
  slot.block.namespace = item.namespace;
627
- // Finalize in-place and strip the scratch buffer so replay only
628
- // carries parsed arguments.
629
- delete slot.block.partialJson;
661
+ unfinishedToolCalls.delete(slot.block);
630
662
  stream.push({
631
663
  type: "toolcall_end",
632
664
  contentIndex: slot.contentIndex,
@@ -635,11 +667,11 @@ export async function processResponsesStream(openaiStream, output, stream, model
635
667
  });
636
668
  outputSlots.delete(event.output_index);
637
669
  }
638
- else if (item.type === "custom_tool_call" && slot?.type === "toolCall" && slot.block.customInput) {
639
- pushToolCallDelta(slot, appendCustomToolCallInput(slot.block, item.input ?? getCustomToolCallInput(slot.block), true));
670
+ else if (item.type === "custom_tool_call" && slot?.type === "toolCall" && slot.input.kind === "custom") {
671
+ pushToolCallDelta(slot, closeCustomInput(slot.block, slot.input, item.input));
640
672
  if (item.namespace !== undefined)
641
673
  slot.block.namespace = item.namespace;
642
- delete slot.block.customInput;
674
+ unfinishedToolCalls.delete(slot.block);
643
675
  stream.push({
644
676
  type: "toolcall_end",
645
677
  contentIndex: slot.contentIndex,
@@ -673,18 +705,39 @@ export async function processResponsesStream(openaiStream, output, stream, model
673
705
  }
674
706
  // The agent runs every tool call in the final message. Refuse to hand over calls whose
675
707
  // output_item.done never arrived: their arguments may be cut off or mixed up, e.g. when a
676
- // non-compliant server omits output_index. Finished calls have their scratch buffers removed.
708
+ // non-compliant server omits output_index.
677
709
  if (output.stopReason === "toolUse") {
678
- for (const block of output.content) {
679
- if (block.type !== "toolCall")
680
- continue;
681
- const toolCall = block;
682
- if (toolCall.partialJson !== undefined || toolCall.customInput !== undefined) {
683
- throw new Error(`OpenAI Responses stream completed with an unfinished tool call: ${toolCall.name} (${toolCall.id})`);
684
- }
710
+ for (const toolCall of unfinishedToolCalls) {
711
+ throw new Error(`OpenAI Responses stream completed with an unfinished tool call: ${toolCall.name} (${toolCall.id})`);
685
712
  }
686
713
  }
687
714
  }
715
+ /** Stream state of a custom tool call that starts with `initialInput`. */
716
+ function customInput(property, initialInput) {
717
+ const buffer = { input: "", started: false, closed: false };
718
+ return {
719
+ kind: "custom",
720
+ property,
721
+ buffer,
722
+ unsent: appendGrammarToolInputJsonDelta(buffer, property, initialInput) ?? "",
723
+ };
724
+ }
725
+ /** Append to a streaming custom tool input; returns the matching piece of its JSON arguments text. */
726
+ function appendCustomInput(block, input, delta) {
727
+ return sendCustomInput(block, input, appendGrammarToolInputJsonDelta(input.buffer, input.property, delta));
728
+ }
729
+ /** Close a custom tool input with the provider's complete input, if it sent one. */
730
+ function closeCustomInput(block, input, finalInput) {
731
+ return sendCustomInput(block, input, closeGrammarToolInputJson(input.buffer, input.property, finalInput));
732
+ }
733
+ function sendCustomInput(block, input, jsonDelta) {
734
+ block.arguments = { [input.property]: input.buffer.input };
735
+ if (input.unsent === "")
736
+ return jsonDelta;
737
+ const sent = input.unsent + (jsonDelta ?? "");
738
+ input.unsent = "";
739
+ return sent;
740
+ }
688
741
  function mapStopReason(status, incompleteReason) {
689
742
  if (!status)
690
743
  return { stopReason: "stop" };