@copilotkit/aimock 1.45.0 → 1.46.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 (426) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +24 -0
  4. package/README.md +7 -1
  5. package/dist/agui-mock.cjs +25 -25
  6. package/dist/agui-mock.cjs.map +1 -1
  7. package/dist/agui-mock.d.cts.map +1 -1
  8. package/dist/agui-mock.d.ts.map +1 -1
  9. package/dist/agui-mock.js +25 -25
  10. package/dist/agui-mock.js.map +1 -1
  11. package/dist/agui-types.d.ts.map +1 -1
  12. package/dist/aimock-cli.cjs +15 -1
  13. package/dist/aimock-cli.cjs.map +1 -1
  14. package/dist/aimock-cli.d.cts.map +1 -1
  15. package/dist/aimock-cli.d.ts.map +1 -1
  16. package/dist/aimock-cli.js +16 -2
  17. package/dist/aimock-cli.js.map +1 -1
  18. package/dist/api-key-auth.cjs +10 -9
  19. package/dist/api-key-auth.cjs.map +1 -1
  20. package/dist/api-key-auth.d.cts.map +1 -1
  21. package/dist/api-key-auth.d.ts.map +1 -1
  22. package/dist/api-key-auth.js +11 -10
  23. package/dist/api-key-auth.js.map +1 -1
  24. package/dist/batches.cjs +2 -4
  25. package/dist/batches.cjs.map +1 -1
  26. package/dist/batches.d.cts.map +1 -1
  27. package/dist/batches.d.ts.map +1 -1
  28. package/dist/batches.js +2 -4
  29. package/dist/batches.js.map +1 -1
  30. package/dist/bedrock-converse.cjs +61 -80
  31. package/dist/bedrock-converse.cjs.map +1 -1
  32. package/dist/bedrock-converse.d.cts.map +1 -1
  33. package/dist/bedrock-converse.d.ts.map +1 -1
  34. package/dist/bedrock-converse.js +58 -77
  35. package/dist/bedrock-converse.js.map +1 -1
  36. package/dist/bedrock.cjs +65 -97
  37. package/dist/bedrock.cjs.map +1 -1
  38. package/dist/bedrock.d.cts.map +1 -1
  39. package/dist/bedrock.d.ts.map +1 -1
  40. package/dist/bedrock.js +62 -94
  41. package/dist/bedrock.js.map +1 -1
  42. package/dist/byteplus-video.cjs +11 -10
  43. package/dist/byteplus-video.cjs.map +1 -1
  44. package/dist/byteplus-video.d.cts.map +1 -1
  45. package/dist/byteplus-video.d.ts.map +1 -1
  46. package/dist/byteplus-video.js +5 -4
  47. package/dist/byteplus-video.js.map +1 -1
  48. package/dist/chaos.cjs +5 -4
  49. package/dist/chaos.cjs.map +1 -1
  50. package/dist/chaos.d.cts.map +1 -1
  51. package/dist/chaos.d.ts.map +1 -1
  52. package/dist/chaos.js +5 -4
  53. package/dist/chaos.js.map +1 -1
  54. package/dist/cli.cjs +15 -0
  55. package/dist/cli.cjs.map +1 -1
  56. package/dist/cli.js +15 -0
  57. package/dist/cli.js.map +1 -1
  58. package/dist/cohere.cjs +49 -74
  59. package/dist/cohere.cjs.map +1 -1
  60. package/dist/cohere.d.cts.map +1 -1
  61. package/dist/cohere.d.ts.map +1 -1
  62. package/dist/cohere.js +47 -72
  63. package/dist/cohere.js.map +1 -1
  64. package/dist/config-loader.cjs +29 -1
  65. package/dist/config-loader.cjs.map +1 -1
  66. package/dist/config-loader.d.cts +7 -1
  67. package/dist/config-loader.d.cts.map +1 -1
  68. package/dist/config-loader.d.ts +7 -1
  69. package/dist/config-loader.d.ts.map +1 -1
  70. package/dist/config-loader.js +29 -2
  71. package/dist/config-loader.js.map +1 -1
  72. package/dist/count-tokens.cjs +146 -0
  73. package/dist/count-tokens.cjs.map +1 -0
  74. package/dist/count-tokens.js +146 -0
  75. package/dist/count-tokens.js.map +1 -0
  76. package/dist/elevenlabs-audio.cjs +36 -34
  77. package/dist/elevenlabs-audio.cjs.map +1 -1
  78. package/dist/elevenlabs-audio.d.cts.map +1 -1
  79. package/dist/elevenlabs-audio.d.ts.map +1 -1
  80. package/dist/elevenlabs-audio.js +33 -31
  81. package/dist/elevenlabs-audio.js.map +1 -1
  82. package/dist/elevenlabs-voice.cjs +38 -37
  83. package/dist/elevenlabs-voice.cjs.map +1 -1
  84. package/dist/elevenlabs-voice.d.cts.map +1 -1
  85. package/dist/elevenlabs-voice.d.ts.map +1 -1
  86. package/dist/elevenlabs-voice.js +33 -32
  87. package/dist/elevenlabs-voice.js.map +1 -1
  88. package/dist/embedding-request.cjs +16 -0
  89. package/dist/embedding-request.cjs.map +1 -0
  90. package/dist/embedding-request.js +14 -0
  91. package/dist/embedding-request.js.map +1 -0
  92. package/dist/embeddings.cjs +30 -20
  93. package/dist/embeddings.cjs.map +1 -1
  94. package/dist/embeddings.d.cts.map +1 -1
  95. package/dist/embeddings.d.ts.map +1 -1
  96. package/dist/embeddings.js +30 -20
  97. package/dist/embeddings.js.map +1 -1
  98. package/dist/fal-audio.cjs +45 -43
  99. package/dist/fal-audio.cjs.map +1 -1
  100. package/dist/fal-audio.d.cts.map +1 -1
  101. package/dist/fal-audio.d.ts.map +1 -1
  102. package/dist/fal-audio.js +42 -40
  103. package/dist/fal-audio.js.map +1 -1
  104. package/dist/fal.cjs +17 -15
  105. package/dist/fal.cjs.map +1 -1
  106. package/dist/fal.js +16 -14
  107. package/dist/fal.js.map +1 -1
  108. package/dist/files.cjs +2 -4
  109. package/dist/files.cjs.map +1 -1
  110. package/dist/files.d.cts.map +1 -1
  111. package/dist/files.d.ts.map +1 -1
  112. package/dist/files.js +2 -4
  113. package/dist/files.js.map +1 -1
  114. package/dist/fine-tuning.cjs +2 -4
  115. package/dist/fine-tuning.cjs.map +1 -1
  116. package/dist/fine-tuning.d.cts.map +1 -1
  117. package/dist/fine-tuning.d.ts.map +1 -1
  118. package/dist/fine-tuning.js +2 -4
  119. package/dist/fine-tuning.js.map +1 -1
  120. package/dist/fixture-loader.cjs +37 -42
  121. package/dist/fixture-loader.cjs.map +1 -1
  122. package/dist/fixture-loader.d.cts.map +1 -1
  123. package/dist/fixture-loader.d.ts.map +1 -1
  124. package/dist/fixture-loader.js +37 -42
  125. package/dist/fixture-loader.js.map +1 -1
  126. package/dist/gemini-embeddings.cjs +26 -24
  127. package/dist/gemini-embeddings.cjs.map +1 -1
  128. package/dist/gemini-embeddings.js +26 -24
  129. package/dist/gemini-embeddings.js.map +1 -1
  130. package/dist/gemini-interactions.cjs +50 -35
  131. package/dist/gemini-interactions.cjs.map +1 -1
  132. package/dist/gemini-interactions.d.cts +0 -1
  133. package/dist/gemini-interactions.d.cts.map +1 -1
  134. package/dist/gemini-interactions.d.ts +0 -1
  135. package/dist/gemini-interactions.d.ts.map +1 -1
  136. package/dist/gemini-interactions.js +49 -34
  137. package/dist/gemini-interactions.js.map +1 -1
  138. package/dist/gemini.cjs +57 -67
  139. package/dist/gemini.cjs.map +1 -1
  140. package/dist/gemini.d.cts.map +1 -1
  141. package/dist/gemini.d.ts.map +1 -1
  142. package/dist/gemini.js +56 -67
  143. package/dist/gemini.js.map +1 -1
  144. package/dist/grok-video.cjs +14 -12
  145. package/dist/grok-video.cjs.map +1 -1
  146. package/dist/grok-video.d.cts.map +1 -1
  147. package/dist/grok-video.d.ts.map +1 -1
  148. package/dist/grok-video.js +8 -6
  149. package/dist/grok-video.js.map +1 -1
  150. package/dist/helpers.cjs +11 -68
  151. package/dist/helpers.cjs.map +1 -1
  152. package/dist/helpers.d.cts.map +1 -1
  153. package/dist/helpers.d.ts.map +1 -1
  154. package/dist/helpers.js +12 -67
  155. package/dist/helpers.js.map +1 -1
  156. package/dist/images.cjs +30 -28
  157. package/dist/images.cjs.map +1 -1
  158. package/dist/images.d.cts.map +1 -1
  159. package/dist/images.d.ts.map +1 -1
  160. package/dist/images.js +27 -25
  161. package/dist/images.js.map +1 -1
  162. package/dist/index.d.cts +2 -2
  163. package/dist/index.d.ts +2 -2
  164. package/dist/journal.cjs +3 -1
  165. package/dist/journal.cjs.map +1 -1
  166. package/dist/journal.d.cts.map +1 -1
  167. package/dist/journal.d.ts.map +1 -1
  168. package/dist/journal.js +2 -1
  169. package/dist/journal.js.map +1 -1
  170. package/dist/llmock.cjs +3 -0
  171. package/dist/llmock.cjs.map +1 -1
  172. package/dist/llmock.d.cts.map +1 -1
  173. package/dist/llmock.d.ts.map +1 -1
  174. package/dist/llmock.js +3 -0
  175. package/dist/llmock.js.map +1 -1
  176. package/dist/mcp-fakes.d.cts.map +1 -1
  177. package/dist/mcp-handler.cjs +14 -4
  178. package/dist/mcp-handler.cjs.map +1 -1
  179. package/dist/mcp-handler.js +14 -4
  180. package/dist/mcp-handler.js.map +1 -1
  181. package/dist/mcp-recorder.cjs +2 -1
  182. package/dist/mcp-recorder.cjs.map +1 -1
  183. package/dist/mcp-recorder.js +3 -2
  184. package/dist/mcp-recorder.js.map +1 -1
  185. package/dist/messages.cjs +111 -96
  186. package/dist/messages.cjs.map +1 -1
  187. package/dist/messages.d.cts.map +1 -1
  188. package/dist/messages.d.ts.map +1 -1
  189. package/dist/messages.js +109 -95
  190. package/dist/messages.js.map +1 -1
  191. package/dist/metrics.cjs +5 -2
  192. package/dist/metrics.cjs.map +1 -1
  193. package/dist/metrics.d.cts.map +1 -1
  194. package/dist/metrics.d.ts.map +1 -1
  195. package/dist/metrics.js +6 -3
  196. package/dist/metrics.js.map +1 -1
  197. package/dist/model-utils.cjs +1 -0
  198. package/dist/model-utils.cjs.map +1 -1
  199. package/dist/model-utils.js +1 -1
  200. package/dist/model-utils.js.map +1 -1
  201. package/dist/moderation.cjs +15 -12
  202. package/dist/moderation.cjs.map +1 -1
  203. package/dist/moderation.js +14 -11
  204. package/dist/moderation.js.map +1 -1
  205. package/dist/ollama.cjs +128 -68
  206. package/dist/ollama.cjs.map +1 -1
  207. package/dist/ollama.d.cts.map +1 -1
  208. package/dist/ollama.d.ts.map +1 -1
  209. package/dist/ollama.js +124 -64
  210. package/dist/ollama.js.map +1 -1
  211. package/dist/openapi.cjs +323 -3
  212. package/dist/openapi.cjs.map +1 -1
  213. package/dist/openapi.d.cts.map +1 -1
  214. package/dist/openapi.d.ts.map +1 -1
  215. package/dist/openapi.js +324 -4
  216. package/dist/openapi.js.map +1 -1
  217. package/dist/openrouter-chat.cjs +11 -155
  218. package/dist/openrouter-chat.cjs.map +1 -1
  219. package/dist/openrouter-chat.js +11 -155
  220. package/dist/openrouter-chat.js.map +1 -1
  221. package/dist/openrouter-video.cjs +76 -71
  222. package/dist/openrouter-video.cjs.map +1 -1
  223. package/dist/openrouter-video.d.cts.map +1 -1
  224. package/dist/openrouter-video.d.ts.map +1 -1
  225. package/dist/openrouter-video.js +63 -58
  226. package/dist/openrouter-video.js.map +1 -1
  227. package/dist/recorder.cjs +176 -95
  228. package/dist/recorder.cjs.map +1 -1
  229. package/dist/recorder.d.cts.map +1 -1
  230. package/dist/recorder.d.ts.map +1 -1
  231. package/dist/recorder.js +176 -95
  232. package/dist/recorder.js.map +1 -1
  233. package/dist/rerank.cjs +13 -11
  234. package/dist/rerank.cjs.map +1 -1
  235. package/dist/rerank.js +12 -10
  236. package/dist/rerank.js.map +1 -1
  237. package/dist/response/catalog/anthropic-page.cjs +39 -0
  238. package/dist/response/catalog/anthropic-page.cjs.map +1 -0
  239. package/dist/response/catalog/anthropic-page.js +38 -0
  240. package/dist/response/catalog/anthropic-page.js.map +1 -0
  241. package/dist/response/catalog/collect.cjs +61 -0
  242. package/dist/response/catalog/collect.cjs.map +1 -0
  243. package/dist/response/catalog/collect.js +59 -0
  244. package/dist/response/catalog/collect.js.map +1 -0
  245. package/dist/response/catalog/gemini-page.cjs +25 -0
  246. package/dist/response/catalog/gemini-page.cjs.map +1 -0
  247. package/dist/response/catalog/gemini-page.js +24 -0
  248. package/dist/response/catalog/gemini-page.js.map +1 -0
  249. package/dist/response/catalog/render.cjs +182 -0
  250. package/dist/response/catalog/render.cjs.map +1 -0
  251. package/dist/response/catalog/render.js +171 -0
  252. package/dist/response/catalog/render.js.map +1 -0
  253. package/dist/response/errors.cjs +225 -0
  254. package/dist/response/errors.cjs.map +1 -0
  255. package/dist/response/errors.js +224 -0
  256. package/dist/response/errors.js.map +1 -0
  257. package/dist/response/finish.cjs +39 -0
  258. package/dist/response/finish.cjs.map +1 -0
  259. package/dist/response/finish.js +35 -0
  260. package/dist/response/finish.js.map +1 -0
  261. package/dist/response/policy.cjs +126 -0
  262. package/dist/response/policy.cjs.map +1 -0
  263. package/dist/response/policy.js +120 -0
  264. package/dist/response/policy.js.map +1 -0
  265. package/dist/response/profiles.cjs +69 -0
  266. package/dist/response/profiles.cjs.map +1 -0
  267. package/dist/response/profiles.js +65 -0
  268. package/dist/response/profiles.js.map +1 -0
  269. package/dist/response/usage/codecs/anthropic.cjs +52 -0
  270. package/dist/response/usage/codecs/anthropic.cjs.map +1 -0
  271. package/dist/response/usage/codecs/anthropic.js +50 -0
  272. package/dist/response/usage/codecs/anthropic.js.map +1 -0
  273. package/dist/response/usage/codecs/cohere.cjs +36 -0
  274. package/dist/response/usage/codecs/cohere.cjs.map +1 -0
  275. package/dist/response/usage/codecs/cohere.js +35 -0
  276. package/dist/response/usage/codecs/cohere.js.map +1 -0
  277. package/dist/response/usage/codecs/converse.cjs +16 -0
  278. package/dist/response/usage/codecs/converse.cjs.map +1 -0
  279. package/dist/response/usage/codecs/converse.js +15 -0
  280. package/dist/response/usage/codecs/converse.js.map +1 -0
  281. package/dist/response/usage/codecs/gemini.cjs +31 -0
  282. package/dist/response/usage/codecs/gemini.cjs.map +1 -0
  283. package/dist/response/usage/codecs/gemini.js +31 -0
  284. package/dist/response/usage/codecs/gemini.js.map +1 -0
  285. package/dist/response/usage/codecs/interactions.cjs +22 -0
  286. package/dist/response/usage/codecs/interactions.cjs.map +1 -0
  287. package/dist/response/usage/codecs/interactions.js +21 -0
  288. package/dist/response/usage/codecs/interactions.js.map +1 -0
  289. package/dist/response/usage/codecs/ollama.cjs +17 -0
  290. package/dist/response/usage/codecs/ollama.cjs.map +1 -0
  291. package/dist/response/usage/codecs/ollama.js +17 -0
  292. package/dist/response/usage/codecs/ollama.js.map +1 -0
  293. package/dist/response/usage/codecs/openai.cjs +52 -0
  294. package/dist/response/usage/codecs/openai.cjs.map +1 -0
  295. package/dist/response/usage/codecs/openai.js +50 -0
  296. package/dist/response/usage/codecs/openai.js.map +1 -0
  297. package/dist/response/usage/codecs/openrouter.cjs +68 -0
  298. package/dist/response/usage/codecs/openrouter.cjs.map +1 -0
  299. package/dist/response/usage/codecs/openrouter.js +67 -0
  300. package/dist/response/usage/codecs/openrouter.js.map +1 -0
  301. package/dist/response/usage/codecs/realtime.cjs +19 -0
  302. package/dist/response/usage/codecs/realtime.cjs.map +1 -0
  303. package/dist/response/usage/codecs/realtime.js +18 -0
  304. package/dist/response/usage/codecs/realtime.js.map +1 -0
  305. package/dist/response/usage/codecs/responses.cjs +21 -0
  306. package/dist/response/usage/codecs/responses.cjs.map +1 -0
  307. package/dist/response/usage/codecs/responses.js +20 -0
  308. package/dist/response/usage/codecs/responses.js.map +1 -0
  309. package/dist/response/usage/estimate.cjs +23 -0
  310. package/dist/response/usage/estimate.cjs.map +1 -0
  311. package/dist/response/usage/estimate.js +21 -0
  312. package/dist/response/usage/estimate.js.map +1 -0
  313. package/dist/response/usage/fields.cjs +72 -0
  314. package/dist/response/usage/fields.cjs.map +1 -0
  315. package/dist/response/usage/fields.js +70 -0
  316. package/dist/response/usage/fields.js.map +1 -0
  317. package/dist/response/usage/recording.cjs +52 -0
  318. package/dist/response/usage/recording.cjs.map +1 -0
  319. package/dist/response/usage/recording.js +52 -0
  320. package/dist/response/usage/recording.js.map +1 -0
  321. package/dist/responses.cjs +45 -58
  322. package/dist/responses.cjs.map +1 -1
  323. package/dist/responses.d.cts.map +1 -1
  324. package/dist/responses.d.ts.map +1 -1
  325. package/dist/responses.js +44 -57
  326. package/dist/responses.js.map +1 -1
  327. package/dist/route-registry.cjs +45 -0
  328. package/dist/route-registry.cjs.map +1 -1
  329. package/dist/route-registry.d.cts.map +1 -1
  330. package/dist/route-registry.d.ts.map +1 -1
  331. package/dist/route-registry.js +41 -1
  332. package/dist/route-registry.js.map +1 -1
  333. package/dist/router.cjs +4 -0
  334. package/dist/router.cjs.map +1 -1
  335. package/dist/router.d.cts.map +1 -1
  336. package/dist/router.d.ts.map +1 -1
  337. package/dist/router.js +3 -0
  338. package/dist/router.js.map +1 -1
  339. package/dist/search.cjs +13 -11
  340. package/dist/search.cjs.map +1 -1
  341. package/dist/search.js +12 -10
  342. package/dist/search.js.map +1 -1
  343. package/dist/server.cjs +222 -146
  344. package/dist/server.cjs.map +1 -1
  345. package/dist/server.d.cts.map +1 -1
  346. package/dist/server.d.ts.map +1 -1
  347. package/dist/server.js +223 -147
  348. package/dist/server.js.map +1 -1
  349. package/dist/speech.cjs +20 -18
  350. package/dist/speech.cjs.map +1 -1
  351. package/dist/speech.d.cts.map +1 -1
  352. package/dist/speech.d.ts.map +1 -1
  353. package/dist/speech.js +19 -17
  354. package/dist/speech.js.map +1 -1
  355. package/dist/sse-writer.cjs +7 -0
  356. package/dist/sse-writer.cjs.map +1 -1
  357. package/dist/sse-writer.d.cts.map +1 -1
  358. package/dist/sse-writer.d.ts.map +1 -1
  359. package/dist/sse-writer.js +7 -1
  360. package/dist/sse-writer.js.map +1 -1
  361. package/dist/stream-collapse.cjs +118 -11
  362. package/dist/stream-collapse.cjs.map +1 -1
  363. package/dist/stream-collapse.d.cts +10 -9
  364. package/dist/stream-collapse.d.cts.map +1 -1
  365. package/dist/stream-collapse.d.ts +10 -9
  366. package/dist/stream-collapse.d.ts.map +1 -1
  367. package/dist/stream-collapse.js +118 -11
  368. package/dist/stream-collapse.js.map +1 -1
  369. package/dist/transcription.cjs +12 -10
  370. package/dist/transcription.cjs.map +1 -1
  371. package/dist/transcription.d.cts.map +1 -1
  372. package/dist/transcription.d.ts.map +1 -1
  373. package/dist/transcription.js +11 -9
  374. package/dist/transcription.js.map +1 -1
  375. package/dist/types.cjs.map +1 -1
  376. package/dist/types.d.cts +62 -3
  377. package/dist/types.d.cts.map +1 -1
  378. package/dist/types.d.ts +62 -3
  379. package/dist/types.d.ts.map +1 -1
  380. package/dist/types.js.map +1 -1
  381. package/dist/vector-mock.cjs +3 -8
  382. package/dist/vector-mock.cjs.map +1 -1
  383. package/dist/vector-mock.d.cts.map +1 -1
  384. package/dist/vector-mock.d.ts.map +1 -1
  385. package/dist/vector-mock.js +3 -8
  386. package/dist/vector-mock.js.map +1 -1
  387. package/dist/vector-stores.cjs +2 -4
  388. package/dist/vector-stores.cjs.map +1 -1
  389. package/dist/vector-stores.d.cts.map +1 -1
  390. package/dist/vector-stores.d.ts.map +1 -1
  391. package/dist/vector-stores.js +2 -4
  392. package/dist/vector-stores.js.map +1 -1
  393. package/dist/veo-video.cjs +16 -14
  394. package/dist/veo-video.cjs.map +1 -1
  395. package/dist/veo-video.js +10 -8
  396. package/dist/veo-video.js.map +1 -1
  397. package/dist/video.cjs +21 -19
  398. package/dist/video.cjs.map +1 -1
  399. package/dist/video.d.cts.map +1 -1
  400. package/dist/video.d.ts.map +1 -1
  401. package/dist/video.js +20 -18
  402. package/dist/video.js.map +1 -1
  403. package/dist/ws-gemini-live.cjs +11 -3
  404. package/dist/ws-gemini-live.cjs.map +1 -1
  405. package/dist/ws-gemini-live.d.cts +0 -1
  406. package/dist/ws-gemini-live.d.cts.map +1 -1
  407. package/dist/ws-gemini-live.d.ts +0 -1
  408. package/dist/ws-gemini-live.d.ts.map +1 -1
  409. package/dist/ws-gemini-live.js +10 -2
  410. package/dist/ws-gemini-live.js.map +1 -1
  411. package/dist/ws-live.cjs +6 -5
  412. package/dist/ws-live.cjs.map +1 -1
  413. package/dist/ws-live.js +5 -4
  414. package/dist/ws-live.js.map +1 -1
  415. package/dist/ws-realtime.cjs +28 -54
  416. package/dist/ws-realtime.cjs.map +1 -1
  417. package/dist/ws-realtime.d.cts.map +1 -1
  418. package/dist/ws-realtime.d.ts.map +1 -1
  419. package/dist/ws-realtime.js +25 -51
  420. package/dist/ws-realtime.js.map +1 -1
  421. package/dist/ws-responses.cjs +8 -6
  422. package/dist/ws-responses.cjs.map +1 -1
  423. package/dist/ws-responses.js +7 -5
  424. package/dist/ws-responses.js.map +1 -1
  425. package/package.json +4 -1
  426. package/skills/write-fixtures/SKILL.md +25 -16
