@raybase/core 0.0.2 → 0.3.3

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 (435) hide show
  1. package/LICENSE +21 -0
  2. package/dist/.admin-build/AdminApp.css +2 -0
  3. package/dist/.admin-build/AdminApp.js +77 -0
  4. package/dist/.admin-docs-build/AdminDocsApp.css +2 -0
  5. package/dist/.admin-docs-build/AdminDocsApp.js +45 -0
  6. package/dist/actions.d.ts +347 -0
  7. package/dist/actions.d.ts.map +1 -0
  8. package/dist/actions.js +661 -0
  9. package/dist/actions.js.map +1 -0
  10. package/dist/admin-assets/admin.7738f50720a8ed7b.css +2 -0
  11. package/dist/admin-assets/admin.8678cb61db34dc81.js +77 -0
  12. package/dist/admin-boot.d.ts +94 -0
  13. package/dist/admin-boot.d.ts.map +1 -0
  14. package/dist/admin-boot.js +139 -0
  15. package/dist/admin-boot.js.map +1 -0
  16. package/dist/admin-docs-content.d.ts +95 -0
  17. package/dist/admin-docs-content.d.ts.map +1 -0
  18. package/dist/admin-docs-content.js +463 -0
  19. package/dist/admin-docs-content.js.map +1 -0
  20. package/dist/admin-docs-ui.d.ts +11 -0
  21. package/dist/admin-docs-ui.d.ts.map +1 -0
  22. package/dist/admin-docs-ui.js +23 -0
  23. package/dist/admin-docs-ui.js.map +1 -0
  24. package/dist/admin-kit.d.ts +29 -0
  25. package/dist/admin-kit.js +1557 -0
  26. package/dist/admin-role.d.ts +8 -0
  27. package/dist/admin-role.d.ts.map +1 -0
  28. package/dist/admin-role.js +22 -0
  29. package/dist/admin-role.js.map +1 -0
  30. package/dist/admin-ui.d.ts +3 -0
  31. package/dist/admin-ui.d.ts.map +1 -0
  32. package/dist/admin-ui.js +16 -0
  33. package/dist/admin-ui.js.map +1 -0
  34. package/dist/agent-ai-chat.d.ts +127 -0
  35. package/dist/agent-ai-chat.d.ts.map +1 -0
  36. package/dist/agent-ai-chat.js +5975 -0
  37. package/dist/agent-ai-chat.js.map +1 -0
  38. package/dist/agent-chapter-archive.d.ts +214 -0
  39. package/dist/agent-chapter-archive.d.ts.map +1 -0
  40. package/dist/agent-chapter-archive.js +696 -0
  41. package/dist/agent-chapter-archive.js.map +1 -0
  42. package/dist/agent-chapter-search.d.ts +116 -0
  43. package/dist/agent-chapter-search.d.ts.map +1 -0
  44. package/dist/agent-chapter-search.js +605 -0
  45. package/dist/agent-chapter-search.js.map +1 -0
  46. package/dist/agent-chapter-tools.d.ts +45 -0
  47. package/dist/agent-chapter-tools.d.ts.map +1 -0
  48. package/dist/agent-chapter-tools.js +344 -0
  49. package/dist/agent-chapter-tools.js.map +1 -0
  50. package/dist/agent-chapters.d.ts +228 -0
  51. package/dist/agent-chapters.d.ts.map +1 -0
  52. package/dist/agent-chapters.js +737 -0
  53. package/dist/agent-chapters.js.map +1 -0
  54. package/dist/agent-data-parts.d.ts +167 -0
  55. package/dist/agent-data-parts.d.ts.map +1 -0
  56. package/dist/agent-data-parts.js +68 -0
  57. package/dist/agent-data-parts.js.map +1 -0
  58. package/dist/agent-errors.d.ts +41 -0
  59. package/dist/agent-errors.d.ts.map +1 -0
  60. package/dist/agent-errors.js +191 -0
  61. package/dist/agent-errors.js.map +1 -0
  62. package/dist/agent-follow-up-store.d.ts +273 -0
  63. package/dist/agent-follow-up-store.d.ts.map +1 -0
  64. package/dist/agent-follow-up-store.js +703 -0
  65. package/dist/agent-follow-up-store.js.map +1 -0
  66. package/dist/agent-follow-ups.d.ts +314 -0
  67. package/dist/agent-follow-ups.d.ts.map +1 -0
  68. package/dist/agent-follow-ups.js +840 -0
  69. package/dist/agent-follow-ups.js.map +1 -0
  70. package/dist/agent-memory.d.ts +323 -0
  71. package/dist/agent-memory.d.ts.map +1 -0
  72. package/dist/agent-memory.js +1270 -0
  73. package/dist/agent-memory.js.map +1 -0
  74. package/dist/agent-message-parts.d.ts +58 -0
  75. package/dist/agent-message-parts.d.ts.map +1 -0
  76. package/dist/agent-message-parts.js +163 -0
  77. package/dist/agent-message-parts.js.map +1 -0
  78. package/dist/agent-remote-mcp-credentials.d.ts +154 -0
  79. package/dist/agent-remote-mcp-credentials.d.ts.map +1 -0
  80. package/dist/agent-remote-mcp-credentials.js +287 -0
  81. package/dist/agent-remote-mcp-credentials.js.map +1 -0
  82. package/dist/agent-remote-mcp-crypto.d.ts +32 -0
  83. package/dist/agent-remote-mcp-crypto.d.ts.map +1 -0
  84. package/dist/agent-remote-mcp-crypto.js +101 -0
  85. package/dist/agent-remote-mcp-crypto.js.map +1 -0
  86. package/dist/agent-remote-mcp-install.d.ts +299 -0
  87. package/dist/agent-remote-mcp-install.d.ts.map +1 -0
  88. package/dist/agent-remote-mcp-install.js +785 -0
  89. package/dist/agent-remote-mcp-install.js.map +1 -0
  90. package/dist/agent-remote-mcp-oauth.d.ts +73 -0
  91. package/dist/agent-remote-mcp-oauth.d.ts.map +1 -0
  92. package/dist/agent-remote-mcp-oauth.js +344 -0
  93. package/dist/agent-remote-mcp-oauth.js.map +1 -0
  94. package/dist/agent-remote-mcp-transport.d.ts +46 -0
  95. package/dist/agent-remote-mcp-transport.d.ts.map +1 -0
  96. package/dist/agent-remote-mcp-transport.js +225 -0
  97. package/dist/agent-remote-mcp-transport.js.map +1 -0
  98. package/dist/agent-remote-mcp.d.ts +147 -0
  99. package/dist/agent-remote-mcp.d.ts.map +1 -0
  100. package/dist/agent-remote-mcp.js +681 -0
  101. package/dist/agent-remote-mcp.js.map +1 -0
  102. package/dist/agent-room-redaction.d.ts +66 -0
  103. package/dist/agent-room-redaction.d.ts.map +1 -0
  104. package/dist/agent-room-redaction.js +264 -0
  105. package/dist/agent-room-redaction.js.map +1 -0
  106. package/dist/agent-rooms.d.ts +209 -0
  107. package/dist/agent-rooms.d.ts.map +1 -0
  108. package/dist/agent-rooms.js +244 -0
  109. package/dist/agent-rooms.js.map +1 -0
  110. package/dist/agent-runtime.d.ts +541 -0
  111. package/dist/agent-runtime.d.ts.map +1 -0
  112. package/dist/agent-runtime.js +4260 -0
  113. package/dist/agent-runtime.js.map +1 -0
  114. package/dist/agent-skill-archive.d.ts +20 -0
  115. package/dist/agent-skill-archive.d.ts.map +1 -0
  116. package/dist/agent-skill-archive.js +316 -0
  117. package/dist/agent-skill-archive.js.map +1 -0
  118. package/dist/agent-skill-discovery.d.ts +96 -0
  119. package/dist/agent-skill-discovery.d.ts.map +1 -0
  120. package/dist/agent-skill-discovery.js +464 -0
  121. package/dist/agent-skill-discovery.js.map +1 -0
  122. package/dist/agent-skill-format.d.ts +57 -0
  123. package/dist/agent-skill-format.d.ts.map +1 -0
  124. package/dist/agent-skill-format.js +238 -0
  125. package/dist/agent-skill-format.js.map +1 -0
  126. package/dist/agent-skill-import.d.ts +64 -0
  127. package/dist/agent-skill-import.d.ts.map +1 -0
  128. package/dist/agent-skill-import.js +295 -0
  129. package/dist/agent-skill-import.js.map +1 -0
  130. package/dist/agent-skill-publish.d.ts +51 -0
  131. package/dist/agent-skill-publish.d.ts.map +1 -0
  132. package/dist/agent-skill-publish.js +136 -0
  133. package/dist/agent-skill-publish.js.map +1 -0
  134. package/dist/agent-skill-store.d.ts +252 -0
  135. package/dist/agent-skill-store.d.ts.map +1 -0
  136. package/dist/agent-skill-store.js +514 -0
  137. package/dist/agent-skill-store.js.map +1 -0
  138. package/dist/agent-skills.d.ts +85 -0
  139. package/dist/agent-skills.d.ts.map +1 -0
  140. package/dist/agent-skills.js +291 -0
  141. package/dist/agent-skills.js.map +1 -0
  142. package/dist/agent-transcript-pager.d.ts +77 -0
  143. package/dist/agent-transcript-pager.d.ts.map +1 -0
  144. package/dist/agent-transcript-pager.js +210 -0
  145. package/dist/agent-transcript-pager.js.map +1 -0
  146. package/dist/agent-user-data-parts.d.ts +20 -0
  147. package/dist/agent-user-data-parts.d.ts.map +1 -0
  148. package/dist/agent-user-data-parts.js +161 -0
  149. package/dist/agent-user-data-parts.js.map +1 -0
  150. package/dist/agent-user-transcript.d.ts +46 -0
  151. package/dist/agent-user-transcript.d.ts.map +1 -0
  152. package/dist/agent-user-transcript.js +106 -0
  153. package/dist/agent-user-transcript.js.map +1 -0
  154. package/dist/agent-voice-notes.d.ts +15 -0
  155. package/dist/agent-voice-notes.d.ts.map +1 -0
  156. package/dist/agent-voice-notes.js +17 -0
  157. package/dist/agent-voice-notes.js.map +1 -0
  158. package/dist/agent-wakes.d.ts +213 -0
  159. package/dist/agent-wakes.d.ts.map +1 -0
  160. package/dist/agent-wakes.js +534 -0
  161. package/dist/agent-wakes.js.map +1 -0
  162. package/dist/agent.d.ts +1780 -0
  163. package/dist/agent.d.ts.map +1 -0
  164. package/dist/agent.js +3123 -0
  165. package/dist/agent.js.map +1 -0
  166. package/dist/ai.d.ts +583 -0
  167. package/dist/ai.d.ts.map +1 -0
  168. package/dist/ai.js +1858 -0
  169. package/dist/ai.js.map +1 -0
  170. package/dist/app-manifest.d.ts +255 -0
  171. package/dist/app-manifest.d.ts.map +1 -0
  172. package/dist/app-manifest.js +372 -0
  173. package/dist/app-manifest.js.map +1 -0
  174. package/dist/app-users.d.ts +30 -0
  175. package/dist/app-users.d.ts.map +1 -0
  176. package/dist/app-users.js +91 -0
  177. package/dist/app-users.js.map +1 -0
  178. package/dist/audit-archive.d.ts +85 -0
  179. package/dist/audit-archive.d.ts.map +1 -0
  180. package/dist/audit-archive.js +178 -0
  181. package/dist/audit-archive.js.map +1 -0
  182. package/dist/audit.d.ts +54 -0
  183. package/dist/audit.d.ts.map +1 -0
  184. package/dist/audit.js +95 -0
  185. package/dist/audit.js.map +1 -0
  186. package/dist/auth-logger.d.ts +28 -0
  187. package/dist/auth-logger.d.ts.map +1 -0
  188. package/dist/auth-logger.js +53 -0
  189. package/dist/auth-logger.js.map +1 -0
  190. package/dist/auth-password-secret.d.ts +59 -0
  191. package/dist/auth-password-secret.d.ts.map +1 -0
  192. package/dist/auth-password-secret.js +409 -0
  193. package/dist/auth-password-secret.js.map +1 -0
  194. package/dist/auth-schema.d.ts +120 -0
  195. package/dist/auth-schema.d.ts.map +1 -0
  196. package/dist/auth-schema.js +285 -0
  197. package/dist/auth-schema.js.map +1 -0
  198. package/dist/auth.d.ts +321 -0
  199. package/dist/auth.d.ts.map +1 -0
  200. package/dist/auth.js +1562 -0
  201. package/dist/auth.js.map +1 -0
  202. package/dist/backup-archive.d.ts +257 -0
  203. package/dist/backup-archive.d.ts.map +1 -0
  204. package/dist/backup-archive.js +2068 -0
  205. package/dist/backup-archive.js.map +1 -0
  206. package/dist/backup-crypto.d.ts +313 -0
  207. package/dist/backup-crypto.d.ts.map +1 -0
  208. package/dist/backup-crypto.js +693 -0
  209. package/dist/backup-crypto.js.map +1 -0
  210. package/dist/backup-format.d.ts +200 -0
  211. package/dist/backup-format.d.ts.map +1 -0
  212. package/dist/backup-format.js +1247 -0
  213. package/dist/backup-format.js.map +1 -0
  214. package/dist/cli.d.ts +9 -0
  215. package/dist/cli.d.ts.map +1 -0
  216. package/dist/cli.js +15 -0
  217. package/dist/cli.js.map +1 -0
  218. package/dist/clock.d.ts +35 -0
  219. package/dist/clock.d.ts.map +1 -0
  220. package/dist/clock.js +83 -0
  221. package/dist/clock.js.map +1 -0
  222. package/dist/data-client.d.ts +187 -0
  223. package/dist/data-client.d.ts.map +1 -0
  224. package/dist/data-client.js +590 -0
  225. package/dist/data-client.js.map +1 -0
  226. package/dist/data-secrets.d.ts +164 -0
  227. package/dist/data-secrets.d.ts.map +1 -0
  228. package/dist/data-secrets.js +383 -0
  229. package/dist/data-secrets.js.map +1 -0
  230. package/dist/db.d.ts +453 -0
  231. package/dist/db.d.ts.map +1 -0
  232. package/dist/db.js +324 -0
  233. package/dist/db.js.map +1 -0
  234. package/dist/dev-activity.d.ts +48 -0
  235. package/dist/dev-activity.d.ts.map +1 -0
  236. package/dist/dev-activity.js +50 -0
  237. package/dist/dev-activity.js.map +1 -0
  238. package/dist/do.d.ts +429 -0
  239. package/dist/do.d.ts.map +1 -0
  240. package/dist/do.js +4526 -0
  241. package/dist/do.js.map +1 -0
  242. package/dist/email.d.ts +137 -0
  243. package/dist/email.d.ts.map +1 -0
  244. package/dist/email.js +527 -0
  245. package/dist/email.js.map +1 -0
  246. package/dist/generated/admin-assets.d.ts +16 -0
  247. package/dist/generated/admin-assets.d.ts.map +1 -0
  248. package/dist/generated/admin-assets.js +16 -0
  249. package/dist/generated/admin-assets.js.map +1 -0
  250. package/dist/generated/admin-docs-assets.d.ts +3 -0
  251. package/dist/generated/admin-docs-assets.d.ts.map +1 -0
  252. package/dist/generated/admin-docs-assets.js +3 -0
  253. package/dist/generated/admin-docs-assets.js.map +1 -0
  254. package/dist/handoff-consumer.d.ts +79 -0
  255. package/dist/handoff-consumer.d.ts.map +1 -0
  256. package/dist/handoff-consumer.js +300 -0
  257. package/dist/handoff-consumer.js.map +1 -0
  258. package/dist/handoff.d.ts +70 -0
  259. package/dist/handoff.d.ts.map +1 -0
  260. package/dist/handoff.js +228 -0
  261. package/dist/handoff.js.map +1 -0
  262. package/dist/host-auth.d.ts +47 -0
  263. package/dist/host-auth.d.ts.map +1 -0
  264. package/dist/host-auth.js +59 -0
  265. package/dist/host-auth.js.map +1 -0
  266. package/dist/host-user.d.ts +15 -0
  267. package/dist/host-user.d.ts.map +1 -0
  268. package/dist/host-user.js +23 -0
  269. package/dist/host-user.js.map +1 -0
  270. package/dist/html.d.ts +35 -0
  271. package/dist/html.d.ts.map +1 -0
  272. package/dist/html.js +634 -0
  273. package/dist/html.js.map +1 -0
  274. package/dist/http-error.d.ts +13 -0
  275. package/dist/http-error.d.ts.map +1 -0
  276. package/dist/http-error.js +15 -0
  277. package/dist/http-error.js.map +1 -0
  278. package/dist/imports.d.ts +219 -0
  279. package/dist/imports.d.ts.map +1 -0
  280. package/dist/imports.js +571 -0
  281. package/dist/imports.js.map +1 -0
  282. package/dist/index.d.ts +78 -0
  283. package/dist/index.d.ts.map +1 -0
  284. package/dist/index.js +76 -0
  285. package/dist/index.js.map +1 -0
  286. package/dist/inference-tape.d.ts +64 -0
  287. package/dist/inference-tape.d.ts.map +1 -0
  288. package/dist/inference-tape.js +278 -0
  289. package/dist/inference-tape.js.map +1 -0
  290. package/dist/internal.d.ts +15 -0
  291. package/dist/internal.d.ts.map +1 -0
  292. package/dist/internal.js +48 -0
  293. package/dist/internal.js.map +1 -0
  294. package/dist/jobs.d.ts +796 -0
  295. package/dist/jobs.d.ts.map +1 -0
  296. package/dist/jobs.js +538 -0
  297. package/dist/jobs.js.map +1 -0
  298. package/dist/json-schema.d.ts +91 -0
  299. package/dist/json-schema.d.ts.map +1 -0
  300. package/dist/json-schema.js +884 -0
  301. package/dist/json-schema.js.map +1 -0
  302. package/dist/knowledge.d.ts +33 -0
  303. package/dist/knowledge.d.ts.map +1 -0
  304. package/dist/knowledge.js +348 -0
  305. package/dist/knowledge.js.map +1 -0
  306. package/dist/local-dev-chrome.d.ts +29 -0
  307. package/dist/local-dev-chrome.d.ts.map +1 -0
  308. package/dist/local-dev-chrome.js +514 -0
  309. package/dist/local-dev-chrome.js.map +1 -0
  310. package/dist/local-dev-personas.d.ts +15 -0
  311. package/dist/local-dev-personas.d.ts.map +1 -0
  312. package/dist/local-dev-personas.js +46 -0
  313. package/dist/local-dev-personas.js.map +1 -0
  314. package/dist/mcp.d.ts +567 -0
  315. package/dist/mcp.d.ts.map +1 -0
  316. package/dist/mcp.js +2480 -0
  317. package/dist/mcp.js.map +1 -0
  318. package/dist/modules.d.ts +145 -0
  319. package/dist/modules.d.ts.map +1 -0
  320. package/dist/modules.js +164 -0
  321. package/dist/modules.js.map +1 -0
  322. package/dist/notification-client.d.ts +94 -0
  323. package/dist/notification-client.d.ts.map +1 -0
  324. package/dist/notification-client.js +127 -0
  325. package/dist/notification-client.js.map +1 -0
  326. package/dist/notifications.d.ts +447 -0
  327. package/dist/notifications.d.ts.map +1 -0
  328. package/dist/notifications.js +1625 -0
  329. package/dist/notifications.js.map +1 -0
  330. package/dist/operator-data-query.d.ts +117 -0
  331. package/dist/operator-data-query.d.ts.map +1 -0
  332. package/dist/operator-data-query.js +431 -0
  333. package/dist/operator-data-query.js.map +1 -0
  334. package/dist/operator-mcp.d.ts +63 -0
  335. package/dist/operator-mcp.d.ts.map +1 -0
  336. package/dist/operator-mcp.js +2828 -0
  337. package/dist/operator-mcp.js.map +1 -0
  338. package/dist/outbound-https.d.ts +24 -0
  339. package/dist/outbound-https.d.ts.map +1 -0
  340. package/dist/outbound-https.js +172 -0
  341. package/dist/outbound-https.js.map +1 -0
  342. package/dist/pitr.d.ts +60 -0
  343. package/dist/pitr.d.ts.map +1 -0
  344. package/dist/pitr.js +94 -0
  345. package/dist/pitr.js.map +1 -0
  346. package/dist/platform.d.ts +199 -0
  347. package/dist/platform.d.ts.map +1 -0
  348. package/dist/platform.js +196 -0
  349. package/dist/platform.js.map +1 -0
  350. package/dist/policies.d.ts +115 -0
  351. package/dist/policies.d.ts.map +1 -0
  352. package/dist/policies.js +158 -0
  353. package/dist/policies.js.map +1 -0
  354. package/dist/principal.d.ts +143 -0
  355. package/dist/principal.d.ts.map +1 -0
  356. package/dist/principal.js +174 -0
  357. package/dist/principal.js.map +1 -0
  358. package/dist/realtime.d.ts +280 -0
  359. package/dist/realtime.d.ts.map +1 -0
  360. package/dist/realtime.js +578 -0
  361. package/dist/realtime.js.map +1 -0
  362. package/dist/retrieval.d.ts +263 -0
  363. package/dist/retrieval.d.ts.map +1 -0
  364. package/dist/retrieval.js +602 -0
  365. package/dist/retrieval.js.map +1 -0
  366. package/dist/runtime-error-client.d.ts +10 -0
  367. package/dist/runtime-error-client.d.ts.map +1 -0
  368. package/dist/runtime-error-client.js +70 -0
  369. package/dist/runtime-error-client.js.map +1 -0
  370. package/dist/runtime-errors.d.ts +180 -0
  371. package/dist/runtime-errors.d.ts.map +1 -0
  372. package/dist/runtime-errors.js +572 -0
  373. package/dist/runtime-errors.js.map +1 -0
  374. package/dist/schema.d.ts +434 -0
  375. package/dist/schema.d.ts.map +1 -0
  376. package/dist/schema.js +232 -0
  377. package/dist/schema.js.map +1 -0
  378. package/dist/search.d.ts +216 -0
  379. package/dist/search.d.ts.map +1 -0
  380. package/dist/search.js +785 -0
  381. package/dist/search.js.map +1 -0
  382. package/dist/settings.d.ts +191 -0
  383. package/dist/settings.d.ts.map +1 -0
  384. package/dist/settings.js +478 -0
  385. package/dist/settings.js.map +1 -0
  386. package/dist/sql.d.ts +7 -0
  387. package/dist/sql.d.ts.map +1 -0
  388. package/dist/sql.js +30 -0
  389. package/dist/sql.js.map +1 -0
  390. package/dist/storage-client.d.ts +69 -0
  391. package/dist/storage-client.d.ts.map +1 -0
  392. package/dist/storage-client.js +469 -0
  393. package/dist/storage-client.js.map +1 -0
  394. package/dist/storage.d.ts +21 -0
  395. package/dist/storage.d.ts.map +1 -0
  396. package/dist/storage.js +82 -0
  397. package/dist/storage.js.map +1 -0
  398. package/dist/subject-domains.d.ts +15 -0
  399. package/dist/subject-domains.d.ts.map +1 -0
  400. package/dist/subject-domains.js +38 -0
  401. package/dist/subject-domains.js.map +1 -0
  402. package/dist/support.d.ts +132 -0
  403. package/dist/support.d.ts.map +1 -0
  404. package/dist/support.js +483 -0
  405. package/dist/support.js.map +1 -0
  406. package/dist/system-tables.d.ts +12 -0
  407. package/dist/system-tables.d.ts.map +1 -0
  408. package/dist/system-tables.js +225 -0
  409. package/dist/system-tables.js.map +1 -0
  410. package/dist/test.d.ts +57 -0
  411. package/dist/test.d.ts.map +1 -0
  412. package/dist/test.js +454 -0
  413. package/dist/test.js.map +1 -0
  414. package/dist/vite.d.ts +82 -0
  415. package/dist/vite.d.ts.map +1 -0
  416. package/dist/vite.js +82 -0
  417. package/dist/vite.js.map +1 -0
  418. package/dist/webpush-crypto.d.ts +39 -0
  419. package/dist/webpush-crypto.d.ts.map +1 -0
  420. package/dist/webpush-crypto.js +213 -0
  421. package/dist/webpush-crypto.js.map +1 -0
  422. package/dist/webpush-private.d.ts +11 -0
  423. package/dist/webpush-private.d.ts.map +1 -0
  424. package/dist/webpush-private.js +11 -0
  425. package/dist/webpush-private.js.map +1 -0
  426. package/dist/webpush.d.ts +86 -0
  427. package/dist/webpush.d.ts.map +1 -0
  428. package/dist/webpush.js +375 -0
  429. package/dist/webpush.js.map +1 -0
  430. package/dist/worker.d.ts +185 -0
  431. package/dist/worker.d.ts.map +1 -0
  432. package/dist/worker.js +13021 -0
  433. package/dist/worker.js.map +1 -0
  434. package/package.json +161 -8
  435. package/README.md +0 -3
package/dist/ai.js ADDED
@@ -0,0 +1,1858 @@
1
+ import { dataStub } from "./db.js";
2
+ import { sha256Hex, stableJson } from "./internal.js";
3
+ import { jsonSchemaFor, parseWithSchema, restoreStrictModelValue, strictModelSchema } from "./json-schema.js";
4
+ import { id, integer, longText, raybaseSystemTable, text } from "./schema.js";
5
+ import { nowIso, randomId } from "./sql.js";
6
+ import { createInferenceTape, tapeChatStream, withoutInferenceTapeEnv } from "./inference-tape.js";
7
+ export const raybaseRecommendedModelsManifestUrl = "https://raybase.dev/models/recommended.json";
8
+ export const defaultAiModel = "";
9
+ export const defaultEmbeddingModel = "@cf/baai/bge-base-en-v1.5";
10
+ export const defaultAiLimits = {
11
+ // perUserDailyRequests, perUserDailyOutputTokens, and perAppDailyRequests are
12
+ // deliberately absent: unset means unlimited. Public (unauthenticated) traffic
13
+ // keeps a default cap because that surface is an abuse question, not a spend one.
14
+ perPublicDailyRequests: 200,
15
+ perPublicDailyOutputTokens: 60_000,
16
+ maxToolCallsPerTurn: 6,
17
+ maxLoopStepsPerTurn: 8,
18
+ maxConversationMessages: 40
19
+ };
20
+ /**
21
+ * Deadline for a single model call. A provider request that hangs otherwise
22
+ * parks the whole agent turn: the turn's abort signal is only consulted
23
+ * between loop steps, so neither a member's cancel nor the runtime can cut a
24
+ * request already in flight. Measured healthy agent calls finish far inside
25
+ * this (drafts up to ~21s, delivery gates and chapter closes ~9s), so the
26
+ * bound never touches honest traffic.
27
+ */
28
+ export const defaultModelCallTimeoutMs = 120_000;
29
+ export const defaultAiDefaults = {
30
+ model: defaultAiModel,
31
+ embeddingModel: defaultEmbeddingModel,
32
+ maxInputChars: 20_000,
33
+ maxOutputTokens: 1_200,
34
+ modelCallTimeoutMs: defaultModelCallTimeoutMs,
35
+ modelParams: {}
36
+ };
37
+ export class RaybaseAiModelNotConfiguredError extends Error {
38
+ constructor(source = "AI model") {
39
+ super(`${source} is not configured. Set the defaultAiModel setting in Raybase admin or provide appConfig.ai.defaults.model.`);
40
+ this.name = "RaybaseAiModelNotConfiguredError";
41
+ }
42
+ }
43
+ export function chatMessageText(message) {
44
+ if (typeof message.content === "string")
45
+ return message.content;
46
+ return message.content
47
+ .filter((part) => part.type === "text")
48
+ .map((part) => part.text)
49
+ .join("");
50
+ }
51
+ /**
52
+ * Tool definitions in the form a strict provider accepts.
53
+ *
54
+ * Every object closed with every property required, optionality spelled as a
55
+ * null union, open records carried as JSON in a string. `restoreStrictToolCalls`
56
+ * is the other half and is not optional: the arguments that come back carry the
57
+ * padding, and an action's own validator refuses it.
58
+ *
59
+ * Core applies both around every `ai.chat` and `ai.chatStream` call, so declared
60
+ * Zod and JSON-Schema inputs work on a strict lane without an app doing
61
+ * anything. A custom inference provider that builds its own request — an app
62
+ * registering `appConfig.ai.provider` — uses this pair rather than rebuilding it.
63
+ */
64
+ export function strictChatTools(tools) {
65
+ if (!tools?.length)
66
+ return tools;
67
+ return tools.map((tool) => {
68
+ const parameters = tool.parameters === undefined
69
+ ? { type: "object", properties: {} }
70
+ : tool.parameters;
71
+ if (!parameters || typeof parameters !== "object" || Array.isArray(parameters))
72
+ return tool;
73
+ return { ...tool, parameters: strictModelSchema(parameters) };
74
+ });
75
+ }
76
+ /**
77
+ * Tool-call arguments with the strict padding undone, restored against the tool
78
+ * schemas *as they were declared* — before `strictChatTools` saw them.
79
+ */
80
+ export function restoreStrictToolCalls(calls, tools) {
81
+ if (!calls?.length)
82
+ return calls ?? [];
83
+ if (!tools?.length)
84
+ return calls;
85
+ const schemas = new Map(tools.map((tool) => [tool.name, tool.parameters]));
86
+ return calls.map((call) => {
87
+ const schema = schemas.get(call.name);
88
+ if (!schema || typeof schema !== "object" || Array.isArray(schema))
89
+ return call;
90
+ return { ...call, arguments: restoreStrictModelValue(call.arguments, schema) };
91
+ });
92
+ }
93
+ /**
94
+ * The first complete JSON object in a reply.
95
+ *
96
+ * Models put prose before the JSON and, less often, after it. Scanning from the
97
+ * first `{` to the last `}` swallows both into one unparseable span; this walks
98
+ * brace depth with string and escape handling, mirroring the boundary a
99
+ * streaming JSON decoder would find, and returns the first object that parses.
100
+ */
101
+ export function firstJsonObject(text) {
102
+ for (let start = text.indexOf("{"); start >= 0; start = text.indexOf("{", start + 1)) {
103
+ let depth = 0;
104
+ let quoted = false;
105
+ let escaped = false;
106
+ for (let index = start; index < text.length; index += 1) {
107
+ const character = text[index];
108
+ if (quoted) {
109
+ if (escaped)
110
+ escaped = false;
111
+ else if (character === "\\")
112
+ escaped = true;
113
+ else if (character === '"')
114
+ quoted = false;
115
+ continue;
116
+ }
117
+ if (character === '"')
118
+ quoted = true;
119
+ else if (character === "{")
120
+ depth += 1;
121
+ else if (character === "}" && --depth === 0) {
122
+ try {
123
+ const value = JSON.parse(text.slice(start, index + 1));
124
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
125
+ }
126
+ catch {
127
+ break;
128
+ }
129
+ }
130
+ }
131
+ }
132
+ return null;
133
+ }
134
+ /**
135
+ * The one input-size measure. Every budget check — the agent turn pre-flight,
136
+ * the in-loop re-measure, and the AI layer's own guard — must count the same
137
+ * request the same way, or a turn passes one check and fails the next on the
138
+ * same bytes. Callers that measure ahead of a call pass exactly what they will
139
+ * send.
140
+ *
141
+ * Image and attachment content parts still count as zero: chatMessageText
142
+ * keeps text parts only, and a provider bills their bytes as tokens on a
143
+ * different scale than characters.
144
+ */
145
+ export function chatRequestInputChars(input) {
146
+ return jsonCharLength({
147
+ messages: input.messages.map((message) => ({ ...message, content: chatMessageText(message) })),
148
+ tools: input.tools,
149
+ metadata: input.metadata,
150
+ responseFormat: input.responseFormat
151
+ });
152
+ }
153
+ export class RaybaseInferenceProviderError extends Error {
154
+ code;
155
+ health;
156
+ retryAt;
157
+ actionHref;
158
+ constructor(input) {
159
+ super(input.message ?? "The selected AI provider is unavailable.");
160
+ this.name = "RaybaseInferenceProviderError";
161
+ this.code = input.code;
162
+ this.health = input.health;
163
+ this.retryAt = input.retryAt;
164
+ this.actionHref = input.actionHref;
165
+ }
166
+ }
167
+ export function safeInferenceProviderError(error) {
168
+ if (error instanceof RaybaseInferenceProviderError) {
169
+ const code = /^[a-z0-9][a-z0-9_.:-]{0,79}$/.test(error.code) ? error.code : "provider_error";
170
+ const retryAt = error.retryAt && Number.isFinite(new Date(error.retryAt).getTime())
171
+ ? new Date(error.retryAt).toISOString()
172
+ : undefined;
173
+ const actionHref = error.actionHref?.startsWith("/") && error.actionHref.length <= 256
174
+ ? error.actionHref
175
+ : undefined;
176
+ return {
177
+ code,
178
+ ...(error.health ? { health: error.health } : {}),
179
+ ...(retryAt ? { retryAt } : {}),
180
+ ...(actionHref ? { actionHref } : {}),
181
+ message: "The selected AI provider is unavailable."
182
+ };
183
+ }
184
+ return {
185
+ code: "provider_error",
186
+ message: "The selected AI provider failed."
187
+ };
188
+ }
189
+ export function safeInferenceProviderErrorMessage(error) {
190
+ return JSON.stringify(safeInferenceProviderError(error));
191
+ }
192
+ /**
193
+ * A structured call that produced nothing usable: no JSON in the reply, or JSON
194
+ * the caller's own schema refused. It carries the raw text and the validation
195
+ * issues, because a caller who cannot see what the model actually said has no
196
+ * way to tell a prompt problem from a schema problem.
197
+ */
198
+ export class RaybaseAIObjectError extends Error {
199
+ raw;
200
+ issues;
201
+ constructor(message, input) {
202
+ super(message, input.cause === undefined ? undefined : { cause: input.cause });
203
+ this.name = "RaybaseAIObjectError";
204
+ this.raw = input.raw;
205
+ this.issues = input.issues ?? [];
206
+ }
207
+ }
208
+ /**
209
+ * `ai.object` for any client that can `chat`: the request-scoped `RaybaseAI`,
210
+ * the commit-scoped variant, and anything wrapping either of them with its own
211
+ * accounting. Kept as a free function so a wrapper delegates in one line rather
212
+ * than reimplementing the parse-and-validate half.
213
+ */
214
+ export function raybaseObjectCall(chat) {
215
+ return async (input, options) => {
216
+ const messages = objectRequestMessages(input);
217
+ const declared = jsonSchemaFor(input.schema);
218
+ const responseFormat = {
219
+ type: "json_schema",
220
+ name: objectSchemaName(input.schemaName),
221
+ schema: strictModelSchema(declared),
222
+ strict: true,
223
+ ...(input.schemaDescription ? { description: input.schemaDescription } : {})
224
+ };
225
+ const attempts = input.retry === false ? 1 : 2;
226
+ let raw = "";
227
+ let issues = [];
228
+ let failure;
229
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
230
+ const result = await chat({
231
+ model: input.model ?? "",
232
+ messages: attempt === 0 ? messages : [...messages, ...objectRetryMessages(raw, issues)],
233
+ responseFormat,
234
+ ...(input.maxOutputTokens !== undefined ? { maxOutputTokens: input.maxOutputTokens } : {}),
235
+ ...(input.modelParams ? { modelParams: input.modelParams } : {}),
236
+ ...(input.providerParams ? { providerParams: input.providerParams } : {}),
237
+ ...(input.metadata ? { metadata: input.metadata } : {})
238
+ }, options);
239
+ raw = result.text;
240
+ const parsed = firstJsonObject(raw);
241
+ if (!parsed) {
242
+ issues = [{ message: "The reply contained no complete JSON object." }];
243
+ failure = undefined;
244
+ continue;
245
+ }
246
+ try {
247
+ // The wire form travels back too: nulls where the caller wrote an
248
+ // optional, JSON in a string where it wrote a record.
249
+ return parseWithSchema(input.schema, restoreStrictModelValue(parsed, declared), "ai.object");
250
+ }
251
+ catch (error) {
252
+ failure = error;
253
+ issues = objectValidationIssues(error);
254
+ }
255
+ }
256
+ throw new RaybaseAIObjectError(issues.length === 1 && typeof issues[0]?.message === "string"
257
+ ? `Structured AI reply was rejected: ${issues[0].message}`
258
+ : "Structured AI reply did not validate against its schema", { raw, issues, cause: failure });
259
+ };
260
+ }
261
+ function objectRequestMessages(input) {
262
+ const messages = input.messages?.length
263
+ ? input.messages
264
+ : input.prompt
265
+ ? [{ role: "user", content: input.prompt }]
266
+ : [];
267
+ if (!messages.length)
268
+ throw new Error("ai.object requires messages or a prompt");
269
+ return messages;
270
+ }
271
+ function objectSchemaName(name) {
272
+ const trimmed = name?.trim();
273
+ if (!trimmed)
274
+ return "response";
275
+ if (!/^[A-Za-z0-9_-]{1,64}$/.test(trimmed))
276
+ throw new Error(`ai.object schemaName ${trimmed} must be 1-64 characters of letters, digits, underscores or dashes`);
277
+ return trimmed;
278
+ }
279
+ function objectRetryMessages(raw, issues) {
280
+ return [
281
+ { role: "assistant", content: raw },
282
+ {
283
+ role: "user",
284
+ content: `That reply did not validate against the required schema: ${objectIssueText(issues)}. Reply again with only the JSON object, corrected.`
285
+ }
286
+ ];
287
+ }
288
+ function objectIssueText(issues) {
289
+ const described = issues.map((issue) => {
290
+ const record = issue;
291
+ const path = Array.isArray(record?.path) && record.path.length ? `${record.path.join(".")}: ` : "";
292
+ return `${path}${typeof record?.message === "string" ? record.message : String(issue)}`;
293
+ });
294
+ return described.join("; ").slice(0, 800) || "no details";
295
+ }
296
+ function objectValidationIssues(error) {
297
+ const issues = error?.issues;
298
+ if (Array.isArray(issues) && issues.length)
299
+ return issues;
300
+ return [{ message: error instanceof Error ? error.message : String(error) }];
301
+ }
302
+ export const raybaseAiSystemTables = [
303
+ raybaseSystemTable("_ai_usage_events", {
304
+ id: id(),
305
+ userId: text(),
306
+ principalKind: text(),
307
+ publicScopeHash: text(),
308
+ serviceName: text(),
309
+ agent: text(),
310
+ conversationId: text(),
311
+ model: text({ required: true }),
312
+ requestKind: text({ required: true }),
313
+ role: text(),
314
+ gatewayId: text(),
315
+ gatewayLogId: text(),
316
+ inputChars: integer({ required: true }),
317
+ floorChars: integer(),
318
+ tailChars: integer(),
319
+ outputChars: integer({ required: true }),
320
+ estimatedInputTokens: integer({ required: true }),
321
+ estimatedOutputTokens: integer({ required: true }),
322
+ estimatedNeurons: integer(),
323
+ modelParams: longText(),
324
+ metadata: longText(),
325
+ status: text({ required: true }),
326
+ error: longText(),
327
+ durationMs: integer({ required: true }),
328
+ createdAt: text({ required: true })
329
+ }, { indexes: [["userId", "createdAt"], ["serviceName", "createdAt"], ["agent", "createdAt"], ["conversationId"]] }),
330
+ raybaseSystemTable("_ai_budget_windows", {
331
+ id: id(),
332
+ scope: text({ required: true }),
333
+ scopeId: text({ required: true }),
334
+ windowStart: text({ required: true }),
335
+ windowEnd: text({ required: true }),
336
+ requestCount: integer({ required: true }),
337
+ estimatedOutputTokens: integer({ required: true }),
338
+ estimatedNeurons: integer(),
339
+ updatedAt: text({ required: true })
340
+ }, { indexes: [["scope", "scopeId", "windowStart"], ["windowEnd"]] }),
341
+ raybaseSystemTable("_ai_action_events", {
342
+ id: id(),
343
+ userId: text({ required: true }),
344
+ agent: text({ required: true }),
345
+ conversationId: text(),
346
+ actionName: text({ required: true }),
347
+ inputHash: text(),
348
+ status: text({ required: true }),
349
+ error: longText(),
350
+ createdAt: text({ required: true })
351
+ }, { indexes: [["userId", "createdAt"], ["agent", "createdAt"], ["conversationId"], ["actionName"]] }),
352
+ raybaseSystemTable("_ai_embedding_chunks", {
353
+ id: id(),
354
+ indexName: text({ required: true }),
355
+ backend: text({ required: true }),
356
+ physicalIndex: text(),
357
+ namespace: text(),
358
+ vectorId: text({ required: true }),
359
+ sourceType: text({ required: true }),
360
+ sourceTable: text(),
361
+ sourceId: text({ required: true }),
362
+ sourceVersion: text(),
363
+ chunkKey: text({ required: true }),
364
+ chunkOrdinal: integer({ required: true }),
365
+ embeddingModel: text({ required: true }),
366
+ dimensions: integer({ required: true }),
367
+ metric: text(),
368
+ textHash: text({ required: true }),
369
+ title: text(),
370
+ url: text(),
371
+ metadata: longText(),
372
+ vectorBase64: longText(),
373
+ status: text({ required: true }),
374
+ mutationId: text(),
375
+ lastError: longText(),
376
+ indexedAt: text(),
377
+ updatedAt: text({ required: true })
378
+ }, {
379
+ indexes: [
380
+ ["indexName", "backend", "sourceType", "sourceTable", "sourceId"],
381
+ ["backend", "physicalIndex", "namespace", "vectorId"],
382
+ ["status", "updatedAt"],
383
+ ["textHash"],
384
+ ["sourceType", "sourceTable", "sourceId", "chunkKey"]
385
+ ]
386
+ }),
387
+ raybaseSystemTable("_ai_retrieval_reindex_runs", {
388
+ id: id(),
389
+ indexName: text({ required: true }),
390
+ backend: text({ required: true }),
391
+ status: text({ required: true }),
392
+ actorId: text(),
393
+ actorKind: text(),
394
+ namespace: text(),
395
+ totalSources: integer({ required: true }),
396
+ totalChunks: integer({ required: true }),
397
+ upsertedChunks: integer({ required: true }),
398
+ deletedChunks: integer({ required: true }),
399
+ skippedChunks: integer({ required: true }),
400
+ errorCount: integer({ required: true }),
401
+ startedAt: text({ required: true }),
402
+ completedAt: text(),
403
+ summaryJson: longText()
404
+ }, { indexes: [["indexName", "startedAt"], ["backend", "status"], ["namespace", "startedAt"]] })
405
+ ];
406
+ export function aiEndpoint(config) {
407
+ const endpoint = config.ai?.endpoint || "/api/ai";
408
+ return endpoint.startsWith("/") ? endpoint.replace(/\/$/, "") || "/api/ai" : `/${endpoint.replace(/\/$/, "")}`;
409
+ }
410
+ export function normalizeAiLimits(config) {
411
+ return { ...defaultAiLimits, ...(config.ai?.limits ?? {}) };
412
+ }
413
+ export function normalizeAiDefaults(config) {
414
+ return {
415
+ ...defaultAiDefaults,
416
+ ...(config.ai?.defaults ?? {}),
417
+ modelParams: normalizeModelParams(config.ai?.defaults?.modelParams ?? {})
418
+ };
419
+ }
420
+ export async function fetchRecommendedAiModelsManifest(url = raybaseRecommendedModelsManifestUrl) {
421
+ const response = await fetch(url, {
422
+ headers: { accept: "application/json" }
423
+ });
424
+ if (!response.ok)
425
+ return null;
426
+ const value = await response.json();
427
+ if (!value || typeof value !== "object")
428
+ return null;
429
+ const manifest = value;
430
+ if (manifest.schemaVersion !== 1)
431
+ return null;
432
+ return manifest;
433
+ }
434
+ export function recommendedDefaultAiModel(manifest) {
435
+ const model = manifest?.defaults?.guide?.model ?? manifest?.defaults?.chat?.model;
436
+ return typeof model === "string" && model.trim() ? model.trim() : null;
437
+ }
438
+ export function requireConfiguredAiModel(model, source = "AI model") {
439
+ const resolved = typeof model === "string" ? model.trim() : "";
440
+ if (resolved)
441
+ return resolved;
442
+ throw new RaybaseAiModelNotConfiguredError(source);
443
+ }
444
+ export function aiGatewayId(config) {
445
+ return config.ai?.gateway?.id ?? null;
446
+ }
447
+ export function buildAiGatewayOptions(input) {
448
+ const gatewayId = effectiveAiGatewayId(input.config, input.env);
449
+ if (!gatewayId)
450
+ return {};
451
+ const gateway = {
452
+ id: gatewayId,
453
+ cache: input.env?.RAYBASE_ENV === "local" && input.env.RAYBASE_AI_GATEWAY_CACHE !== undefined
454
+ ? parseAiGatewayCache(input.env.RAYBASE_AI_GATEWAY_CACHE)
455
+ : input.config.ai?.gateway?.cache,
456
+ metadata: {
457
+ raybaseApp: input.config.appName,
458
+ raybaseAgent: input.agent ?? null,
459
+ raybasePrincipalKind: input.principalKind ?? (input.publicId ? "public" : "user"),
460
+ raybaseUser: input.userId ?? null,
461
+ raybasePublicPrincipal: input.publicId ?? null,
462
+ raybaseService: input.serviceName ?? null,
463
+ raybaseRequest: input.requestId ?? null,
464
+ raybaseSurface: input.surface ?? null,
465
+ raybaseEnv: input.env?.RAYBASE_ENV === "local" ? "local" : "production",
466
+ ...(input.metadata ?? {})
467
+ }
468
+ };
469
+ return { gateway };
470
+ }
471
+ function effectiveAiGatewayProviderAuthorization(config, env) {
472
+ const secretName = config.ai?.gateway?.authorizationSecretName?.trim();
473
+ if (!secretName || !env)
474
+ return null;
475
+ const value = env[secretName];
476
+ return typeof value === "string" && value.trim() ? `Bearer ${value.trim()}` : null;
477
+ }
478
+ function effectiveAiGatewayRequestAuthorization(env) {
479
+ const value = env?.RAYBASE_AI_GATEWAY_AUTH?.trim();
480
+ if (!value)
481
+ return null;
482
+ return /^Bearer\s+/i.test(value) ? value : `Bearer ${value}`;
483
+ }
484
+ export function aiGatewayAuthorizationConfig(config) {
485
+ return {
486
+ authorizationSecretName: config.ai?.gateway?.authorizationSecretName?.trim() || undefined,
487
+ storeKeyName: config.ai?.gateway?.storeKeyName?.trim() || undefined
488
+ };
489
+ }
490
+ function parseAiGatewayCache(value) {
491
+ const normalized = value.trim().toLowerCase();
492
+ if (!normalized)
493
+ return undefined;
494
+ if (["true", "1", "yes", "on"].includes(normalized))
495
+ return true;
496
+ if (["false", "0", "no", "off"].includes(normalized))
497
+ return false;
498
+ return undefined;
499
+ }
500
+ function effectiveAiGatewayId(config, env) {
501
+ if (env?.RAYBASE_ENV === "local" && env.RAYBASE_AI_GATEWAY_ID !== undefined) {
502
+ return env.RAYBASE_AI_GATEWAY_ID.trim() || null;
503
+ }
504
+ return aiGatewayId(config);
505
+ }
506
+ function normalizeAiPrincipal(options) {
507
+ if (options.principal)
508
+ return options.principal;
509
+ if (options.user)
510
+ return { kind: "user", user: options.user };
511
+ throw new Error("createRaybaseAI requires a signed-in user or explicit principal");
512
+ }
513
+ function usagePrincipalFields(principal) {
514
+ switch (principal.kind) {
515
+ case "user":
516
+ return { principalKind: "user", userId: principal.user.id, publicScopeHash: null, serviceName: null };
517
+ case "public":
518
+ return { principalKind: "public", userId: null, publicScopeHash: principal.id, serviceName: null };
519
+ case "service":
520
+ return { principalKind: "service", userId: null, publicScopeHash: null, serviceName: principal.service };
521
+ }
522
+ }
523
+ function usagePromptSplitFields(split) {
524
+ if (!split)
525
+ return { floorChars: null, tailChars: null };
526
+ return {
527
+ floorChars: Math.max(0, Math.round(split.floorChars)),
528
+ tailChars: Math.max(0, Math.round(split.tailChars))
529
+ };
530
+ }
531
+ export function createRaybaseAI(options) {
532
+ const workersProvider = options.env.AI ? createCloudflareWorkersAIInferenceProvider() : undefined;
533
+ const cloudflareProvider = options.env.AI ? createCloudflareInferenceProvider() : undefined;
534
+ const principal = normalizeAiPrincipal(options);
535
+ const defaults = normalizeAiDefaults(options.config);
536
+ const limits = normalizeAiLimits(options.config);
537
+ const requestId = options.requestId ?? options.request?.headers.get("cf-ray") ?? randomId("ai_req");
538
+ const baseSignal = options.signal ?? options.request?.signal;
539
+ const inferenceTape = createInferenceTape(options.env);
540
+ const providerEnv = withoutInferenceTapeEnv(options.env);
541
+ let providerPromise;
542
+ const resolveProvider = () => {
543
+ providerPromise ??= Promise.resolve(options.providerFactory
544
+ ? options.providerFactory({
545
+ env: providerEnv,
546
+ request: options.request,
547
+ config: options.config,
548
+ control: options.control,
549
+ principal,
550
+ organizationId: options.organizationId,
551
+ requestId,
552
+ surface: options.surface ?? "http",
553
+ signal: baseSignal,
554
+ moduleOptions: options.config.modules
555
+ })
556
+ : options.provider ?? cloudflareProvider).then((provider) => localAiProvider(options.env, options.config, provider));
557
+ return providerPromise;
558
+ };
559
+ const resolveEmbeddingProvider = async () => {
560
+ const selected = await resolveProvider();
561
+ if (selected?.embed)
562
+ return selected;
563
+ return localAiProvider(options.env, options.config, workersProvider);
564
+ };
565
+ const claimBudget = options.claimBudget ??
566
+ ((input) => {
567
+ return dataStub(options.env).claimAiBudget(input);
568
+ });
569
+ async function beforeCall(input) {
570
+ const maxInputChars = input.maxInputChars ?? defaults.maxInputChars;
571
+ if (input.inputChars > maxInputChars) {
572
+ throw new Error(`AI input is ${input.inputChars} characters, exceeding maxInputChars ${maxInputChars}`);
573
+ }
574
+ if (input.budgetMode === "system-exempt")
575
+ return;
576
+ const overhead = input.budgetMode === "system-overhead" || principal.kind === "service";
577
+ const claim = await claimBudget({
578
+ now: nowIso(),
579
+ principalKind: overhead ? undefined : principal.kind,
580
+ userId: overhead ? null : principal.kind === "user" ? principal.user.id : null,
581
+ publicScopeId: overhead ? null : principal.kind === "public" ? principal.id : null,
582
+ appScopeId: "app",
583
+ requestCount: 1,
584
+ estimatedOutputTokens: Math.max(0, input.estimatedOutputTokens),
585
+ estimatedNeurons: null,
586
+ perUserDailyRequests: overhead ? null : limits.perUserDailyRequests ?? null,
587
+ perUserDailyOutputTokens: overhead ? null : limits.perUserDailyOutputTokens ?? null,
588
+ perAppDailyRequests: limits.perAppDailyRequests ?? null,
589
+ perPublicDailyRequests: overhead ? null : limits.perPublicDailyRequests,
590
+ perPublicDailyOutputTokens: overhead ? null : limits.perPublicDailyOutputTokens
591
+ });
592
+ if (!claim.ok) {
593
+ throw new Error(`AI budget exhausted for ${claim.scope}: ${claim.reason}`);
594
+ }
595
+ }
596
+ async function record(event) {
597
+ await recordAiUsageEvent(options.control, {
598
+ ...event,
599
+ metadata: options.usageMetadata ?? null
600
+ });
601
+ }
602
+ function providerContext(input) {
603
+ const gateway = buildAiGatewayOptions({
604
+ config: options.config,
605
+ env: providerEnv,
606
+ agent: input.agent ?? options.agent,
607
+ userId: principal.kind === "user" ? principal.user.id : undefined,
608
+ principalKind: principal.kind,
609
+ publicId: principal.kind === "public" ? principal.id : undefined,
610
+ serviceName: principal.kind === "service" ? principal.service : undefined,
611
+ requestId,
612
+ surface: options.surface ?? "http",
613
+ metadata: input.metadata
614
+ });
615
+ return {
616
+ env: providerEnv,
617
+ request: options.request,
618
+ config: options.config,
619
+ principal,
620
+ organizationId: options.organizationId,
621
+ surface: options.surface ?? "http",
622
+ agent: input.agent ?? options.agent,
623
+ conversationId: input.conversationId ?? options.conversationId,
624
+ requestId,
625
+ gatewayOptions: { ...gateway, ...(input.gateway ?? {}) },
626
+ metadata: input.metadata,
627
+ signal: input.signal ?? baseSignal
628
+ };
629
+ }
630
+ function tapeCorrelation(input) {
631
+ return {
632
+ ...(input.agent ?? options.agent ? { agent: input.agent ?? options.agent } : {}),
633
+ ...(input.conversationId ?? options.conversationId
634
+ ? { conversationId: input.conversationId ?? options.conversationId }
635
+ : {}),
636
+ requestId,
637
+ ...(options.turnKey ? { turnKey: options.turnKey } : {}),
638
+ surface: options.surface ?? "http",
639
+ ...(options.organizationId ? { organizationId: options.organizationId } : {}),
640
+ ...(effectiveAiGatewayId(options.config, options.env)
641
+ ? { gatewayId: effectiveAiGatewayId(options.config, options.env) }
642
+ : {})
643
+ };
644
+ }
645
+ const client = {
646
+ async chat(input, chatOptions = {}) {
647
+ const provider = await resolveProvider();
648
+ if (!provider)
649
+ throw new Error("Raybase AI is enabled in appConfig but no AI provider is available");
650
+ const model = requireConfiguredAiModel(input.model || options.defaultModel || defaults.model);
651
+ const inputChars = chatRequestInputChars(input);
652
+ const promptSplit = usagePromptSplitFields(chatOptions.promptSplit);
653
+ const maxOutputTokens = input.maxOutputTokens ?? chatOptions.maxOutputTokens ?? defaults.maxOutputTokens;
654
+ const requestKind = chatOptions.requestKind ?? "chat";
655
+ const role = aiUsageRole(chatOptions.metadata ?? input.metadata);
656
+ const modelParams = effectiveModelParams(defaults.modelParams, {
657
+ modelParams: { ...(chatOptions.modelParams ?? {}), ...(input.modelParams ?? {}) }
658
+ });
659
+ await beforeCall({
660
+ agent: chatOptions.agent,
661
+ requestKind,
662
+ budgetMode: chatOptions.budgetMode,
663
+ inputChars,
664
+ estimatedOutputTokens: maxOutputTokens,
665
+ maxInputChars: chatOptions.maxInputChars
666
+ });
667
+ const request = {
668
+ ...input,
669
+ model,
670
+ maxOutputTokens,
671
+ modelParams,
672
+ ...(input.tools ? { tools: strictChatTools(input.tools) } : {})
673
+ };
674
+ const tapeCall = await inferenceTape.begin({
675
+ operation: "chat",
676
+ provider: provider.id ?? "unknown",
677
+ requestKind,
678
+ roleOrLane: role ?? requestKind,
679
+ request,
680
+ ...(chatOptions.promptBandDiagnostics
681
+ ? { diagnostics: { promptBands: chatOptions.promptBandDiagnostics } }
682
+ : {}),
683
+ correlation: tapeCorrelation({ agent: chatOptions.agent, conversationId: chatOptions.conversationId })
684
+ });
685
+ const started = Date.now();
686
+ try {
687
+ const result = await provider.chat(request, providerContext({
688
+ agent: chatOptions.agent,
689
+ conversationId: chatOptions.conversationId,
690
+ gateway: chatOptions.gateway,
691
+ metadata: chatOptions.metadata ?? input.metadata,
692
+ signal: chatOptions.signal
693
+ }));
694
+ await tapeCall.completed(result);
695
+ await record({
696
+ ...usagePrincipalFields(principal),
697
+ agent: chatOptions.agent ?? options.agent ?? null,
698
+ conversationId: chatOptions.conversationId ?? options.conversationId ?? null,
699
+ model,
700
+ requestKind,
701
+ role,
702
+ gatewayId: effectiveAiGatewayId(options.config, options.env),
703
+ gatewayLogId: result.provider?.requestId ?? null,
704
+ inputChars,
705
+ ...promptSplit,
706
+ outputChars: result.text.length,
707
+ estimatedInputTokens: result.usage?.inputTokens ?? estimateTokensFromChars(inputChars),
708
+ estimatedOutputTokens: result.usage?.outputTokens ?? estimateTokensFromChars(result.text.length),
709
+ estimatedNeurons: null,
710
+ modelParams,
711
+ status: "ok",
712
+ durationMs: Date.now() - started
713
+ });
714
+ return {
715
+ ...result,
716
+ // The padding the strict form required, undone against the tools as
717
+ // the caller declared them, before anything parses these arguments.
718
+ toolCalls: restoreStrictToolCalls(result.toolCalls, input.tools),
719
+ provider: { id: result.provider?.id ?? provider.id, requestId: result.provider?.requestId, raw: result.provider?.raw }
720
+ };
721
+ }
722
+ catch (error) {
723
+ await tapeCall.error(error);
724
+ await record({
725
+ ...usagePrincipalFields(principal),
726
+ agent: chatOptions.agent ?? options.agent ?? null,
727
+ conversationId: chatOptions.conversationId ?? options.conversationId ?? null,
728
+ model,
729
+ requestKind,
730
+ role,
731
+ gatewayId: effectiveAiGatewayId(options.config, options.env),
732
+ inputChars,
733
+ ...promptSplit,
734
+ outputChars: 0,
735
+ estimatedInputTokens: estimateTokensFromChars(inputChars),
736
+ estimatedOutputTokens: 0,
737
+ modelParams,
738
+ status: "error",
739
+ error: safeInferenceProviderErrorMessage(error),
740
+ durationMs: Date.now() - started
741
+ });
742
+ throw error;
743
+ }
744
+ },
745
+ async chatStream(input, streamOptions = {}) {
746
+ const provider = await resolveProvider();
747
+ if (!provider)
748
+ throw new Error("Raybase AI is enabled in appConfig but no AI provider is available");
749
+ const model = requireConfiguredAiModel(input.model || options.defaultModel || defaults.model);
750
+ const inputChars = chatRequestInputChars(input);
751
+ const promptSplit = usagePromptSplitFields(streamOptions.promptSplit);
752
+ const maxOutputTokens = input.maxOutputTokens ?? streamOptions.maxOutputTokens ?? defaults.maxOutputTokens;
753
+ const requestKind = streamOptions.requestKind ?? "chat";
754
+ const role = aiUsageRole(streamOptions.metadata ?? input.metadata);
755
+ const modelParams = effectiveModelParams(defaults.modelParams, {
756
+ modelParams: { ...(streamOptions.modelParams ?? {}), ...(input.modelParams ?? {}) }
757
+ });
758
+ await beforeCall({
759
+ agent: streamOptions.agent,
760
+ requestKind,
761
+ budgetMode: streamOptions.budgetMode,
762
+ inputChars,
763
+ estimatedOutputTokens: maxOutputTokens,
764
+ maxInputChars: streamOptions.maxInputChars
765
+ });
766
+ const request = {
767
+ ...input,
768
+ model,
769
+ maxOutputTokens,
770
+ modelParams,
771
+ ...(input.tools ? { tools: strictChatTools(input.tools) } : {})
772
+ };
773
+ const tapeCall = await inferenceTape.begin({
774
+ operation: "chatStream",
775
+ provider: provider.id ?? "unknown",
776
+ requestKind,
777
+ roleOrLane: role ?? requestKind,
778
+ request,
779
+ ...(streamOptions.promptBandDiagnostics
780
+ ? { diagnostics: { promptBands: streamOptions.promptBandDiagnostics } }
781
+ : {}),
782
+ correlation: tapeCorrelation({ agent: streamOptions.agent, conversationId: streamOptions.conversationId })
783
+ });
784
+ const started = Date.now();
785
+ try {
786
+ const source = provider.chatStream
787
+ ? await provider.chatStream(request, providerContext({
788
+ agent: streamOptions.agent,
789
+ conversationId: streamOptions.conversationId,
790
+ gateway: streamOptions.gateway,
791
+ metadata: streamOptions.metadata ?? input.metadata,
792
+ signal: streamOptions.signal
793
+ }))
794
+ : chatResultToStream(await provider.chat(request, providerContext({
795
+ agent: streamOptions.agent,
796
+ conversationId: streamOptions.conversationId,
797
+ gateway: streamOptions.gateway,
798
+ metadata: streamOptions.metadata ?? input.metadata,
799
+ signal: streamOptions.signal
800
+ })));
801
+ return recordChatStreamUsage(restoreStrictToolCallStream(tapeChatStream(source, tapeCall), input.tools), {
802
+ record,
803
+ principal,
804
+ agent: streamOptions.agent ?? options.agent ?? null,
805
+ conversationId: streamOptions.conversationId ?? options.conversationId ?? null,
806
+ model,
807
+ requestKind,
808
+ role,
809
+ gatewayId: effectiveAiGatewayId(options.config, options.env),
810
+ inputChars,
811
+ promptSplit,
812
+ modelParams,
813
+ started,
814
+ maxOutputTokens
815
+ });
816
+ }
817
+ catch (error) {
818
+ await tapeCall.error(error);
819
+ await record({
820
+ ...usagePrincipalFields(principal),
821
+ agent: streamOptions.agent ?? options.agent ?? null,
822
+ conversationId: streamOptions.conversationId ?? options.conversationId ?? null,
823
+ model,
824
+ requestKind,
825
+ role,
826
+ gatewayId: effectiveAiGatewayId(options.config, options.env),
827
+ inputChars,
828
+ ...promptSplit,
829
+ outputChars: 0,
830
+ estimatedInputTokens: estimateTokensFromChars(inputChars),
831
+ estimatedOutputTokens: 0,
832
+ modelParams,
833
+ status: "error",
834
+ error: safeInferenceProviderErrorMessage(error),
835
+ durationMs: Date.now() - started
836
+ });
837
+ throw error;
838
+ }
839
+ },
840
+ async embed(input, embedOptions = {}) {
841
+ const embeddingProvider = await resolveEmbeddingProvider();
842
+ if (!embeddingProvider?.embed)
843
+ throw new Error("Raybase AI embedding provider is unavailable");
844
+ const model = requireConfiguredAiModel(embedOptions.model ?? defaults.embeddingModel, "AI embedding model");
845
+ const inputChars = Array.isArray(input) ? input.join("\n").length : input.length;
846
+ const role = aiUsageRole(embedOptions.metadata);
847
+ const maxInputChars = embedOptions.maxInputChars ?? defaults.maxInputChars;
848
+ if (inputChars > maxInputChars)
849
+ throw new Error(`AI embedding input exceeds maxInputChars ${maxInputChars}`);
850
+ await beforeCall({
851
+ agent: embedOptions.agent,
852
+ requestKind: "embedding",
853
+ budgetMode: embedOptions.budgetMode,
854
+ inputChars,
855
+ estimatedOutputTokens: 0,
856
+ maxInputChars
857
+ });
858
+ const request = { model, input, metadata: embedOptions.metadata };
859
+ const tapeCall = await inferenceTape.begin({
860
+ operation: "embed",
861
+ provider: embeddingProvider.id ?? "unknown",
862
+ requestKind: "embedding",
863
+ roleOrLane: role ?? "embedding",
864
+ request,
865
+ correlation: tapeCorrelation({ agent: embedOptions.agent, conversationId: embedOptions.conversationId })
866
+ });
867
+ const started = Date.now();
868
+ try {
869
+ const result = await embeddingProvider.embed(request, providerContext({
870
+ agent: embedOptions.agent,
871
+ conversationId: embedOptions.conversationId,
872
+ gateway: embedOptions.gateway,
873
+ metadata: embedOptions.metadata,
874
+ signal: embedOptions.signal
875
+ }));
876
+ await tapeCall.completed(result);
877
+ await recordAiEmbeddingUsage({
878
+ record,
879
+ principal,
880
+ agent: embedOptions.agent ?? options.agent ?? null,
881
+ conversationId: embedOptions.conversationId ?? options.conversationId ?? null,
882
+ model,
883
+ gatewayId: effectiveAiGatewayId(options.config, options.env),
884
+ raw: result.provider?.raw,
885
+ inputChars,
886
+ role,
887
+ started
888
+ });
889
+ return result.embeddings;
890
+ }
891
+ catch (error) {
892
+ await tapeCall.error(error);
893
+ await record({
894
+ ...usagePrincipalFields(principal),
895
+ agent: embedOptions.agent ?? options.agent ?? null,
896
+ conversationId: embedOptions.conversationId ?? options.conversationId ?? null,
897
+ model,
898
+ requestKind: "embedding",
899
+ role,
900
+ gatewayId: effectiveAiGatewayId(options.config, options.env),
901
+ inputChars,
902
+ outputChars: 0,
903
+ estimatedInputTokens: estimateTokensFromChars(inputChars),
904
+ estimatedOutputTokens: 0,
905
+ status: "error",
906
+ error: safeInferenceProviderErrorMessage(error),
907
+ durationMs: Date.now() - started
908
+ });
909
+ throw error;
910
+ }
911
+ },
912
+ object: (input, objectOptions) => raybaseObjectCall((request, callOptions) => client.chat(request, callOptions))(input, objectOptions)
913
+ };
914
+ return client;
915
+ }
916
+ /** Tool calls in a stream, restored the same way `chat` restores its own. */
917
+ async function* restoreStrictToolCallStream(source, tools) {
918
+ if (!tools?.length) {
919
+ yield* source;
920
+ return;
921
+ }
922
+ for await (const event of source) {
923
+ if (event.type === "tool-call") {
924
+ yield { ...event, toolCall: restoreStrictToolCalls([event.toolCall], tools)[0] };
925
+ continue;
926
+ }
927
+ if (event.type === "done" && event.result?.toolCalls?.length) {
928
+ yield { ...event, result: { ...event.result, toolCalls: restoreStrictToolCalls(event.result.toolCalls, tools) } };
929
+ continue;
930
+ }
931
+ yield event;
932
+ }
933
+ }
934
+ export const disabledRaybaseAI = {
935
+ async chat() {
936
+ throw new Error("Raybase AI is not available in this context");
937
+ },
938
+ async chatStream() {
939
+ throw new Error("Raybase AI is not available in this context");
940
+ },
941
+ async object() {
942
+ throw new Error("Raybase AI is not available in this context");
943
+ },
944
+ async embed() {
945
+ throw new Error("Raybase AI is not available in this context");
946
+ }
947
+ };
948
+ async function recordAiEmbeddingUsage(input) {
949
+ await input.record({
950
+ ...usagePrincipalFields(input.principal),
951
+ agent: input.agent,
952
+ conversationId: input.conversationId,
953
+ model: input.model,
954
+ requestKind: "embedding",
955
+ role: input.role,
956
+ gatewayId: input.gatewayId,
957
+ gatewayLogId: gatewayLogId(input.raw),
958
+ inputChars: input.inputChars,
959
+ outputChars: 0,
960
+ estimatedInputTokens: estimateTokensFromChars(input.inputChars),
961
+ estimatedOutputTokens: 0,
962
+ estimatedNeurons: null,
963
+ status: "ok",
964
+ durationMs: Date.now() - input.started
965
+ });
966
+ }
967
+ function recordChatStreamUsage(source, input) {
968
+ return (async function* streamWithUsage() {
969
+ let outputText = "";
970
+ let doneResult;
971
+ try {
972
+ for await (const event of source) {
973
+ if (event.type === "text-delta")
974
+ outputText += event.text;
975
+ if (event.type === "done")
976
+ doneResult = event.result;
977
+ yield event;
978
+ }
979
+ const recordedText = typeof doneResult?.text === "string" ? doneResult.text : outputText;
980
+ await input.record({
981
+ ...usagePrincipalFields(input.principal),
982
+ agent: input.agent,
983
+ conversationId: input.conversationId,
984
+ model: input.model,
985
+ requestKind: input.requestKind,
986
+ role: input.role,
987
+ gatewayId: input.gatewayId,
988
+ gatewayLogId: doneResult?.provider?.requestId ?? null,
989
+ inputChars: input.inputChars,
990
+ ...input.promptSplit,
991
+ outputChars: recordedText.length,
992
+ estimatedInputTokens: doneResult?.usage?.inputTokens ?? estimateTokensFromChars(input.inputChars),
993
+ estimatedOutputTokens: doneResult?.usage?.outputTokens ?? estimateTokensFromChars(recordedText.length || input.maxOutputTokens),
994
+ estimatedNeurons: null,
995
+ modelParams: input.modelParams,
996
+ status: "ok",
997
+ durationMs: Date.now() - input.started
998
+ });
999
+ }
1000
+ catch (error) {
1001
+ await input.record({
1002
+ ...usagePrincipalFields(input.principal),
1003
+ agent: input.agent,
1004
+ conversationId: input.conversationId,
1005
+ model: input.model,
1006
+ requestKind: input.requestKind,
1007
+ role: input.role,
1008
+ gatewayId: input.gatewayId,
1009
+ inputChars: input.inputChars,
1010
+ ...input.promptSplit,
1011
+ outputChars: 0,
1012
+ estimatedInputTokens: estimateTokensFromChars(input.inputChars),
1013
+ estimatedOutputTokens: 0,
1014
+ modelParams: input.modelParams,
1015
+ status: "error",
1016
+ error: safeInferenceProviderErrorMessage(error),
1017
+ durationMs: Date.now() - input.started
1018
+ });
1019
+ throw error;
1020
+ }
1021
+ })();
1022
+ }
1023
+ async function* chatResultToStream(result) {
1024
+ if (result.text)
1025
+ yield { type: "text-delta", text: result.text };
1026
+ for (const toolCall of result.toolCalls)
1027
+ yield { type: "tool-call", toolCall };
1028
+ yield { type: "done", result };
1029
+ }
1030
+ export function createCloudflareInferenceProvider() {
1031
+ const workers = createCloudflareWorkersAIInferenceProvider();
1032
+ const gateway = createCloudflareAiGatewayInferenceProvider();
1033
+ return {
1034
+ id: "cloudflare",
1035
+ async chat(input, context) {
1036
+ return shouldUseProviderNativeAiGateway(input.model, context) ? gateway.chat(input, context) : workers.chat(input, context);
1037
+ },
1038
+ async chatStream(input, context) {
1039
+ return shouldUseProviderNativeAiGateway(input.model, context) ? gateway.chatStream(input, context) : workers.chatStream(input, context);
1040
+ },
1041
+ async embed(input, context) {
1042
+ return workers.embed(input, context);
1043
+ }
1044
+ };
1045
+ }
1046
+ export function createCloudflareAiGatewayInferenceProvider() {
1047
+ return {
1048
+ id: "cloudflare-ai-gateway",
1049
+ async chat(input, context) {
1050
+ const response = await fetch(await aiGatewayChatCompletionsUrl(input.model, context), {
1051
+ method: "POST",
1052
+ headers: aiGatewayProviderHeaders(input.model, context, false),
1053
+ body: stableJson(aiGatewayChatPayload(input)),
1054
+ signal: context.signal
1055
+ });
1056
+ const raw = await parseAiGatewayJsonResponse(response);
1057
+ const result = normalizeWorkersAiChatResult(raw, "cloudflare-ai-gateway");
1058
+ return {
1059
+ ...result,
1060
+ provider: {
1061
+ id: "cloudflare-ai-gateway",
1062
+ requestId: gatewayLogIdFromHeaders(response.headers) ?? result.provider?.requestId,
1063
+ raw
1064
+ }
1065
+ };
1066
+ },
1067
+ async chatStream(input, context) {
1068
+ const response = await fetch(await aiGatewayChatCompletionsUrl(input.model, context), {
1069
+ method: "POST",
1070
+ headers: aiGatewayProviderHeaders(input.model, context, true),
1071
+ body: stableJson(aiGatewayChatPayload(input, true)),
1072
+ signal: context.signal
1073
+ });
1074
+ if (!response.ok)
1075
+ await throwAiGatewayResponseError(response);
1076
+ return aiGatewayRawStreamEvents(response);
1077
+ }
1078
+ };
1079
+ }
1080
+ export function createCloudflareWorkersAIInferenceProvider() {
1081
+ return {
1082
+ id: "workers-ai",
1083
+ async chat(input, context) {
1084
+ const raw = await requireWorkersAI(context.env).run(input.model, workersAiChatPayload(input), context.gatewayOptions);
1085
+ return normalizeWorkersAiChatResult(raw, "workers-ai");
1086
+ },
1087
+ async chatStream(input, context) {
1088
+ const raw = await requireWorkersAI(context.env).run(input.model, workersAiChatPayload(input, true), context.gatewayOptions);
1089
+ return workersAiRawStreamEvents(raw);
1090
+ },
1091
+ async embed(input, context) {
1092
+ const raw = await requireWorkersAI(context.env).run(input.model, { text: input.input }, context.gatewayOptions);
1093
+ return {
1094
+ embeddings: parseEmbeddingResult(raw),
1095
+ provider: { id: "workers-ai", requestId: gatewayLogId(raw) ?? undefined, raw }
1096
+ };
1097
+ }
1098
+ };
1099
+ }
1100
+ export const raybaseTranscriptionModel = "@cf/openai/whisper-large-v3-turbo";
1101
+ export async function transcribeAudioWithWorkersAI(env, input) {
1102
+ const result = await requireWorkersAI(env).run(raybaseTranscriptionModel, {
1103
+ audio: input.audioBase64
1104
+ });
1105
+ const transcript = result && typeof result === "object" && typeof result.text === "string"
1106
+ ? result.text.trim()
1107
+ : "";
1108
+ return { transcript };
1109
+ }
1110
+ function requireWorkersAI(env) {
1111
+ if (!env.AI)
1112
+ throw new Error("Workers AI binding is unavailable");
1113
+ return env.AI;
1114
+ }
1115
+ function workersAiChatPayload(input, stream = false) {
1116
+ const payload = {
1117
+ messages: input.messages.map(workersAiChatMessage),
1118
+ ...(input.maxOutputTokens !== undefined ? { max_tokens: input.maxOutputTokens } : {}),
1119
+ ...(input.modelParams ?? {}),
1120
+ ...chatProviderParams(input.providerParams)
1121
+ };
1122
+ if (input.tools?.length)
1123
+ payload.tools = input.tools.map(workersAiTool);
1124
+ if (input.responseFormat)
1125
+ payload.response_format = chatResponseFormatPayload(input.responseFormat);
1126
+ if (stream)
1127
+ payload.stream = true;
1128
+ return payload;
1129
+ }
1130
+ function chatProviderParams(params) {
1131
+ if (!params?.verbosity)
1132
+ return {};
1133
+ return { verbosity: params.verbosity };
1134
+ }
1135
+ function chatResponseFormatPayload(format) {
1136
+ if (format.type === "json_object")
1137
+ return { type: "json_object" };
1138
+ return {
1139
+ type: "json_schema",
1140
+ json_schema: {
1141
+ name: format.name,
1142
+ schema: format.schema,
1143
+ ...(format.description ? { description: format.description } : {}),
1144
+ ...(format.strict !== undefined ? { strict: format.strict } : {})
1145
+ }
1146
+ };
1147
+ }
1148
+ function workersAiChatMessage(message) {
1149
+ if (message.role === "tool")
1150
+ return { role: "tool", tool_call_id: message.toolCallId, content: message.content };
1151
+ const content = message.role === "user" && Array.isArray(message.content)
1152
+ ? message.content.map(workersAiChatContentPart)
1153
+ : message.content;
1154
+ const output = { role: message.role, content };
1155
+ if (message.role === "assistant" && message.toolCalls?.length) {
1156
+ output.tool_calls = message.toolCalls.map((call) => ({
1157
+ id: call.id,
1158
+ type: "function",
1159
+ function: { name: call.name, arguments: stableJson(call.arguments ?? {}) }
1160
+ }));
1161
+ }
1162
+ return output;
1163
+ }
1164
+ function workersAiChatContentPart(part) {
1165
+ if (part.type === "text")
1166
+ return { type: "text", text: part.text };
1167
+ const url = part.type === "image"
1168
+ ? `data:${part.mediaType};base64,${part.data}`
1169
+ : part.url;
1170
+ return { type: "image_url", image_url: { url } };
1171
+ }
1172
+ function workersAiTool(tool) {
1173
+ return {
1174
+ type: "function",
1175
+ function: {
1176
+ name: tool.name,
1177
+ description: tool.description ?? "",
1178
+ parameters: tool.parameters ?? { type: "object", properties: {} }
1179
+ }
1180
+ };
1181
+ }
1182
+ function shouldUseProviderNativeAiGateway(model, context) {
1183
+ if (model.startsWith("@cf/"))
1184
+ return false;
1185
+ if (!effectiveAiGatewayId(context.config, context.env))
1186
+ return false;
1187
+ return Boolean(context.config.ai?.gateway?.authorizationSecretName?.trim() ||
1188
+ context.config.ai?.gateway?.storeKeyName?.trim() ||
1189
+ context.env.RAYBASE_AI_GATEWAY_AUTH?.trim());
1190
+ }
1191
+ async function aiGatewayChatCompletionsUrl(model, context) {
1192
+ const gatewayId = effectiveAiGatewayId(context.config, context.env);
1193
+ if (!gatewayId)
1194
+ throw new Error("AI Gateway id is required for provider-native AI Gateway requests");
1195
+ const provider = aiGatewayProviderSlug(model);
1196
+ const gateway = context.env.AI?.gateway?.(gatewayId);
1197
+ if (!gateway?.getUrl)
1198
+ throw new Error("AI Gateway provider-native requests require env.AI.gateway().getUrl()");
1199
+ const baseUrl = (await gateway.getUrl(provider)).replace(/\/+$/, "");
1200
+ return `${baseUrl}${aiGatewayChatCompletionsPath(provider)}`;
1201
+ }
1202
+ /**
1203
+ * The OpenAI-compatible chat path under a provider's AI Gateway base. The
1204
+ * gateway appends what follows the provider slug to the provider's own API
1205
+ * root, so the path depends on where each provider mounts its compatible
1206
+ * endpoint: OpenAI-shaped APIs serve `/chat/completions` at their `/v1`
1207
+ * root, while Anthropic's compatibility layer lives at `/v1/chat/completions`
1208
+ * under `api.anthropic.com`.
1209
+ */
1210
+ export function aiGatewayChatCompletionsPath(provider) {
1211
+ return provider === "anthropic" ? "/v1/chat/completions" : "/chat/completions";
1212
+ }
1213
+ function aiGatewayProviderSlug(model) {
1214
+ const slash = model.indexOf("/");
1215
+ const provider = slash === -1 ? "" : model.slice(0, slash);
1216
+ if (!provider || provider.startsWith("@"))
1217
+ throw new Error(`AI Gateway provider-native model must be provider/model, received ${model}`);
1218
+ return provider;
1219
+ }
1220
+ function aiGatewayProviderModel(model) {
1221
+ const slash = model.indexOf("/");
1222
+ return slash === -1 ? model : model.slice(slash + 1);
1223
+ }
1224
+ function aiGatewayProviderHeaders(model, context, stream) {
1225
+ const headers = new Headers({ "Content-Type": "application/json" });
1226
+ if (stream)
1227
+ headers.set("Accept", "text/event-stream");
1228
+ const gatewayAuthorization = effectiveAiGatewayRequestAuthorization(context.env);
1229
+ if (gatewayAuthorization)
1230
+ headers.set("cf-aig-authorization", gatewayAuthorization);
1231
+ const providerAuthorization = effectiveAiGatewayProviderAuthorization(context.config, context.env);
1232
+ if (providerAuthorization) {
1233
+ headers.set("Authorization", providerAuthorization);
1234
+ // Anthropic reads its key from x-api-key; the gateway only recognises a
1235
+ // request-supplied Anthropic credential there, and the compatibility
1236
+ // endpoint accepts either header.
1237
+ if (aiGatewayProviderSlug(model) === "anthropic")
1238
+ headers.set("x-api-key", providerAuthorization.replace(/^Bearer\s+/i, ""));
1239
+ }
1240
+ const storeKeyName = context.config.ai?.gateway?.storeKeyName?.trim();
1241
+ if (storeKeyName && storeKeyName !== "default")
1242
+ headers.set("cf-aig-byok-alias", storeKeyName);
1243
+ headers.set("cf-aig-metadata", stableJson(aiGatewayMetadata(context)));
1244
+ headers.set("x-raybase-model-provider", aiGatewayProviderSlug(model));
1245
+ return headers;
1246
+ }
1247
+ function aiGatewayMetadata(context) {
1248
+ const gateway = asRecord(asRecord(context.gatewayOptions).gateway);
1249
+ return {
1250
+ ...asRecord(gateway.metadata),
1251
+ ...(context.metadata ?? {})
1252
+ };
1253
+ }
1254
+ function aiGatewayChatPayload(input, stream = false) {
1255
+ const providerModel = aiGatewayProviderModel(input.model);
1256
+ return {
1257
+ ...workersAiChatPayload(input, stream),
1258
+ model: providerModel
1259
+ };
1260
+ }
1261
+ async function parseAiGatewayJsonResponse(response) {
1262
+ const text = await response.text();
1263
+ let parsed = text;
1264
+ if (text.trim()) {
1265
+ try {
1266
+ parsed = JSON.parse(text);
1267
+ }
1268
+ catch {
1269
+ parsed = text;
1270
+ }
1271
+ }
1272
+ if (!response.ok) {
1273
+ const message = typeof parsed === "string" ? parsed : stableJson(parsed);
1274
+ throw new Error(`AI Gateway request failed with ${response.status}: ${message}`);
1275
+ }
1276
+ return parsed;
1277
+ }
1278
+ async function throwAiGatewayResponseError(response) {
1279
+ const body = await response.text();
1280
+ throw new Error(`AI Gateway request failed with ${response.status}: ${body}`);
1281
+ }
1282
+ /**
1283
+ * Tool calls in an OpenAI-shaped chat stream arrive as fragments: the first
1284
+ * delta for an index carries the id and name with empty arguments, later
1285
+ * deltas append argument text, and the finish chunk closes them. Fragments
1286
+ * are gathered here per index and released as one call each at the finish;
1287
+ * a delta that already carries parsed (non-string) arguments is complete and
1288
+ * released at once, which is how Workers AI streams them.
1289
+ */
1290
+ export class AiStreamToolCallAssembler {
1291
+ pending = new Map();
1292
+ /** Returns the calls completed by this chunk; fragments stay pending. */
1293
+ collect(raw) {
1294
+ const record = asRecord(raw);
1295
+ const choices = Array.isArray(record.choices) ? record.choices : [];
1296
+ const first = asRecord(choices[0]);
1297
+ const delta = asRecord(first.delta);
1298
+ const fragments = Array.isArray(delta.tool_calls) ? delta.tool_calls : Array.isArray(delta.toolCalls) ? delta.toolCalls : null;
1299
+ const finished = typeof first.finish_reason === "string" || typeof first.finishReason === "string";
1300
+ if (!fragments) {
1301
+ const complete = extractProviderToolCalls(raw);
1302
+ return finished ? [...complete, ...this.flush()] : complete;
1303
+ }
1304
+ const complete = [];
1305
+ fragments.forEach((entry, position) => {
1306
+ const call = asRecord(entry);
1307
+ const fn = asRecord(call.function);
1308
+ const args = call.arguments ?? fn.arguments ?? call.args ?? call.input;
1309
+ if (args !== undefined && typeof args !== "string") {
1310
+ complete.push(...extractProviderToolCalls({ tool_calls: [entry] }));
1311
+ return;
1312
+ }
1313
+ const index = typeof call.index === "number" ? call.index : position;
1314
+ const current = this.pending.get(index) ?? { id: "", name: "", arguments: "" };
1315
+ if (typeof call.id === "string" && call.id)
1316
+ current.id = call.id;
1317
+ const name = String(call.name ?? fn.name ?? "");
1318
+ if (name)
1319
+ current.name = name;
1320
+ if (typeof args === "string")
1321
+ current.arguments += args;
1322
+ this.pending.set(index, current);
1323
+ });
1324
+ return finished ? [...complete, ...this.flush()] : complete;
1325
+ }
1326
+ /** Releases every pending call, for the finish chunk and the end of the stream. */
1327
+ flush() {
1328
+ const calls = [...this.pending.entries()]
1329
+ .sort(([left], [right]) => left - right)
1330
+ .map(([index, call]) => {
1331
+ if (!call.name)
1332
+ throw new Error(`Malformed streamed tool call at index ${index}: missing name`);
1333
+ return {
1334
+ id: call.id || `tool_call_${index + 1}_${randomId("call")}`,
1335
+ name: call.name,
1336
+ arguments: parseProviderToolArguments(call.arguments.trim() || "{}")
1337
+ };
1338
+ });
1339
+ this.pending.clear();
1340
+ return calls;
1341
+ }
1342
+ }
1343
+ async function* aiGatewayRawStreamEvents(response) {
1344
+ const stream = coerceReadableStream(response);
1345
+ const reader = stream.getReader();
1346
+ const decoder = new TextDecoder();
1347
+ const requestId = gatewayLogIdFromHeaders(response.headers) ?? undefined;
1348
+ const assembler = new AiStreamToolCallAssembler();
1349
+ let buffered = "";
1350
+ let outputText = "";
1351
+ let sawDone = false;
1352
+ const done = () => ({ type: "done", result: { text: outputText, provider: { id: "cloudflare-ai-gateway", requestId } } });
1353
+ try {
1354
+ while (true) {
1355
+ const { value, done: finished } = await reader.read();
1356
+ if (finished)
1357
+ break;
1358
+ buffered += decoder.decode(value, { stream: true });
1359
+ const splitAt = buffered.lastIndexOf("\n\n");
1360
+ if (splitAt === -1)
1361
+ continue;
1362
+ const ready = buffered.slice(0, splitAt + 2);
1363
+ buffered = buffered.slice(splitAt + 2);
1364
+ for (const event of parseWorkersAiSseText(ready)) {
1365
+ if (event.text) {
1366
+ outputText += event.text;
1367
+ yield { type: "text-delta", text: event.text };
1368
+ }
1369
+ if (event.done) {
1370
+ for (const toolCall of assembler.flush())
1371
+ yield { type: "tool-call", toolCall };
1372
+ sawDone = true;
1373
+ yield done();
1374
+ continue;
1375
+ }
1376
+ for (const toolCall of assembler.collect(event.raw))
1377
+ yield { type: "tool-call", toolCall };
1378
+ }
1379
+ }
1380
+ buffered += decoder.decode();
1381
+ if (buffered.trim()) {
1382
+ for (const event of parseWorkersAiSseText(buffered)) {
1383
+ if (event.text) {
1384
+ outputText += event.text;
1385
+ yield { type: "text-delta", text: event.text };
1386
+ }
1387
+ if (event.done) {
1388
+ for (const toolCall of assembler.flush())
1389
+ yield { type: "tool-call", toolCall };
1390
+ sawDone = true;
1391
+ yield done();
1392
+ continue;
1393
+ }
1394
+ for (const toolCall of assembler.collect(event.raw))
1395
+ yield { type: "tool-call", toolCall };
1396
+ }
1397
+ }
1398
+ if (!sawDone) {
1399
+ for (const toolCall of assembler.flush())
1400
+ yield { type: "tool-call", toolCall };
1401
+ yield done();
1402
+ }
1403
+ }
1404
+ finally {
1405
+ reader.releaseLock();
1406
+ }
1407
+ }
1408
+ function normalizeWorkersAiChatResult(raw, providerId) {
1409
+ const text = modelResultText(raw);
1410
+ const toolCalls = extractProviderToolCalls(raw);
1411
+ return {
1412
+ text,
1413
+ toolCalls,
1414
+ finishReason: normalizeFinishReason(raw, toolCalls),
1415
+ usage: normalizeProviderUsage(raw),
1416
+ provider: { id: providerId, requestId: gatewayLogId(raw) ?? undefined, raw }
1417
+ };
1418
+ }
1419
+ async function* workersAiRawStreamEvents(raw) {
1420
+ if (!(raw instanceof ReadableStream) && !(raw instanceof Response) && typeof raw !== "string") {
1421
+ yield* chatResultToStream(normalizeWorkersAiChatResult(raw, "workers-ai"));
1422
+ return;
1423
+ }
1424
+ const stream = coerceReadableStream(raw);
1425
+ const reader = stream.getReader();
1426
+ const decoder = new TextDecoder();
1427
+ let buffered = "";
1428
+ let sawDone = false;
1429
+ try {
1430
+ while (true) {
1431
+ const { value, done } = await reader.read();
1432
+ if (done)
1433
+ break;
1434
+ buffered += decoder.decode(value, { stream: true });
1435
+ const splitAt = buffered.lastIndexOf("\n\n");
1436
+ if (splitAt === -1)
1437
+ continue;
1438
+ const ready = buffered.slice(0, splitAt + 2);
1439
+ buffered = buffered.slice(splitAt + 2);
1440
+ for (const event of parseWorkersAiSseText(ready)) {
1441
+ if (event.text)
1442
+ yield { type: "text-delta", text: event.text };
1443
+ for (const toolCall of extractProviderToolCalls(event.raw))
1444
+ yield { type: "tool-call", toolCall };
1445
+ if (event.done) {
1446
+ sawDone = true;
1447
+ yield { type: "done" };
1448
+ }
1449
+ }
1450
+ }
1451
+ buffered += decoder.decode();
1452
+ if (buffered.trim()) {
1453
+ const events = parseWorkersAiSseText(buffered);
1454
+ if (events.length) {
1455
+ for (const event of events) {
1456
+ if (event.text)
1457
+ yield { type: "text-delta", text: event.text };
1458
+ for (const toolCall of extractProviderToolCalls(event.raw))
1459
+ yield { type: "tool-call", toolCall };
1460
+ if (event.done) {
1461
+ sawDone = true;
1462
+ yield { type: "done" };
1463
+ }
1464
+ }
1465
+ }
1466
+ else {
1467
+ let parsed = buffered;
1468
+ try {
1469
+ parsed = JSON.parse(buffered);
1470
+ }
1471
+ catch {
1472
+ parsed = buffered;
1473
+ }
1474
+ const result = normalizeWorkersAiChatResult(parsed, "workers-ai");
1475
+ if (result.text)
1476
+ yield { type: "text-delta", text: result.text };
1477
+ for (const toolCall of result.toolCalls)
1478
+ yield { type: "tool-call", toolCall };
1479
+ sawDone = true;
1480
+ yield { type: "done", result };
1481
+ }
1482
+ }
1483
+ if (!sawDone)
1484
+ yield { type: "done" };
1485
+ }
1486
+ finally {
1487
+ reader.releaseLock();
1488
+ }
1489
+ }
1490
+ function extractProviderToolCalls(result) {
1491
+ const record = asRecord(result);
1492
+ const choices = Array.isArray(record.choices) ? record.choices : [];
1493
+ const firstMessage = asRecord(asRecord(choices[0]).message);
1494
+ const firstDelta = asRecord(asRecord(choices[0]).delta);
1495
+ const candidates = [record.tool_calls, record.toolCalls, firstMessage.tool_calls, firstMessage.toolCalls, firstDelta.tool_calls, firstDelta.toolCalls]
1496
+ .find(Array.isArray);
1497
+ return (candidates ?? []).map((raw, index) => {
1498
+ const call = asRecord(raw);
1499
+ const fn = asRecord(call.function);
1500
+ const name = String(call.name ?? fn.name ?? "");
1501
+ if (!name)
1502
+ throw new Error(`Malformed tool call at index ${index}: missing name`);
1503
+ return {
1504
+ id: String(call.id ?? `tool_call_${index + 1}_${randomId("call")}`),
1505
+ name,
1506
+ arguments: parseProviderToolArguments(call.arguments ?? fn.arguments ?? call.args ?? call.input ?? {})
1507
+ };
1508
+ });
1509
+ }
1510
+ function parseProviderToolArguments(value) {
1511
+ if (typeof value !== "string")
1512
+ return value ?? {};
1513
+ try {
1514
+ return JSON.parse(value);
1515
+ }
1516
+ catch {
1517
+ throw new Error("Malformed tool call arguments JSON");
1518
+ }
1519
+ }
1520
+ function normalizeFinishReason(raw, toolCalls) {
1521
+ const record = asRecord(raw);
1522
+ const choices = Array.isArray(record.choices) ? record.choices : [];
1523
+ const first = asRecord(choices[0]);
1524
+ const reason = String(record.finish_reason ?? record.finishReason ?? first.finish_reason ?? first.finishReason ?? "").toLowerCase();
1525
+ if (toolCalls.length || reason === "tool_calls" || reason === "tool-calls")
1526
+ return "tool-calls";
1527
+ if (reason === "stop")
1528
+ return "stop";
1529
+ if (reason === "length" || reason === "max_tokens")
1530
+ return "length";
1531
+ if (reason === "error")
1532
+ return "error";
1533
+ return "unknown";
1534
+ }
1535
+ function normalizeProviderUsage(raw) {
1536
+ const usage = asRecord(asRecord(raw).usage);
1537
+ const inputTokens = numericUsage(usage.prompt_tokens ?? usage.input_tokens ?? usage.inputTokens);
1538
+ const outputTokens = numericUsage(usage.completion_tokens ?? usage.output_tokens ?? usage.outputTokens);
1539
+ return inputTokens === undefined && outputTokens === undefined ? undefined : { inputTokens, outputTokens };
1540
+ }
1541
+ function numericUsage(value) {
1542
+ const numeric = Number(value);
1543
+ return Number.isFinite(numeric) && numeric >= 0 ? numeric : undefined;
1544
+ }
1545
+ function localAiProvider(env, config, liveProvider) {
1546
+ if (env.RAYBASE_ENV !== "local")
1547
+ return liveProvider;
1548
+ const mode = normalizeLocalAiMode(env.RAYBASE_AI_MODE);
1549
+ if (mode === "mock")
1550
+ return mockRaybaseAIProvider(config, env.RAYBASE_AI_MOCK_RESPONSE);
1551
+ if (mode === "disabled")
1552
+ return localDisabledRaybaseAIProvider;
1553
+ return liveProvider;
1554
+ }
1555
+ function normalizeLocalAiMode(value) {
1556
+ const mode = value?.trim().toLowerCase();
1557
+ if (mode === "live" || mode === "mock" || mode === "disabled")
1558
+ return mode;
1559
+ return null;
1560
+ }
1561
+ export function mockRaybaseAIProvider(config, responseOverride) {
1562
+ const defaults = normalizeAiDefaults(config);
1563
+ return {
1564
+ id: "raybase-local-mock",
1565
+ async chat(input) {
1566
+ const text = responseOverride?.trim() || "Raybase local mock AI response.";
1567
+ return {
1568
+ text,
1569
+ toolCalls: [],
1570
+ finishReason: "stop",
1571
+ provider: { id: "raybase-local-mock", raw: { input } }
1572
+ };
1573
+ },
1574
+ async chatStream(input) {
1575
+ const text = responseOverride?.trim() || "Raybase local mock AI response.";
1576
+ return chatResultToStream({
1577
+ text,
1578
+ toolCalls: [],
1579
+ finishReason: "stop",
1580
+ provider: { id: "raybase-local-mock", raw: { input } }
1581
+ });
1582
+ },
1583
+ async embed(input) {
1584
+ const dimensions = embeddingDimensionsForModelName(defaults.embeddingModel);
1585
+ const values = Array.isArray(input.input) ? input.input : [input.input];
1586
+ return {
1587
+ embeddings: values.map((value) => deterministicUnitVector(String(value), dimensions)),
1588
+ provider: { id: "raybase-local-mock" }
1589
+ };
1590
+ }
1591
+ };
1592
+ }
1593
+ const localDisabledRaybaseAIProvider = {
1594
+ id: "raybase-local-disabled",
1595
+ async chat() {
1596
+ throw new Error("Raybase AI is disabled for local development. Set RAYBASE_AI_MODE=mock or run `raybase dev --ai live` to use Workers AI.");
1597
+ },
1598
+ async chatStream() {
1599
+ throw new Error("Raybase AI is disabled for local development. Set RAYBASE_AI_MODE=mock or run `raybase dev --ai live` to use Workers AI.");
1600
+ },
1601
+ async embed() {
1602
+ throw new Error("Raybase AI is disabled for local development. Set RAYBASE_AI_MODE=mock or run `raybase dev --ai live` to use Workers AI.");
1603
+ }
1604
+ };
1605
+ function deterministicUnitVector(input, dimensions) {
1606
+ const vector = [];
1607
+ let state = deterministicHash(input || "raybase-local-mock");
1608
+ let sumSquares = 0;
1609
+ for (let index = 0; index < dimensions; index += 1) {
1610
+ state = (1664525 * state + 1013904223) >>> 0;
1611
+ const value = ((state / 0xffffffff) * 2) - 1;
1612
+ vector.push(value);
1613
+ sumSquares += value * value;
1614
+ }
1615
+ const norm = Math.sqrt(sumSquares) || 1;
1616
+ return vector.map((value) => value / norm);
1617
+ }
1618
+ function deterministicHash(value) {
1619
+ let hash = 2166136261;
1620
+ for (let index = 0; index < value.length; index += 1) {
1621
+ hash ^= value.charCodeAt(index);
1622
+ hash = Math.imul(hash, 16777619);
1623
+ }
1624
+ return hash >>> 0 || 1;
1625
+ }
1626
+ function embeddingDimensionsForModelName(model) {
1627
+ if (model === "@cf/baai/bge-small-en-v1.5")
1628
+ return 384;
1629
+ if (model === "@cf/baai/bge-large-en-v1.5")
1630
+ return 1024;
1631
+ return 768;
1632
+ }
1633
+ function effectiveModelParams(defaults, options) {
1634
+ return normalizeModelParams({
1635
+ ...defaults,
1636
+ ...(options.modelParams ?? {})
1637
+ });
1638
+ }
1639
+ function normalizeModelParams(params) {
1640
+ const output = {};
1641
+ const temperature = boundedModelParam(params.temperature, "temperature");
1642
+ const topP = boundedModelParam(params.top_p, "top_p");
1643
+ if (temperature !== undefined)
1644
+ output.temperature = temperature;
1645
+ if (topP !== undefined)
1646
+ output.top_p = topP;
1647
+ return output;
1648
+ }
1649
+ function boundedModelParam(value, name) {
1650
+ if (value === undefined || value === null)
1651
+ return undefined;
1652
+ const numeric = Number(value);
1653
+ if (!Number.isFinite(numeric) || numeric < 0 || numeric > 2) {
1654
+ throw new Error(`AI model parameter ${name} must be a number between 0 and 2`);
1655
+ }
1656
+ return numeric;
1657
+ }
1658
+ export async function recordAiUsageEvent(db, event) {
1659
+ await db.run(`INSERT INTO "_ai_usage_events"
1660
+ ("id", "userId", "principalKind", "publicScopeHash", "serviceName", "agent", "conversationId", "model", "requestKind", "role", "gatewayId", "gatewayLogId",
1661
+ "inputChars", "floorChars", "tailChars", "outputChars", "estimatedInputTokens", "estimatedOutputTokens", "estimatedNeurons", "modelParams", "metadata",
1662
+ "status", "error", "durationMs", "createdAt")
1663
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
1664
+ randomId("ai_usage"),
1665
+ event.userId ?? null,
1666
+ event.principalKind ?? "user",
1667
+ event.publicScopeHash ?? null,
1668
+ event.serviceName ?? null,
1669
+ event.agent ?? null,
1670
+ event.conversationId ?? null,
1671
+ event.model,
1672
+ event.requestKind,
1673
+ event.role ?? null,
1674
+ event.gatewayId ?? null,
1675
+ event.gatewayLogId ?? null,
1676
+ event.inputChars,
1677
+ event.floorChars ?? null,
1678
+ event.tailChars ?? null,
1679
+ event.outputChars,
1680
+ event.estimatedInputTokens,
1681
+ event.estimatedOutputTokens,
1682
+ event.estimatedNeurons ?? null,
1683
+ event.modelParams && Object.keys(event.modelParams).length ? stableJson(event.modelParams) : null,
1684
+ event.metadata && Object.keys(event.metadata).length ? stableJson(event.metadata) : null,
1685
+ event.status,
1686
+ event.error ?? null,
1687
+ event.durationMs,
1688
+ nowIso()
1689
+ ]);
1690
+ }
1691
+ export async function recordAiActionEvent(db, input) {
1692
+ await db.run(`INSERT INTO "_ai_action_events" ("id", "userId", "agent", "conversationId", "actionName", "inputHash", "status", "error", "createdAt")
1693
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
1694
+ randomId("ai_action"),
1695
+ input.userId,
1696
+ input.agent,
1697
+ input.conversationId ?? null,
1698
+ input.actionName,
1699
+ input.actionInput === undefined ? null : await sha256Hex(stableJson(input.actionInput)),
1700
+ input.status,
1701
+ input.error ?? null,
1702
+ nowIso()
1703
+ ]);
1704
+ }
1705
+ export function formatSseEvent(event, data) {
1706
+ return `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
1707
+ }
1708
+ export function parseWorkersAiSseText(text) {
1709
+ const events = [];
1710
+ let current = [];
1711
+ const flush = () => {
1712
+ if (!current.length)
1713
+ return;
1714
+ const data = current.join("\n").trim();
1715
+ current = [];
1716
+ if (!data)
1717
+ return;
1718
+ if (data === "[DONE]") {
1719
+ events.push({ raw: "[DONE]", done: true });
1720
+ return;
1721
+ }
1722
+ try {
1723
+ const parsed = JSON.parse(data);
1724
+ events.push({ raw: parsed, text: modelResultText(parsed) || undefined });
1725
+ }
1726
+ catch {
1727
+ events.push({ raw: data, text: data });
1728
+ }
1729
+ };
1730
+ for (const line of text.split(/\r?\n/)) {
1731
+ if (!line.trim()) {
1732
+ flush();
1733
+ continue;
1734
+ }
1735
+ if (line.startsWith("data:"))
1736
+ current.push(line.slice(5).trimStart());
1737
+ }
1738
+ flush();
1739
+ return events;
1740
+ }
1741
+ export function modelResultText(value) {
1742
+ if (typeof value === "string")
1743
+ return value;
1744
+ const record = asRecord(value);
1745
+ if (typeof record.response === "string")
1746
+ return record.response;
1747
+ if (typeof record.text === "string")
1748
+ return record.text;
1749
+ if (typeof record.content === "string")
1750
+ return record.content;
1751
+ const output = record.output;
1752
+ if (typeof output === "string")
1753
+ return output;
1754
+ const choices = Array.isArray(record.choices) ? record.choices : [];
1755
+ const first = asRecord(choices[0]);
1756
+ const message = asRecord(first.message);
1757
+ const delta = asRecord(first.delta);
1758
+ if (typeof message.content === "string")
1759
+ return message.content;
1760
+ if (typeof delta.content === "string")
1761
+ return delta.content;
1762
+ if (typeof first.text === "string")
1763
+ return first.text;
1764
+ return "";
1765
+ }
1766
+ export function jsonCharLength(value) {
1767
+ if (typeof value === "string")
1768
+ return value.length;
1769
+ return stableJson(value).length;
1770
+ }
1771
+ export function estimateTokensFromChars(chars) {
1772
+ return Math.max(0, Math.ceil(chars / 4));
1773
+ }
1774
+ export function encodeFloatVector(vector) {
1775
+ const floats = new Float32Array(vector);
1776
+ const bytes = new Uint8Array(floats.buffer);
1777
+ let binary = "";
1778
+ for (const byte of bytes)
1779
+ binary += String.fromCharCode(byte);
1780
+ if (typeof btoa === "function")
1781
+ return btoa(binary);
1782
+ throw new Error("Base64 encoding is unavailable in this runtime");
1783
+ }
1784
+ export function decodeFloatVector(base64) {
1785
+ if (typeof atob !== "function")
1786
+ throw new Error("Base64 decoding is unavailable in this runtime");
1787
+ const binary = atob(base64);
1788
+ const bytes = new Uint8Array(binary.length);
1789
+ for (let index = 0; index < binary.length; index += 1)
1790
+ bytes[index] = binary.charCodeAt(index);
1791
+ return Array.from(new Float32Array(bytes.buffer));
1792
+ }
1793
+ export function cosineSimilarity(left, right) {
1794
+ const length = Math.min(left.length, right.length);
1795
+ let dot = 0;
1796
+ let leftNorm = 0;
1797
+ let rightNorm = 0;
1798
+ for (let index = 0; index < length; index += 1) {
1799
+ const a = left[index] ?? 0;
1800
+ const b = right[index] ?? 0;
1801
+ dot += a * b;
1802
+ leftNorm += a * a;
1803
+ rightNorm += b * b;
1804
+ }
1805
+ if (!leftNorm || !rightNorm)
1806
+ return 0;
1807
+ return dot / (Math.sqrt(leftNorm) * Math.sqrt(rightNorm));
1808
+ }
1809
+ function parseEmbeddingResult(raw) {
1810
+ if (Array.isArray(raw) && Array.isArray(raw[0]))
1811
+ return raw;
1812
+ const record = asRecord(raw);
1813
+ const data = record.data;
1814
+ if (Array.isArray(data)) {
1815
+ if (Array.isArray(data[0]))
1816
+ return data;
1817
+ if (data.every((item) => asRecord(item).embedding))
1818
+ return data.map((item) => asRecord(item).embedding);
1819
+ }
1820
+ if (Array.isArray(record.embeddings))
1821
+ return record.embeddings;
1822
+ if (Array.isArray(record.embedding))
1823
+ return [record.embedding];
1824
+ throw new Error("Workers AI embedding response did not include vectors");
1825
+ }
1826
+ function coerceReadableStream(raw) {
1827
+ if (raw instanceof ReadableStream)
1828
+ return raw;
1829
+ if (raw instanceof Response && raw.body)
1830
+ return raw.body;
1831
+ const text = typeof raw === "string" ? raw : stableJson(raw);
1832
+ return new ReadableStream({
1833
+ start(controller) {
1834
+ controller.enqueue(new TextEncoder().encode(text));
1835
+ controller.close();
1836
+ }
1837
+ });
1838
+ }
1839
+ function gatewayLogId(raw) {
1840
+ const record = asRecord(raw);
1841
+ return typeof record.gatewayLogId === "string" ? record.gatewayLogId : typeof record.logId === "string" ? record.logId : null;
1842
+ }
1843
+ function gatewayLogIdFromHeaders(headers) {
1844
+ return headers.get("cf-aig-log-id") ?? headers.get("cf-ai-gateway-log-id") ?? headers.get("x-ai-gateway-log-id");
1845
+ }
1846
+ function asRecord(value) {
1847
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
1848
+ }
1849
+ function aiUsageRole(metadata) {
1850
+ const record = asRecord(metadata);
1851
+ for (const key of ["role", "raybaseComposingSurface"]) {
1852
+ const value = record[key];
1853
+ if (typeof value === "string" && value.trim())
1854
+ return value.trim();
1855
+ }
1856
+ return null;
1857
+ }
1858
+ //# sourceMappingURL=ai.js.map