@@ -0,0 +1,52 @@
1
+ const require_estimate = require('../estimate.cjs');
2
+
3
+ //#region src/response/usage/codecs/openai.ts
4
+ /** Token aliases shared with the OpenRouter passthrough exclusion. Order is observable. */
5
+ const OPENAI_TOKEN_KEYS = [
6
+ "prompt_tokens",
7
+ "completion_tokens",
8
+ "total_tokens",
9
+ "input_tokens",
10
+ "output_tokens",
11
+ "promptTokenCount",
12
+ "candidatesTokenCount",
13
+ "totalTokenCount"
14
+ ];
15
+ /** Preserve definedness, alias precedence and caller text estimation without sanitizing. */
16
+ function resolve(overrides, context) {
17
+ const { promptText, completionText } = context;
18
+ if (overrides?.usage) {
19
+ const u = overrides.usage;
20
+ const hasExplicitTokens = OPENAI_TOKEN_KEYS.some((key) => u[key] !== void 0);
21
+ const fallbackPrompt = hasExplicitTokens ? 0 : require_estimate.estimateTokens(promptText || "x");
22
+ const fallbackCompletion = hasExplicitTokens ? 0 : require_estimate.estimateTokens(completionText || "x");
23
+ const prompt = u.prompt_tokens ?? u.input_tokens ?? u.promptTokenCount ?? fallbackPrompt;
24
+ const completion = u.completion_tokens ?? u.output_tokens ?? u.candidatesTokenCount ?? fallbackCompletion;
25
+ return {
26
+ prompt,
27
+ completion,
28
+ total: u.total_tokens ?? u.totalTokenCount ?? prompt + completion
29
+ };
30
+ }
31
+ const prompt = require_estimate.estimateTokens(promptText || "x");
32
+ const completion = require_estimate.estimateTokens(completionText || "x");
33
+ return {
34
+ prompt,
35
+ completion,
36
+ total: prompt + completion
37
+ };
38
+ }
39
+ /** Native field order is identical for final responses and terminal usage chunks. */
40
+ function render(usage) {
41
+ return {
42
+ prompt_tokens: usage.prompt,
43
+ completion_tokens: usage.completion,
44
+ total_tokens: usage.total
45
+ };
46
+ }
47
+
48
+ //#endregion
49
+ exports.OPENAI_TOKEN_KEYS = OPENAI_TOKEN_KEYS;
50
+ exports.render = render;
51
+ exports.resolve = resolve;
52
+ //# sourceMappingURL=openai.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.cjs","names":["estimateTokens"],"sources":["../../../../src/response/usage/codecs/openai.ts"],"sourcesContent":["import type { ResponseOverrides } from \"../../../types.js\";\nimport { estimateTokens } from \"../estimate.js\";\n\n/** Token aliases shared with the OpenRouter passthrough exclusion. Order is observable. */\nexport const OPENAI_TOKEN_KEYS = [\n \"prompt_tokens\",\n \"completion_tokens\",\n \"total_tokens\",\n \"input_tokens\",\n \"output_tokens\",\n \"promptTokenCount\",\n \"candidatesTokenCount\",\n \"totalTokenCount\",\n] as const;\n\ninterface ResolvedOpenAIUsage {\n prompt: number;\n completion: number;\n total: number;\n}\n\n/** Preserve definedness, alias precedence and caller text estimation without sanitizing. */\nexport function resolve(\n overrides: ResponseOverrides | undefined,\n context: { promptText: string; completionText: string },\n): ResolvedOpenAIUsage {\n const { promptText, completionText } = context;\n if (overrides?.usage) {\n const u = overrides.usage;\n // A usage override that scripts only cost fields (e.g. `{ cost: 0.5 }`)\n // carries NO token counts. Real providers always report real token usage,\n // so estimate the counts rather than forcing them to 0 — otherwise a\n // cost-scripting fixture is unfaithful (cost present, tokens 0). When the\n // override DOES set any token count we preserve the explicit-or-zero merge\n // behavior, and any explicit token value always wins.\n const hasExplicitTokens = OPENAI_TOKEN_KEYS.some((key) => u[key] !== undefined);\n const fallbackPrompt = hasExplicitTokens ? 0 : estimateTokens(promptText || \"x\");\n const fallbackCompletion = hasExplicitTokens ? 0 : estimateTokens(completionText || \"x\");\n const prompt = u.prompt_tokens ?? u.input_tokens ?? u.promptTokenCount ?? fallbackPrompt;\n const completion =\n u.completion_tokens ?? u.output_tokens ?? u.candidatesTokenCount ?? fallbackCompletion;\n return {\n prompt,\n completion,\n total: u.total_tokens ?? u.totalTokenCount ?? prompt + completion,\n };\n }\n const prompt = estimateTokens(promptText || \"x\");\n const completion = estimateTokens(completionText || \"x\");\n return {\n prompt,\n completion,\n total: prompt + completion,\n };\n}\n\n/** Native field order is identical for final responses and terminal usage chunks. */\nexport function render(usage: ResolvedOpenAIUsage): {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n} {\n return {\n prompt_tokens: usage.prompt,\n completion_tokens: usage.completion,\n total_tokens: usage.total,\n };\n}\n"],"mappings":";;;;AAIA,MAAa,oBAAoB;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;AASD,SAAgB,QACd,WACA,SACqB;CACrB,MAAM,EAAE,YAAY,mBAAmB;AACvC,KAAI,WAAW,OAAO;EACpB,MAAM,IAAI,UAAU;EAOpB,MAAM,oBAAoB,kBAAkB,MAAM,QAAQ,EAAE,SAAS,OAAU;EAC/E,MAAM,iBAAiB,oBAAoB,IAAIA,gCAAe,cAAc,IAAI;EAChF,MAAM,qBAAqB,oBAAoB,IAAIA,gCAAe,kBAAkB,IAAI;EACxF,MAAM,SAAS,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,oBAAoB;EAC1E,MAAM,aACJ,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,wBAAwB;AACtE,SAAO;GACL;GACA;GACA,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,SAAS;GACxD;;CAEH,MAAM,SAASA,gCAAe,cAAc,IAAI;CAChD,MAAM,aAAaA,gCAAe,kBAAkB,IAAI;AACxD,QAAO;EACL;EACA;EACA,OAAO,SAAS;EACjB;;;AAIH,SAAgB,OAAO,OAIrB;AACA,QAAO;EACL,eAAe,MAAM;EACrB,mBAAmB,MAAM;EACzB,cAAc,MAAM;EACrB"}
@@ -0,0 +1,50 @@
1
+ import { estimateTokens } from "../estimate.js";
2
+
3
+ //#region src/response/usage/codecs/openai.ts
4
+ /** Token aliases shared with the OpenRouter passthrough exclusion. Order is observable. */
5
+ const OPENAI_TOKEN_KEYS = [
6
+ "prompt_tokens",
7
+ "completion_tokens",
8
+ "total_tokens",
9
+ "input_tokens",
10
+ "output_tokens",
11
+ "promptTokenCount",
12
+ "candidatesTokenCount",
13
+ "totalTokenCount"
14
+ ];
15
+ /** Preserve definedness, alias precedence and caller text estimation without sanitizing. */
16
+ function resolve(overrides, context) {
17
+ const { promptText, completionText } = context;
18
+ if (overrides?.usage) {
19
+ const u = overrides.usage;
20
+ const hasExplicitTokens = OPENAI_TOKEN_KEYS.some((key) => u[key] !== void 0);
21
+ const fallbackPrompt = hasExplicitTokens ? 0 : estimateTokens(promptText || "x");
22
+ const fallbackCompletion = hasExplicitTokens ? 0 : estimateTokens(completionText || "x");
23
+ const prompt = u.prompt_tokens ?? u.input_tokens ?? u.promptTokenCount ?? fallbackPrompt;
24
+ const completion = u.completion_tokens ?? u.output_tokens ?? u.candidatesTokenCount ?? fallbackCompletion;
25
+ return {
26
+ prompt,
27
+ completion,
28
+ total: u.total_tokens ?? u.totalTokenCount ?? prompt + completion
29
+ };
30
+ }
31
+ const prompt = estimateTokens(promptText || "x");
32
+ const completion = estimateTokens(completionText || "x");
33
+ return {
34
+ prompt,
35
+ completion,
36
+ total: prompt + completion
37
+ };
38
+ }
39
+ /** Native field order is identical for final responses and terminal usage chunks. */
40
+ function render(usage) {
41
+ return {
42
+ prompt_tokens: usage.prompt,
43
+ completion_tokens: usage.completion,
44
+ total_tokens: usage.total
45
+ };
46
+ }
47
+
48
+ //#endregion
49
+ export { OPENAI_TOKEN_KEYS, render, resolve };
50
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","names":[],"sources":["../../../../src/response/usage/codecs/openai.ts"],"sourcesContent":["import type { ResponseOverrides } from \"../../../types.js\";\nimport { estimateTokens } from \"../estimate.js\";\n\n/** Token aliases shared with the OpenRouter passthrough exclusion. Order is observable. */\nexport const OPENAI_TOKEN_KEYS = [\n \"prompt_tokens\",\n \"completion_tokens\",\n \"total_tokens\",\n \"input_tokens\",\n \"output_tokens\",\n \"promptTokenCount\",\n \"candidatesTokenCount\",\n \"totalTokenCount\",\n] as const;\n\ninterface ResolvedOpenAIUsage {\n prompt: number;\n completion: number;\n total: number;\n}\n\n/** Preserve definedness, alias precedence and caller text estimation without sanitizing. */\nexport function resolve(\n overrides: ResponseOverrides | undefined,\n context: { promptText: string; completionText: string },\n): ResolvedOpenAIUsage {\n const { promptText, completionText } = context;\n if (overrides?.usage) {\n const u = overrides.usage;\n // A usage override that scripts only cost fields (e.g. `{ cost: 0.5 }`)\n // carries NO token counts. Real providers always report real token usage,\n // so estimate the counts rather than forcing them to 0 — otherwise a\n // cost-scripting fixture is unfaithful (cost present, tokens 0). When the\n // override DOES set any token count we preserve the explicit-or-zero merge\n // behavior, and any explicit token value always wins.\n const hasExplicitTokens = OPENAI_TOKEN_KEYS.some((key) => u[key] !== undefined);\n const fallbackPrompt = hasExplicitTokens ? 0 : estimateTokens(promptText || \"x\");\n const fallbackCompletion = hasExplicitTokens ? 0 : estimateTokens(completionText || \"x\");\n const prompt = u.prompt_tokens ?? u.input_tokens ?? u.promptTokenCount ?? fallbackPrompt;\n const completion =\n u.completion_tokens ?? u.output_tokens ?? u.candidatesTokenCount ?? fallbackCompletion;\n return {\n prompt,\n completion,\n total: u.total_tokens ?? u.totalTokenCount ?? prompt + completion,\n };\n }\n const prompt = estimateTokens(promptText || \"x\");\n const completion = estimateTokens(completionText || \"x\");\n return {\n prompt,\n completion,\n total: prompt + completion,\n };\n}\n\n/** Native field order is identical for final responses and terminal usage chunks. */\nexport function render(usage: ResolvedOpenAIUsage): {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n} {\n return {\n prompt_tokens: usage.prompt,\n completion_tokens: usage.completion,\n total_tokens: usage.total,\n };\n}\n"],"mappings":";;;;AAIA,MAAa,oBAAoB;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;AASD,SAAgB,QACd,WACA,SACqB;CACrB,MAAM,EAAE,YAAY,mBAAmB;AACvC,KAAI,WAAW,OAAO;EACpB,MAAM,IAAI,UAAU;EAOpB,MAAM,oBAAoB,kBAAkB,MAAM,QAAQ,EAAE,SAAS,OAAU;EAC/E,MAAM,iBAAiB,oBAAoB,IAAI,eAAe,cAAc,IAAI;EAChF,MAAM,qBAAqB,oBAAoB,IAAI,eAAe,kBAAkB,IAAI;EACxF,MAAM,SAAS,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,oBAAoB;EAC1E,MAAM,aACJ,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,wBAAwB;AACtE,SAAO;GACL;GACA;GACA,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,SAAS;GACxD;;CAEH,MAAM,SAAS,eAAe,cAAc,IAAI;CAChD,MAAM,aAAa,eAAe,kBAAkB,IAAI;AACxD,QAAO;EACL;EACA;EACA,OAAO,SAAS;EACjB;;;AAIH,SAAgB,OAAO,OAIrB;AACA,QAAO;EACL,eAAe,MAAM;EACrB,mBAAmB,MAAM;EACzB,cAAc,MAAM;EACrB"}
@@ -0,0 +1,68 @@
1
+ const require_openai = require('./openai.cjs');
2
+
3
+ //#region src/response/usage/codecs/openrouter.ts
4
+ /** Explicit extras follow canonical tokens; own prototype keys never pass through. */
5
+ const SHAPED_OR_CANONICAL_USAGE_KEYS = new Set([
6
+ ...require_openai.OPENAI_TOKEN_KEYS,
7
+ "cost",
8
+ "cost_details",
9
+ "prompt_tokens_details",
10
+ "completion_tokens_details",
11
+ "is_byok"
12
+ ]);
13
+ /**
14
+ * Keys that must never flow through the passthrough assignment below: a
15
+ * JSON-parsed usage frame (fixtures are attacker-adjacent — they mirror upstream
16
+ * provider responses) can carry a real own `__proto__`/`constructor`/`prototype`
17
+ * key, and a plain `usageExtras[key] = value` for one of those hits the
18
+ * prototype setter, corrupting the emitted object's prototype chain instead of
19
+ * emitting a data field. Real providers never send these, so skipping is safe.
20
+ */
21
+ const UNSAFE_PROTO_KEYS = new Set([
22
+ "__proto__",
23
+ "constructor",
24
+ "prototype"
25
+ ]);
26
+ /** Keep suppliedness, required nested defaults and original unknown-key insertion order. */
27
+ function resolve(overrides) {
28
+ const u = overrides?.usage;
29
+ const usageExtras = {};
30
+ if (u?.cost !== void 0) {
31
+ usageExtras.cost = u.cost;
32
+ const cd = u.cost_details;
33
+ usageExtras.cost_details = {
34
+ ...cd ?? {},
35
+ upstream_inference_cost: cd?.upstream_inference_cost ?? 0,
36
+ upstream_inference_prompt_cost: cd?.upstream_inference_prompt_cost ?? 0,
37
+ upstream_inference_completions_cost: cd?.upstream_inference_completions_cost ?? 0
38
+ };
39
+ }
40
+ if (u?.prompt_tokens_details !== void 0) usageExtras.prompt_tokens_details = {
41
+ ...u.prompt_tokens_details,
42
+ cached_tokens: u.prompt_tokens_details.cached_tokens ?? 0
43
+ };
44
+ if (u?.completion_tokens_details !== void 0) usageExtras.completion_tokens_details = {
45
+ ...u.completion_tokens_details,
46
+ reasoning_tokens: u.completion_tokens_details.reasoning_tokens ?? 0
47
+ };
48
+ if (u?.is_byok !== void 0) usageExtras.is_byok = u.is_byok;
49
+ for (const [key, value] of Object.entries(u ?? {})) {
50
+ if (value === void 0) continue;
51
+ if (SHAPED_OR_CANONICAL_USAGE_KEYS.has(key)) continue;
52
+ if (UNSAFE_PROTO_KEYS.has(key)) continue;
53
+ usageExtras[key] = value;
54
+ }
55
+ return usageExtras;
56
+ }
57
+ /** Wrap the rendered OpenAI usage without dropping fields on compatibility callers. */
58
+ function render(usage, extras) {
59
+ return {
60
+ ...usage,
61
+ ...extras
62
+ };
63
+ }
64
+
65
+ //#endregion
66
+ exports.render = render;
67
+ exports.resolve = resolve;
68
+ //# sourceMappingURL=openrouter.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openrouter.cjs","names":["OPENAI_TOKEN_KEYS"],"sources":["../../../../src/response/usage/codecs/openrouter.ts"],"sourcesContent":["import type { OpenRouterUsageExtras, ResponseOverrides } from \"../../../types.js\";\nimport { OPENAI_TOKEN_KEYS } from \"./openai.js\";\n\n/** Explicit extras follow canonical tokens; own prototype keys never pass through. */\nconst SHAPED_OR_CANONICAL_USAGE_KEYS = new Set([\n ...OPENAI_TOKEN_KEYS,\n \"cost\",\n \"cost_details\",\n \"prompt_tokens_details\",\n \"completion_tokens_details\",\n \"is_byok\",\n]);\n\n/**\n * Keys that must never flow through the passthrough assignment below: a\n * JSON-parsed usage frame (fixtures are attacker-adjacent — they mirror upstream\n * provider responses) can carry a real own `__proto__`/`constructor`/`prototype`\n * key, and a plain `usageExtras[key] = value` for one of those hits the\n * prototype setter, corrupting the emitted object's prototype chain instead of\n * emitting a data field. Real providers never send these, so skipping is safe.\n */\nconst UNSAFE_PROTO_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\n/** Keep suppliedness, required nested defaults and original unknown-key insertion order. */\nexport function resolve(overrides: ResponseOverrides | undefined): OpenRouterUsageExtras {\n const u = overrides?.usage;\n const usageExtras: OpenRouterUsageExtras = {};\n if (u?.cost !== undefined) {\n usageExtras.cost = u.cost;\n const cd = u.cost_details;\n usageExtras.cost_details = {\n ...(cd ?? {}),\n upstream_inference_cost: cd?.upstream_inference_cost ?? 0,\n upstream_inference_prompt_cost: cd?.upstream_inference_prompt_cost ?? 0,\n upstream_inference_completions_cost: cd?.upstream_inference_completions_cost ?? 0,\n };\n }\n if (u?.prompt_tokens_details !== undefined) {\n usageExtras.prompt_tokens_details = {\n ...u.prompt_tokens_details,\n cached_tokens: u.prompt_tokens_details.cached_tokens ?? 0,\n };\n }\n if (u?.completion_tokens_details !== undefined) {\n usageExtras.completion_tokens_details = {\n ...u.completion_tokens_details,\n reasoning_tokens: u.completion_tokens_details.reasoning_tokens ?? 0,\n };\n }\n if (u?.is_byok !== undefined) {\n usageExtras.is_byok = u.is_byok;\n }\n // Forward-compat passthrough (#368): a fixture's `usage` may carry provider\n // fields aimock does not model — typically written by the recorder straight\n // from a real upstream usage frame (OpenRouter `native_tokens_prompt`,\n // `native_tokens_completion`, …). Emit them verbatim rather than silently\n // dropping them, so a recorded usage object round-trips on replay. The\n // canonical token counts and every field shaped above are excluded: those are\n // already resolved onto the base usage object (see helpers.ts `resolveUsage`)\n // or handled with their own required-member defaults.\n for (const [key, value] of Object.entries(u ?? {})) {\n if (value === undefined) continue;\n if (SHAPED_OR_CANONICAL_USAGE_KEYS.has(key)) continue;\n if (UNSAFE_PROTO_KEYS.has(key)) continue;\n usageExtras[key] = value;\n }\n return usageExtras;\n}\n\n/** Wrap the rendered OpenAI usage without dropping fields on compatibility callers. */\nexport function render<T extends object>(\n usage: T,\n extras: OpenRouterUsageExtras,\n): T & OpenRouterUsageExtras {\n return { ...usage, ...extras };\n}\n"],"mappings":";;;;AAIA,MAAM,iCAAiC,IAAI,IAAI;CAC7C,GAAGA;CACH;CACA;CACA;CACA;CACA;CACD,CAAC;;;;;;;;;AAUF,MAAM,oBAAoB,IAAI,IAAI;CAAC;CAAa;CAAe;CAAY,CAAC;;AAG5E,SAAgB,QAAQ,WAAiE;CACvF,MAAM,IAAI,WAAW;CACrB,MAAM,cAAqC,EAAE;AAC7C,KAAI,GAAG,SAAS,QAAW;AACzB,cAAY,OAAO,EAAE;EACrB,MAAM,KAAK,EAAE;AACb,cAAY,eAAe;GACzB,GAAI,MAAM,EAAE;GACZ,yBAAyB,IAAI,2BAA2B;GACxD,gCAAgC,IAAI,kCAAkC;GACtE,qCAAqC,IAAI,uCAAuC;GACjF;;AAEH,KAAI,GAAG,0BAA0B,OAC/B,aAAY,wBAAwB;EAClC,GAAG,EAAE;EACL,eAAe,EAAE,sBAAsB,iBAAiB;EACzD;AAEH,KAAI,GAAG,8BAA8B,OACnC,aAAY,4BAA4B;EACtC,GAAG,EAAE;EACL,kBAAkB,EAAE,0BAA0B,oBAAoB;EACnE;AAEH,KAAI,GAAG,YAAY,OACjB,aAAY,UAAU,EAAE;AAU1B,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,EAAE,CAAC,EAAE;AAClD,MAAI,UAAU,OAAW;AACzB,MAAI,+BAA+B,IAAI,IAAI,CAAE;AAC7C,MAAI,kBAAkB,IAAI,IAAI,CAAE;AAChC,cAAY,OAAO;;AAErB,QAAO;;;AAIT,SAAgB,OACd,OACA,QAC2B;AAC3B,QAAO;EAAE,GAAG;EAAO,GAAG;EAAQ"}
@@ -0,0 +1,67 @@
1
+ import { OPENAI_TOKEN_KEYS } from "./openai.js";
2
+
3
+ //#region src/response/usage/codecs/openrouter.ts
4
+ /** Explicit extras follow canonical tokens; own prototype keys never pass through. */
5
+ const SHAPED_OR_CANONICAL_USAGE_KEYS = new Set([
6
+ ...OPENAI_TOKEN_KEYS,
7
+ "cost",
8
+ "cost_details",
9
+ "prompt_tokens_details",
10
+ "completion_tokens_details",
11
+ "is_byok"
12
+ ]);
13
+ /**
14
+ * Keys that must never flow through the passthrough assignment below: a
15
+ * JSON-parsed usage frame (fixtures are attacker-adjacent — they mirror upstream
16
+ * provider responses) can carry a real own `__proto__`/`constructor`/`prototype`
17
+ * key, and a plain `usageExtras[key] = value` for one of those hits the
18
+ * prototype setter, corrupting the emitted object's prototype chain instead of
19
+ * emitting a data field. Real providers never send these, so skipping is safe.
20
+ */
21
+ const UNSAFE_PROTO_KEYS = new Set([
22
+ "__proto__",
23
+ "constructor",
24
+ "prototype"
25
+ ]);
26
+ /** Keep suppliedness, required nested defaults and original unknown-key insertion order. */
27
+ function resolve(overrides) {
28
+ const u = overrides?.usage;
29
+ const usageExtras = {};
30
+ if (u?.cost !== void 0) {
31
+ usageExtras.cost = u.cost;
32
+ const cd = u.cost_details;
33
+ usageExtras.cost_details = {
34
+ ...cd ?? {},
35
+ upstream_inference_cost: cd?.upstream_inference_cost ?? 0,
36
+ upstream_inference_prompt_cost: cd?.upstream_inference_prompt_cost ?? 0,
37
+ upstream_inference_completions_cost: cd?.upstream_inference_completions_cost ?? 0
38
+ };
39
+ }
40
+ if (u?.prompt_tokens_details !== void 0) usageExtras.prompt_tokens_details = {
41
+ ...u.prompt_tokens_details,
42
+ cached_tokens: u.prompt_tokens_details.cached_tokens ?? 0
43
+ };
44
+ if (u?.completion_tokens_details !== void 0) usageExtras.completion_tokens_details = {
45
+ ...u.completion_tokens_details,
46
+ reasoning_tokens: u.completion_tokens_details.reasoning_tokens ?? 0
47
+ };
48
+ if (u?.is_byok !== void 0) usageExtras.is_byok = u.is_byok;
49
+ for (const [key, value] of Object.entries(u ?? {})) {
50
+ if (value === void 0) continue;
51
+ if (SHAPED_OR_CANONICAL_USAGE_KEYS.has(key)) continue;
52
+ if (UNSAFE_PROTO_KEYS.has(key)) continue;
53
+ usageExtras[key] = value;
54
+ }
55
+ return usageExtras;
56
+ }
57
+ /** Wrap the rendered OpenAI usage without dropping fields on compatibility callers. */
58
+ function render(usage, extras) {
59
+ return {
60
+ ...usage,
61
+ ...extras
62
+ };
63
+ }
64
+
65
+ //#endregion
66
+ export { render, resolve };
67
+ //# sourceMappingURL=openrouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openrouter.js","names":[],"sources":["../../../../src/response/usage/codecs/openrouter.ts"],"sourcesContent":["import type { OpenRouterUsageExtras, ResponseOverrides } from \"../../../types.js\";\nimport { OPENAI_TOKEN_KEYS } from \"./openai.js\";\n\n/** Explicit extras follow canonical tokens; own prototype keys never pass through. */\nconst SHAPED_OR_CANONICAL_USAGE_KEYS = new Set([\n ...OPENAI_TOKEN_KEYS,\n \"cost\",\n \"cost_details\",\n \"prompt_tokens_details\",\n \"completion_tokens_details\",\n \"is_byok\",\n]);\n\n/**\n * Keys that must never flow through the passthrough assignment below: a\n * JSON-parsed usage frame (fixtures are attacker-adjacent — they mirror upstream\n * provider responses) can carry a real own `__proto__`/`constructor`/`prototype`\n * key, and a plain `usageExtras[key] = value` for one of those hits the\n * prototype setter, corrupting the emitted object's prototype chain instead of\n * emitting a data field. Real providers never send these, so skipping is safe.\n */\nconst UNSAFE_PROTO_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\n/** Keep suppliedness, required nested defaults and original unknown-key insertion order. */\nexport function resolve(overrides: ResponseOverrides | undefined): OpenRouterUsageExtras {\n const u = overrides?.usage;\n const usageExtras: OpenRouterUsageExtras = {};\n if (u?.cost !== undefined) {\n usageExtras.cost = u.cost;\n const cd = u.cost_details;\n usageExtras.cost_details = {\n ...(cd ?? {}),\n upstream_inference_cost: cd?.upstream_inference_cost ?? 0,\n upstream_inference_prompt_cost: cd?.upstream_inference_prompt_cost ?? 0,\n upstream_inference_completions_cost: cd?.upstream_inference_completions_cost ?? 0,\n };\n }\n if (u?.prompt_tokens_details !== undefined) {\n usageExtras.prompt_tokens_details = {\n ...u.prompt_tokens_details,\n cached_tokens: u.prompt_tokens_details.cached_tokens ?? 0,\n };\n }\n if (u?.completion_tokens_details !== undefined) {\n usageExtras.completion_tokens_details = {\n ...u.completion_tokens_details,\n reasoning_tokens: u.completion_tokens_details.reasoning_tokens ?? 0,\n };\n }\n if (u?.is_byok !== undefined) {\n usageExtras.is_byok = u.is_byok;\n }\n // Forward-compat passthrough (#368): a fixture's `usage` may carry provider\n // fields aimock does not model — typically written by the recorder straight\n // from a real upstream usage frame (OpenRouter `native_tokens_prompt`,\n // `native_tokens_completion`, …). Emit them verbatim rather than silently\n // dropping them, so a recorded usage object round-trips on replay. The\n // canonical token counts and every field shaped above are excluded: those are\n // already resolved onto the base usage object (see helpers.ts `resolveUsage`)\n // or handled with their own required-member defaults.\n for (const [key, value] of Object.entries(u ?? {})) {\n if (value === undefined) continue;\n if (SHAPED_OR_CANONICAL_USAGE_KEYS.has(key)) continue;\n if (UNSAFE_PROTO_KEYS.has(key)) continue;\n usageExtras[key] = value;\n }\n return usageExtras;\n}\n\n/** Wrap the rendered OpenAI usage without dropping fields on compatibility callers. */\nexport function render<T extends object>(\n usage: T,\n extras: OpenRouterUsageExtras,\n): T & OpenRouterUsageExtras {\n return { ...usage, ...extras };\n}\n"],"mappings":";;;;AAIA,MAAM,iCAAiC,IAAI,IAAI;CAC7C,GAAG;CACH;CACA;CACA;CACA;CACA;CACD,CAAC;;;;;;;;;AAUF,MAAM,oBAAoB,IAAI,IAAI;CAAC;CAAa;CAAe;CAAY,CAAC;;AAG5E,SAAgB,QAAQ,WAAiE;CACvF,MAAM,IAAI,WAAW;CACrB,MAAM,cAAqC,EAAE;AAC7C,KAAI,GAAG,SAAS,QAAW;AACzB,cAAY,OAAO,EAAE;EACrB,MAAM,KAAK,EAAE;AACb,cAAY,eAAe;GACzB,GAAI,MAAM,EAAE;GACZ,yBAAyB,IAAI,2BAA2B;GACxD,gCAAgC,IAAI,kCAAkC;GACtE,qCAAqC,IAAI,uCAAuC;GACjF;;AAEH,KAAI,GAAG,0BAA0B,OAC/B,aAAY,wBAAwB;EAClC,GAAG,EAAE;EACL,eAAe,EAAE,sBAAsB,iBAAiB;EACzD;AAEH,KAAI,GAAG,8BAA8B,OACnC,aAAY,4BAA4B;EACtC,GAAG,EAAE;EACL,kBAAkB,EAAE,0BAA0B,oBAAoB;EACnE;AAEH,KAAI,GAAG,YAAY,OACjB,aAAY,UAAU,EAAE;AAU1B,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,EAAE,CAAC,EAAE;AAClD,MAAI,UAAU,OAAW;AACzB,MAAI,+BAA+B,IAAI,IAAI,CAAE;AAC7C,MAAI,kBAAkB,IAAI,IAAI,CAAE;AAChC,cAAY,OAAO;;AAErB,QAAO;;;AAIT,SAAgB,OACd,OACA,QAC2B;AAC3B,QAAO;EAAE,GAAG;EAAO,GAAG;EAAQ"}
@@ -0,0 +1,19 @@
1
+
2
+ //#region src/response/usage/codecs/realtime.ts
3
+ /** Render chat usage only; transcription retains its model-dependent discriminator. */
4
+ function render(state) {
5
+ if (state.kind === "applied-misbehavior") return {
6
+ input_tokens: state.usage.prompt_tokens,
7
+ output_tokens: state.usage.completion_tokens,
8
+ total_tokens: state.usage.total_tokens
9
+ };
10
+ return {
11
+ total_tokens: 0,
12
+ input_tokens: 0,
13
+ output_tokens: 0
14
+ };
15
+ }
16
+
17
+ //#endregion
18
+ exports.render = render;
19
+ //# sourceMappingURL=realtime.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime.cjs","names":[],"sources":["../../../../src/response/usage/codecs/realtime.ts"],"sourcesContent":["type RealtimeChatUsage =\n | { kind: \"ordinary-zero\" }\n | {\n kind: \"applied-misbehavior\";\n usage: { prompt_tokens: number; completion_tokens: number; total_tokens: number };\n };\n\n/** Render chat usage only; transcription retains its model-dependent discriminator. */\nexport function render(state: RealtimeChatUsage) {\n if (state.kind === \"applied-misbehavior\") {\n return {\n input_tokens: state.usage.prompt_tokens,\n output_tokens: state.usage.completion_tokens,\n total_tokens: state.usage.total_tokens,\n };\n }\n return { total_tokens: 0, input_tokens: 0, output_tokens: 0 };\n}\n"],"mappings":";;;AAQA,SAAgB,OAAO,OAA0B;AAC/C,KAAI,MAAM,SAAS,sBACjB,QAAO;EACL,cAAc,MAAM,MAAM;EAC1B,eAAe,MAAM,MAAM;EAC3B,cAAc,MAAM,MAAM;EAC3B;AAEH,QAAO;EAAE,cAAc;EAAG,cAAc;EAAG,eAAe;EAAG"}
@@ -0,0 +1,18 @@
1
+ //#region src/response/usage/codecs/realtime.ts
2
+ /** Render chat usage only; transcription retains its model-dependent discriminator. */
3
+ function render(state) {
4
+ if (state.kind === "applied-misbehavior") return {
5
+ input_tokens: state.usage.prompt_tokens,
6
+ output_tokens: state.usage.completion_tokens,
7
+ total_tokens: state.usage.total_tokens
8
+ };
9
+ return {
10
+ total_tokens: 0,
11
+ input_tokens: 0,
12
+ output_tokens: 0
13
+ };
14
+ }
15
+
16
+ //#endregion
17
+ export { render };
18
+ //# sourceMappingURL=realtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime.js","names":[],"sources":["../../../../src/response/usage/codecs/realtime.ts"],"sourcesContent":["type RealtimeChatUsage =\n | { kind: \"ordinary-zero\" }\n | {\n kind: \"applied-misbehavior\";\n usage: { prompt_tokens: number; completion_tokens: number; total_tokens: number };\n };\n\n/** Render chat usage only; transcription retains its model-dependent discriminator. */\nexport function render(state: RealtimeChatUsage) {\n if (state.kind === \"applied-misbehavior\") {\n return {\n input_tokens: state.usage.prompt_tokens,\n output_tokens: state.usage.completion_tokens,\n total_tokens: state.usage.total_tokens,\n };\n }\n return { total_tokens: 0, input_tokens: 0, output_tokens: 0 };\n}\n"],"mappings":";;AAQA,SAAgB,OAAO,OAA0B;AAC/C,KAAI,MAAM,SAAS,sBACjB,QAAO;EACL,cAAc,MAAM,MAAM;EAC1B,eAAe,MAAM,MAAM;EAC3B,cAAc,MAAM,MAAM;EAC3B;AAEH,QAAO;EAAE,cAAc;EAAG,cAAc;EAAG,eAAe;EAAG"}
@@ -0,0 +1,21 @@
1
+
2
+ //#region src/response/usage/codecs/responses.ts
3
+ /** Responses keeps native aliases first and emits all three counts, including absent zeros. */
4
+ function render(overrides) {
5
+ if (!overrides?.usage) return {
6
+ input_tokens: 0,
7
+ output_tokens: 0,
8
+ total_tokens: 0
9
+ };
10
+ const input = overrides.usage.input_tokens ?? overrides.usage.prompt_tokens ?? 0;
11
+ const output = overrides.usage.output_tokens ?? overrides.usage.completion_tokens ?? 0;
12
+ return {
13
+ input_tokens: input,
14
+ output_tokens: output,
15
+ total_tokens: overrides.usage.total_tokens ?? input + output
16
+ };
17
+ }
18
+
19
+ //#endregion
20
+ exports.render = render;
21
+ //# sourceMappingURL=responses.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"responses.cjs","names":[],"sources":["../../../../src/response/usage/codecs/responses.ts"],"sourcesContent":["import type { ResponseOverrides } from \"../../../types.js\";\n\n/** Responses keeps native aliases first and emits all three counts, including absent zeros. */\nexport function render(overrides?: ResponseOverrides): {\n input_tokens: number;\n output_tokens: number;\n total_tokens: number;\n} {\n if (!overrides?.usage) return { input_tokens: 0, output_tokens: 0, total_tokens: 0 };\n const input = overrides.usage.input_tokens ?? overrides.usage.prompt_tokens ?? 0;\n const output = overrides.usage.output_tokens ?? overrides.usage.completion_tokens ?? 0;\n return {\n input_tokens: input,\n output_tokens: output,\n total_tokens: overrides.usage.total_tokens ?? input + output,\n };\n}\n"],"mappings":";;;AAGA,SAAgB,OAAO,WAIrB;AACA,KAAI,CAAC,WAAW,MAAO,QAAO;EAAE,cAAc;EAAG,eAAe;EAAG,cAAc;EAAG;CACpF,MAAM,QAAQ,UAAU,MAAM,gBAAgB,UAAU,MAAM,iBAAiB;CAC/E,MAAM,SAAS,UAAU,MAAM,iBAAiB,UAAU,MAAM,qBAAqB;AACrF,QAAO;EACL,cAAc;EACd,eAAe;EACf,cAAc,UAAU,MAAM,gBAAgB,QAAQ;EACvD"}
@@ -0,0 +1,20 @@
1
+ //#region src/response/usage/codecs/responses.ts
2
+ /** Responses keeps native aliases first and emits all three counts, including absent zeros. */
3
+ function render(overrides) {
4
+ if (!overrides?.usage) return {
5
+ input_tokens: 0,
6
+ output_tokens: 0,
7
+ total_tokens: 0
8
+ };
9
+ const input = overrides.usage.input_tokens ?? overrides.usage.prompt_tokens ?? 0;
10
+ const output = overrides.usage.output_tokens ?? overrides.usage.completion_tokens ?? 0;
11
+ return {
12
+ input_tokens: input,
13
+ output_tokens: output,
14
+ total_tokens: overrides.usage.total_tokens ?? input + output
15
+ };
16
+ }
17
+
18
+ //#endregion
19
+ export { render };
20
+ //# sourceMappingURL=responses.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"responses.js","names":[],"sources":["../../../../src/response/usage/codecs/responses.ts"],"sourcesContent":["import type { ResponseOverrides } from \"../../../types.js\";\n\n/** Responses keeps native aliases first and emits all three counts, including absent zeros. */\nexport function render(overrides?: ResponseOverrides): {\n input_tokens: number;\n output_tokens: number;\n total_tokens: number;\n} {\n if (!overrides?.usage) return { input_tokens: 0, output_tokens: 0, total_tokens: 0 };\n const input = overrides.usage.input_tokens ?? overrides.usage.prompt_tokens ?? 0;\n const output = overrides.usage.output_tokens ?? overrides.usage.completion_tokens ?? 0;\n return {\n input_tokens: input,\n output_tokens: output,\n total_tokens: overrides.usage.total_tokens ?? input + output,\n };\n}\n"],"mappings":";;AAGA,SAAgB,OAAO,WAIrB;AACA,KAAI,CAAC,WAAW,MAAO,QAAO;EAAE,cAAc;EAAG,eAAe;EAAG,cAAc;EAAG;CACpF,MAAM,QAAQ,UAAU,MAAM,gBAAgB,UAAU,MAAM,iBAAiB;CAC/E,MAAM,SAAS,UAAU,MAAM,iBAAiB,UAAU,MAAM,qBAAqB;AACrF,QAAO;EACL,cAAc;EACd,eAAe;EACf,cAAc,UAAU,MAAM,gBAAgB,QAAQ;EACvD"}
@@ -0,0 +1,23 @@
1
+
2
+ //#region src/response/usage/estimate.ts
3
+ /**
4
+ * Rough token count estimation based on character length.
5
+ * Uses the ~4 characters per token heuristic common for English text.
6
+ */
7
+ function estimateTokens(text) {
8
+ return Math.max(1, Math.ceil(text.length / 4));
9
+ }
10
+ /** Estimate prompt tokens from a request's messages array. */
11
+ function estimatePromptTokens(messages) {
12
+ let totalChars = 0;
13
+ for (const msg of messages) if (typeof msg.content === "string") totalChars += msg.content.length;
14
+ else if (Array.isArray(msg.content)) {
15
+ for (const part of msg.content) if (part.text) totalChars += part.text.length;
16
+ }
17
+ return Math.max(1, Math.ceil(totalChars / 4));
18
+ }
19
+
20
+ //#endregion
21
+ exports.estimatePromptTokens = estimatePromptTokens;
22
+ exports.estimateTokens = estimateTokens;
23
+ //# sourceMappingURL=estimate.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estimate.cjs","names":[],"sources":["../../../src/response/usage/estimate.ts"],"sourcesContent":["import type { ChatCompletionRequest } from \"../../types.js\";\n\n/**\n * Rough token count estimation based on character length.\n * Uses the ~4 characters per token heuristic common for English text.\n */\nexport function estimateTokens(text: string): number {\n return Math.max(1, Math.ceil(text.length / 4));\n}\n\n/** Estimate prompt tokens from a request's messages array. */\nexport function estimatePromptTokens(messages: ChatCompletionRequest[\"messages\"]): number {\n let totalChars = 0;\n for (const msg of messages) {\n if (typeof msg.content === \"string\") {\n totalChars += msg.content.length;\n } else if (Array.isArray(msg.content)) {\n for (const part of msg.content) {\n if (part.text) totalChars += part.text.length;\n }\n }\n }\n return Math.max(1, Math.ceil(totalChars / 4));\n}\n"],"mappings":";;;;;;AAMA,SAAgB,eAAe,MAAsB;AACnD,QAAO,KAAK,IAAI,GAAG,KAAK,KAAK,KAAK,SAAS,EAAE,CAAC;;;AAIhD,SAAgB,qBAAqB,UAAqD;CACxF,IAAI,aAAa;AACjB,MAAK,MAAM,OAAO,SAChB,KAAI,OAAO,IAAI,YAAY,SACzB,eAAc,IAAI,QAAQ;UACjB,MAAM,QAAQ,IAAI,QAAQ,EACnC;OAAK,MAAM,QAAQ,IAAI,QACrB,KAAI,KAAK,KAAM,eAAc,KAAK,KAAK;;AAI7C,QAAO,KAAK,IAAI,GAAG,KAAK,KAAK,aAAa,EAAE,CAAC"}
@@ -0,0 +1,21 @@
1
+ //#region src/response/usage/estimate.ts
2
+ /**
3
+ * Rough token count estimation based on character length.
4
+ * Uses the ~4 characters per token heuristic common for English text.
5
+ */
6
+ function estimateTokens(text) {
7
+ return Math.max(1, Math.ceil(text.length / 4));
8
+ }
9
+ /** Estimate prompt tokens from a request's messages array. */
10
+ function estimatePromptTokens(messages) {
11
+ let totalChars = 0;
12
+ for (const msg of messages) if (typeof msg.content === "string") totalChars += msg.content.length;
13
+ else if (Array.isArray(msg.content)) {
14
+ for (const part of msg.content) if (part.text) totalChars += part.text.length;
15
+ }
16
+ return Math.max(1, Math.ceil(totalChars / 4));
17
+ }
18
+
19
+ //#endregion
20
+ export { estimatePromptTokens, estimateTokens };
21
+ //# sourceMappingURL=estimate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estimate.js","names":[],"sources":["../../../src/response/usage/estimate.ts"],"sourcesContent":["import type { ChatCompletionRequest } from \"../../types.js\";\n\n/**\n * Rough token count estimation based on character length.\n * Uses the ~4 characters per token heuristic common for English text.\n */\nexport function estimateTokens(text: string): number {\n return Math.max(1, Math.ceil(text.length / 4));\n}\n\n/** Estimate prompt tokens from a request's messages array. */\nexport function estimatePromptTokens(messages: ChatCompletionRequest[\"messages\"]): number {\n let totalChars = 0;\n for (const msg of messages) {\n if (typeof msg.content === \"string\") {\n totalChars += msg.content.length;\n } else if (Array.isArray(msg.content)) {\n for (const part of msg.content) {\n if (part.text) totalChars += part.text.length;\n }\n }\n }\n return Math.max(1, Math.ceil(totalChars / 4));\n}\n"],"mappings":";;;;;AAMA,SAAgB,eAAe,MAAsB;AACnD,QAAO,KAAK,IAAI,GAAG,KAAK,KAAK,KAAK,SAAS,EAAE,CAAC;;;AAIhD,SAAgB,qBAAqB,UAAqD;CACxF,IAAI,aAAa;AACjB,MAAK,MAAM,OAAO,SAChB,KAAI,OAAO,IAAI,YAAY,SACzB,eAAc,IAAI,QAAQ;UACjB,MAAM,QAAQ,IAAI,QAAQ,EACnC;OAAK,MAAM,QAAQ,IAAI,QACrB,KAAI,KAAK,KAAM,eAAc,KAAK,KAAK;;AAI7C,QAAO,KAAK,IAAI,GAAG,KAAK,KAAK,aAAa,EAAE,CAAC"}
@@ -0,0 +1,72 @@
1
+
2
+ //#region src/response/usage/fields.ts
3
+ /** Shared classification; validation checks only the documented inner members. */
4
+ const USAGE_FIELD_DEFINITIONS = {
5
+ cache_creation: {
6
+ kind: "number-or-object",
7
+ numericMembers: ["ephemeral_5m_input_tokens", "ephemeral_1h_input_tokens"]
8
+ },
9
+ cost_details: {
10
+ kind: "object",
11
+ numericMembers: [
12
+ "upstream_inference_cost",
13
+ "upstream_inference_prompt_cost",
14
+ "upstream_inference_completions_cost"
15
+ ]
16
+ },
17
+ prompt_tokens_details: {
18
+ kind: "object",
19
+ numericMembers: [
20
+ "cached_tokens",
21
+ "cache_write_tokens",
22
+ "audio_tokens"
23
+ ]
24
+ },
25
+ completion_tokens_details: {
26
+ kind: "object",
27
+ numericMembers: ["reasoning_tokens"]
28
+ },
29
+ is_byok: { kind: "boolean" }
30
+ };
31
+ const NUMERIC_FIELD = { kind: "number" };
32
+ /** Unknown keys, including prototype names, retain numeric-scalar classification. */
33
+ function getUsageFieldDefinition(key) {
34
+ return Object.hasOwn(USAGE_FIELD_DEFINITIONS, key) ? USAGE_FIELD_DEFINITIONS[key] : NUMERIC_FIELD;
35
+ }
36
+ /** Recording retains finite numbers, including members of recognized usage objects. */
37
+ function sanitizeUsage(raw) {
38
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return void 0;
39
+ const out = {};
40
+ for (const [key, val] of Object.entries(raw)) {
41
+ if (val === void 0 || val === null) continue;
42
+ const definition = getUsageFieldDefinition(key);
43
+ if (definition.kind === "number-or-object" && typeof val === "number") {
44
+ if (Number.isFinite(val)) out[key] = val;
45
+ continue;
46
+ }
47
+ if (definition.kind === "object" || definition.kind === "number-or-object") {
48
+ if (typeof val !== "object" || val === null || Array.isArray(val)) continue;
49
+ const inner = {};
50
+ for (const [innerKey, innerVal] of Object.entries(val)) if (typeof innerVal === "number" && Number.isFinite(innerVal)) if (key === "cache_creation") Object.defineProperty(inner, innerKey, {
51
+ value: innerVal,
52
+ enumerable: true,
53
+ configurable: true,
54
+ writable: true
55
+ });
56
+ else inner[innerKey] = innerVal;
57
+ if (Object.keys(inner).length > 0) out[key] = inner;
58
+ continue;
59
+ }
60
+ if (definition.kind === "boolean") {
61
+ if (typeof val === "boolean") out[key] = val;
62
+ continue;
63
+ }
64
+ if (typeof val === "number" && Number.isFinite(val)) out[key] = val;
65
+ }
66
+ return Object.keys(out).length > 0 ? out : void 0;
67
+ }
68
+
69
+ //#endregion
70
+ exports.getUsageFieldDefinition = getUsageFieldDefinition;
71
+ exports.sanitizeUsage = sanitizeUsage;
72
+ //# sourceMappingURL=fields.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fields.cjs","names":[],"sources":["../../../src/response/usage/fields.ts"],"sourcesContent":["import type { ResponseOverrides } from \"../../types.js\";\n\ntype UsageFieldDefinition =\n | { readonly kind: \"number\" }\n | { readonly kind: \"boolean\" }\n | { readonly kind: \"object\" | \"number-or-object\"; readonly numericMembers: readonly string[] };\n\n/** Shared classification; validation checks only the documented inner members. */\nconst USAGE_FIELD_DEFINITIONS = {\n cache_creation: {\n kind: \"number-or-object\",\n numericMembers: [\"ephemeral_5m_input_tokens\", \"ephemeral_1h_input_tokens\"],\n },\n cost_details: {\n kind: \"object\",\n numericMembers: [\n \"upstream_inference_cost\",\n \"upstream_inference_prompt_cost\",\n \"upstream_inference_completions_cost\",\n ],\n },\n prompt_tokens_details: {\n kind: \"object\",\n numericMembers: [\"cached_tokens\", \"cache_write_tokens\", \"audio_tokens\"],\n },\n completion_tokens_details: { kind: \"object\", numericMembers: [\"reasoning_tokens\"] },\n is_byok: { kind: \"boolean\" },\n} as const satisfies Readonly<Record<string, UsageFieldDefinition>>;\n\nconst NUMERIC_FIELD: UsageFieldDefinition = { kind: \"number\" };\n\n/** Unknown keys, including prototype names, retain numeric-scalar classification. */\nexport function getUsageFieldDefinition(key: string): UsageFieldDefinition {\n return Object.hasOwn(USAGE_FIELD_DEFINITIONS, key)\n ? USAGE_FIELD_DEFINITIONS[key as keyof typeof USAGE_FIELD_DEFINITIONS]\n : NUMERIC_FIELD;\n}\n\n/** Recording retains finite numbers, including members of recognized usage objects. */\nexport function sanitizeUsage(raw: unknown): ResponseOverrides[\"usage\"] | undefined {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) return undefined;\n const out: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(raw as Record<string, unknown>)) {\n if (val === undefined || val === null) continue;\n const definition = getUsageFieldDefinition(key);\n if (definition.kind === \"number-or-object\" && typeof val === \"number\") {\n if (Number.isFinite(val)) out[key] = val;\n continue;\n }\n if (definition.kind === \"object\" || definition.kind === \"number-or-object\") {\n if (typeof val !== \"object\" || val === null || Array.isArray(val)) continue;\n const inner: Record<string, unknown> = {};\n for (const [innerKey, innerVal] of Object.entries(val as Record<string, unknown>)) {\n if (typeof innerVal === \"number\" && Number.isFinite(innerVal)) {\n if (key === \"cache_creation\") {\n // Cache members parsed from JSON include own names such as __proto__.\n Object.defineProperty(inner, innerKey, {\n value: innerVal,\n enumerable: true,\n configurable: true,\n writable: true,\n });\n } else inner[innerKey] = innerVal;\n }\n }\n if (Object.keys(inner).length > 0) out[key] = inner;\n continue;\n }\n if (definition.kind === \"boolean\") {\n if (typeof val === \"boolean\") out[key] = val;\n continue;\n }\n if (typeof val === \"number\" && Number.isFinite(val)) out[key] = val;\n }\n return Object.keys(out).length > 0 ? (out as ResponseOverrides[\"usage\"]) : undefined;\n}\n"],"mappings":";;;AAQA,MAAM,0BAA0B;CAC9B,gBAAgB;EACd,MAAM;EACN,gBAAgB,CAAC,6BAA6B,4BAA4B;EAC3E;CACD,cAAc;EACZ,MAAM;EACN,gBAAgB;GACd;GACA;GACA;GACD;EACF;CACD,uBAAuB;EACrB,MAAM;EACN,gBAAgB;GAAC;GAAiB;GAAsB;GAAe;EACxE;CACD,2BAA2B;EAAE,MAAM;EAAU,gBAAgB,CAAC,mBAAmB;EAAE;CACnF,SAAS,EAAE,MAAM,WAAW;CAC7B;AAED,MAAM,gBAAsC,EAAE,MAAM,UAAU;;AAG9D,SAAgB,wBAAwB,KAAmC;AACzE,QAAO,OAAO,OAAO,yBAAyB,IAAI,GAC9C,wBAAwB,OACxB;;;AAIN,SAAgB,cAAc,KAAsD;AAClF,KAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,MAAM,QAAQ,IAAI,CAAE,QAAO;CAC1E,MAAM,MAA+B,EAAE;AACvC,MAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,IAA+B,EAAE;AACvE,MAAI,QAAQ,UAAa,QAAQ,KAAM;EACvC,MAAM,aAAa,wBAAwB,IAAI;AAC/C,MAAI,WAAW,SAAS,sBAAsB,OAAO,QAAQ,UAAU;AACrE,OAAI,OAAO,SAAS,IAAI,CAAE,KAAI,OAAO;AACrC;;AAEF,MAAI,WAAW,SAAS,YAAY,WAAW,SAAS,oBAAoB;AAC1E,OAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,MAAM,QAAQ,IAAI,CAAE;GACnE,MAAM,QAAiC,EAAE;AACzC,QAAK,MAAM,CAAC,UAAU,aAAa,OAAO,QAAQ,IAA+B,CAC/E,KAAI,OAAO,aAAa,YAAY,OAAO,SAAS,SAAS,CAC3D,KAAI,QAAQ,iBAEV,QAAO,eAAe,OAAO,UAAU;IACrC,OAAO;IACP,YAAY;IACZ,cAAc;IACd,UAAU;IACX,CAAC;OACG,OAAM,YAAY;AAG7B,OAAI,OAAO,KAAK,MAAM,CAAC,SAAS,EAAG,KAAI,OAAO;AAC9C;;AAEF,MAAI,WAAW,SAAS,WAAW;AACjC,OAAI,OAAO,QAAQ,UAAW,KAAI,OAAO;AACzC;;AAEF,MAAI,OAAO,QAAQ,YAAY,OAAO,SAAS,IAAI,CAAE,KAAI,OAAO;;AAElE,QAAO,OAAO,KAAK,IAAI,CAAC,SAAS,IAAK,MAAqC"}
@@ -0,0 +1,70 @@
1
+ //#region src/response/usage/fields.ts
2
+ /** Shared classification; validation checks only the documented inner members. */
3
+ const USAGE_FIELD_DEFINITIONS = {
4
+ cache_creation: {
5
+ kind: "number-or-object",
6
+ numericMembers: ["ephemeral_5m_input_tokens", "ephemeral_1h_input_tokens"]
7
+ },
8
+ cost_details: {
9
+ kind: "object",
10
+ numericMembers: [
11
+ "upstream_inference_cost",
12
+ "upstream_inference_prompt_cost",
13
+ "upstream_inference_completions_cost"
14
+ ]
15
+ },
16
+ prompt_tokens_details: {
17
+ kind: "object",
18
+ numericMembers: [
19
+ "cached_tokens",
20
+ "cache_write_tokens",
21
+ "audio_tokens"
22
+ ]
23
+ },
24
+ completion_tokens_details: {
25
+ kind: "object",
26
+ numericMembers: ["reasoning_tokens"]
27
+ },
28
+ is_byok: { kind: "boolean" }
29
+ };
30
+ const NUMERIC_FIELD = { kind: "number" };
31
+ /** Unknown keys, including prototype names, retain numeric-scalar classification. */
32
+ function getUsageFieldDefinition(key) {
33
+ return Object.hasOwn(USAGE_FIELD_DEFINITIONS, key) ? USAGE_FIELD_DEFINITIONS[key] : NUMERIC_FIELD;
34
+ }
35
+ /** Recording retains finite numbers, including members of recognized usage objects. */
36
+ function sanitizeUsage(raw) {
37
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return void 0;
38
+ const out = {};
39
+ for (const [key, val] of Object.entries(raw)) {
40
+ if (val === void 0 || val === null) continue;
41
+ const definition = getUsageFieldDefinition(key);
42
+ if (definition.kind === "number-or-object" && typeof val === "number") {
43
+ if (Number.isFinite(val)) out[key] = val;
44
+ continue;
45
+ }
46
+ if (definition.kind === "object" || definition.kind === "number-or-object") {
47
+ if (typeof val !== "object" || val === null || Array.isArray(val)) continue;
48
+ const inner = {};
49
+ for (const [innerKey, innerVal] of Object.entries(val)) if (typeof innerVal === "number" && Number.isFinite(innerVal)) if (key === "cache_creation") Object.defineProperty(inner, innerKey, {
50
+ value: innerVal,
51
+ enumerable: true,
52
+ configurable: true,
53
+ writable: true
54
+ });
55
+ else inner[innerKey] = innerVal;
56
+ if (Object.keys(inner).length > 0) out[key] = inner;
57
+ continue;
58
+ }
59
+ if (definition.kind === "boolean") {
60
+ if (typeof val === "boolean") out[key] = val;
61
+ continue;
62
+ }
63
+ if (typeof val === "number" && Number.isFinite(val)) out[key] = val;
64
+ }
65
+ return Object.keys(out).length > 0 ? out : void 0;
66
+ }
67
+
68
+ //#endregion
69
+ export { getUsageFieldDefinition, sanitizeUsage };
70
+ //# sourceMappingURL=fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fields.js","names":[],"sources":["../../../src/response/usage/fields.ts"],"sourcesContent":["import type { ResponseOverrides } from \"../../types.js\";\n\ntype UsageFieldDefinition =\n | { readonly kind: \"number\" }\n | { readonly kind: \"boolean\" }\n | { readonly kind: \"object\" | \"number-or-object\"; readonly numericMembers: readonly string[] };\n\n/** Shared classification; validation checks only the documented inner members. */\nconst USAGE_FIELD_DEFINITIONS = {\n cache_creation: {\n kind: \"number-or-object\",\n numericMembers: [\"ephemeral_5m_input_tokens\", \"ephemeral_1h_input_tokens\"],\n },\n cost_details: {\n kind: \"object\",\n numericMembers: [\n \"upstream_inference_cost\",\n \"upstream_inference_prompt_cost\",\n \"upstream_inference_completions_cost\",\n ],\n },\n prompt_tokens_details: {\n kind: \"object\",\n numericMembers: [\"cached_tokens\", \"cache_write_tokens\", \"audio_tokens\"],\n },\n completion_tokens_details: { kind: \"object\", numericMembers: [\"reasoning_tokens\"] },\n is_byok: { kind: \"boolean\" },\n} as const satisfies Readonly<Record<string, UsageFieldDefinition>>;\n\nconst NUMERIC_FIELD: UsageFieldDefinition = { kind: \"number\" };\n\n/** Unknown keys, including prototype names, retain numeric-scalar classification. */\nexport function getUsageFieldDefinition(key: string): UsageFieldDefinition {\n return Object.hasOwn(USAGE_FIELD_DEFINITIONS, key)\n ? USAGE_FIELD_DEFINITIONS[key as keyof typeof USAGE_FIELD_DEFINITIONS]\n : NUMERIC_FIELD;\n}\n\n/** Recording retains finite numbers, including members of recognized usage objects. */\nexport function sanitizeUsage(raw: unknown): ResponseOverrides[\"usage\"] | undefined {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) return undefined;\n const out: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(raw as Record<string, unknown>)) {\n if (val === undefined || val === null) continue;\n const definition = getUsageFieldDefinition(key);\n if (definition.kind === \"number-or-object\" && typeof val === \"number\") {\n if (Number.isFinite(val)) out[key] = val;\n continue;\n }\n if (definition.kind === \"object\" || definition.kind === \"number-or-object\") {\n if (typeof val !== \"object\" || val === null || Array.isArray(val)) continue;\n const inner: Record<string, unknown> = {};\n for (const [innerKey, innerVal] of Object.entries(val as Record<string, unknown>)) {\n if (typeof innerVal === \"number\" && Number.isFinite(innerVal)) {\n if (key === \"cache_creation\") {\n // Cache members parsed from JSON include own names such as __proto__.\n Object.defineProperty(inner, innerKey, {\n value: innerVal,\n enumerable: true,\n configurable: true,\n writable: true,\n });\n } else inner[innerKey] = innerVal;\n }\n }\n if (Object.keys(inner).length > 0) out[key] = inner;\n continue;\n }\n if (definition.kind === \"boolean\") {\n if (typeof val === \"boolean\") out[key] = val;\n continue;\n }\n if (typeof val === \"number\" && Number.isFinite(val)) out[key] = val;\n }\n return Object.keys(out).length > 0 ? (out as ResponseOverrides[\"usage\"]) : undefined;\n}\n"],"mappings":";;AAQA,MAAM,0BAA0B;CAC9B,gBAAgB;EACd,MAAM;EACN,gBAAgB,CAAC,6BAA6B,4BAA4B;EAC3E;CACD,cAAc;EACZ,MAAM;EACN,gBAAgB;GACd;GACA;GACA;GACD;EACF;CACD,uBAAuB;EACrB,MAAM;EACN,gBAAgB;GAAC;GAAiB;GAAsB;GAAe;EACxE;CACD,2BAA2B;EAAE,MAAM;EAAU,gBAAgB,CAAC,mBAAmB;EAAE;CACnF,SAAS,EAAE,MAAM,WAAW;CAC7B;AAED,MAAM,gBAAsC,EAAE,MAAM,UAAU;;AAG9D,SAAgB,wBAAwB,KAAmC;AACzE,QAAO,OAAO,OAAO,yBAAyB,IAAI,GAC9C,wBAAwB,OACxB;;;AAIN,SAAgB,cAAc,KAAsD;AAClF,KAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,MAAM,QAAQ,IAAI,CAAE,QAAO;CAC1E,MAAM,MAA+B,EAAE;AACvC,MAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,IAA+B,EAAE;AACvE,MAAI,QAAQ,UAAa,QAAQ,KAAM;EACvC,MAAM,aAAa,wBAAwB,IAAI;AAC/C,MAAI,WAAW,SAAS,sBAAsB,OAAO,QAAQ,UAAU;AACrE,OAAI,OAAO,SAAS,IAAI,CAAE,KAAI,OAAO;AACrC;;AAEF,MAAI,WAAW,SAAS,YAAY,WAAW,SAAS,oBAAoB;AAC1E,OAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,MAAM,QAAQ,IAAI,CAAE;GACnE,MAAM,QAAiC,EAAE;AACzC,QAAK,MAAM,CAAC,UAAU,aAAa,OAAO,QAAQ,IAA+B,CAC/E,KAAI,OAAO,aAAa,YAAY,OAAO,SAAS,SAAS,CAC3D,KAAI,QAAQ,iBAEV,QAAO,eAAe,OAAO,UAAU;IACrC,OAAO;IACP,YAAY;IACZ,cAAc;IACd,UAAU;IACX,CAAC;OACG,OAAM,YAAY;AAG7B,OAAI,OAAO,KAAK,MAAM,CAAC,SAAS,EAAG,KAAI,OAAO;AAC9C;;AAEF,MAAI,WAAW,SAAS,WAAW;AACjC,OAAI,OAAO,QAAQ,UAAW,KAAI,OAAO;AACzC;;AAEF,MAAI,OAAO,QAAQ,YAAY,OAAO,SAAS,IAAI,CAAE,KAAI,OAAO;;AAElE,QAAO,OAAO,KAAK,IAAI,CAAC,SAAS,IAAK,MAAqC"}